ACES LUT for Unity


So I put my ACES in Unity dream on the side for a while but now I’m kind of on it again and, well they still haven’t included proper ACES support, or any OCIO implementation.

So i’m wondering if anybody has a LUT to use with Unity’s Color Grading system, or any resources on how I can make one that takes their standard non graded output and applies the ACES RRT look?

Any indication would be very much appreciated.

I’m no game dev by any means but I thought the ACES(like) tonemapper is already an option in Unity making the colorgrading operations in ACES?

The Post-Processing Stack plugin should have that indeed!

No, there is a watered down attempt at replicating the look through a basic tonemapper, but it is by no means similar.

Ah that’s a bummer. Sorry about that.
Regarding the LUT. Are you familiar with Resolve? It’s easy to create .cube LUTs there via the ACES Transform. You would need to know what the game is outputting to though. And I don’t think that method would work on linear data as the LUT would be limited to 0-1 range. If there’s a way to get Unity to output some form of known log space it should be doable? Do you know which lut types are supported in the engine? And can you stack multiple?

Ah, I cant use a LUT on linear output, hmm.

Well I have access to the Render pipeline at a shader level and can output both linear and gamma corrected srgb color space to feed the LUT, but log space, I’m not sure.

I could output a flat neutral tone map, and then use the LUT to fix some of the colors, but I’m getting the feeling that will only work for limited value ranges ranges.

As far as I know URP only accepts 2D LUTs, but there might be a way I can force a 3D LUT like .cube to work.

Have used Resolve a bit, but not enough I guess, thanks for the tip on building LUT’s there.

Ah only a texture you mean? You can load a dummy texture into Resolve, generate the transform and save out to the texture again. But that method is also not suitable for linear data. Really designed for display referred grading.

Just thinking outloud here, would it be possible to set the tonemapper to ACES but turn it off leaving you in the grading space? If you can do that but slap a LUT on top you’d kinda get it to work. But only if it seems to be actual ACEScc/ACEScct. Their description of the ACES tonemapper and stating that grading is in ACES is very vague and not technical :slight_smile:

ACES : Use this option to apply a close approximation of the reference ACES tonemapper, for a more cinematic look. It is more contrasted than Neutral, and has an effect on actual color hue & saturation. If you use this tonemapper, Unity does all the grading operations in the ACES color spaces, for optimal precision and results.

Another tool to consider is Nuke. You can begin using the ocio v1 config that ships with it to get an example of the luts needed, and then bake these into 3D cube luts. Since these need to have log shapers, you can make an inverse log2lin, followed by the 3d lut, then a lin2log, and baking that all to a .cube. That will allow you to have linear input

You could also use the command line utilities in ocio to convert the spi3d and spi2d luts in the v1 config to .cube files (including the sharper space).

Of course all of this is contingent on being able to read 3D luts in Unity

I got more interested in the challenge and found this documentation page.

A very odd method is described. Writing log to EXR for LUT creation. Unity seems to use Arri LogC v3 EI 1000. They tell you to go from there back to linear with their LUT. Not sure why they can’t just export linear immediately. With some resulting cube file you can put that back in the postprocessing as external tone mapper it seems. Unity then on top of the LUT applies a linear to sRGB gamma conversion.

So I did some testing in Resolve and it does seem to work in the sense that what I see in Resolve matches Unity. The wonky part is that I’m assuming that via this method the postprocessing grading stack might still be either linear sRGB converting to log up until the LUT is applied or entirely in Arri LogC EI 1000 with sRGB primaries.

I’m not sure if this suits your needs in regards to a ‘real’ ACES project but I think it’s as close as we can get for now. My tests were very rudimentary and on a single scene so do your own of course. I used 33 size cubes. Resolve can export 65 too but it might impact performance. The doc explains how to set size in the project.

This was my setup:

  1. Unity Log to Linear r1.cube (Arri LogC EI 1000 to linear)
  2. ColorSpaceTransform → sRGB/Linear to AP1/ACEScct
  3. Grading operations (if you want to)
  4. ACES Transform → ACEScct to sRGB (output transform/RRT)
  5. ColorSpaceTransform → sRGB gamma to Linear (to cancel the post lin to sRGB gamma from Unity because we already converted to display)
  6. Linear to sRGB r1.cube (from Unity to monitor result. Disable this on LUT export or put it as a monitor view LUT instead like they explain but I like to have things visually clear)

The artifacts you see in Resolve came from the EXR itself, don’t know why but ignore them.
If you don’t feel like jumping in to Resolve yet you can check the LUTs I created on testing.

Good luck!

Dude! Great find, and with awesome tests as well, we have been using URP so I’m not able to use the External LUT Tone mapping feature but I might be able to change that.

Again thank you so much, im gonna start doing tests with our lighting to se how it pans out.


Just a question, how did you change the size of the HDRP settings to match your .cube file?

Hmm, ok i got it working, but interestingly enough the LUT you made gave med the same result as unitys own “ACES” tonemapper, and not similar to what im getting in Vray

This one is from unity with your grading33_1.Frame as the extrenal LUT for the tonemapper. it got a more blue hue to it an still not matching the Vray tonemapper

How about modified UE3 Filmic? Have a look, it might get you somewhere:

Are you using Vray in Maya? The reason I’m asking is that Maya ships with an OCIO config with an Output Transform called “Unity neutral tone-map” which emulates the default viewing pipeline in Unity. So concievably you could use that to get your Vray renders to match what you see in Unity.

I guess the tonemapper isn’t that far of the ACES RRT+ODT then :wink: I checked myself on the not super descriptive scene I was using and indeed only a miniscule exposure difference possibly due to other variables. Might be the brief switch in math under the hood but actually the same image after.

What @Derek said above about Vray… but also
If Vray setup was ACES I think Unity’s working space is still hardcoded sRGB and not ACEScg. If you are using lights/hdri or surface colors with values outside sRGB in Vray you’ll get different results. We’re only using the ACES output transform in Unity not the rendering space.

The grading LUT was just an example to see if it would work including some artistic grading. It’s not meant to match something. Sorry I didn’t clarify that.

Yes, I see that the Unity neutral tone-mapper output transform translates from the working color space to sRGB primaries before applying the tone-mapping. So maybe you could add an ACEScg to sRGB/709 linear transform into the the LUT to do that?

Hey, thanks for all the info guys I figured it out with that mention of rendering in ACEScg colorspace.

So my workflow in Vray was to use .exr files with ACES primaries, and render in ACEScg colorspace, which then got tonemapped to sRGB with the OCIO Display Correction

And I made the error of thinking that unity would render in ACES and use the colors from the exr correctly but it does not.

However if I use sRGB primaries in my .exr and switch my workflow in Vray to render in sRGB and then only convert to ACES via the RRT view transform, I at least get a 99% similar result in Unity and Vray, which will have to do until Unity or our programmers implements native rendering in ACES colorspace.

Again, thank you all for your valuable input, it helped me think about the right points of error

Glad we were able to help! :slight_smile: