Creating an OCIO view transform to match default Unreal 4 ACES viewport tonemapper

Hello,

First post here so please be gentle. We are using unreal engine as part our lighting department in our vfx pipeline. We plan to produce acescg exrs from Unreal which will then be brought into Nuke for compositing. Pretty much like a traditional vfx workflow.

The problem we are having is with the ACES filmic tonemapper. Looking at the docs for Unreal they say that there is support for exporting HDR data in exr on custom passes. There is an option for changing the capture gamut when storing the captured HDR data.
https://docs.unrealengine.com/en-US/Engine/Sequencer/Workflow/CustomRenderPass/index.html

I assumed that this would equate to the working/rendering colourspace as in an offline renderer like Arnold or Mantra but maybe this assumption is incorrect.

The way that aces has been integrated into Unreal seems different to other dccs. There seems to be no way to change the view transform for different display devices (rec709, p3, srgb etc). They also seem to expose the curves for aces tonemapping which doesn’t seem to align with the aces standardization. There is also no OCIO support.

When we rendered out an image sequence as exrs using the acescg capture gamut, the result didn’t look as expected. For example if I export an exr with these settings:

If I view the image without a view transform (raw) the results seem to match the viewport in unreal.

Unreal viewport

Nuke viewing raw

This implies that the image has been exported with the tonemapper applied and not the linear data, like I would expect an offline renderer would produce.
We have found a way to disable the tonemapper then only apply it to the exported exrs which seems to produce a correct result:

https://forums.unrealengine.com/development-discussion/rendering/1600749-another-way-to-disable-tonemapping

This means that we can render out the exrs in linear and continue our pipeline as a regular vfx pipeline.
Now we just want to make sure the viewing experience in Unreal and Nuke match.
Has anyone found a way of creating/modifing any current OCIO aces view transforms to match the UE4 viewport?
Any help would be much appreciated.

2 Likes

Hi Jeremy,

Welcome and thanks for your first post!

Steve T
ACESCentral Admin

1 Like

I’ve never used the Render Movie option in UE4, but if you’re looking to export out a pre-tonemapped image, have you tried the Scene Color option? iirc Final Image is exactly as it sounds, but then again there are multiple options with different names that are identical, so it’s hard to say exactly without digging through them again. Scene Color should be the scene-referred linear color though.

As far as I understand the code, it looked pretty standard to me except near the end when everything is multiplied where the ODT has a gain of 1.5 applied to it. Somewhere in the post-process shader, there is also a correction for the “electric” blue and a fake wide gamut which may cause some slight discontinuities depending on the colors used. The exposed options for the user can be found in the camera/Post-Process Volume under Color Grading > Misc.

Another issue you might run into is everything is included in the tonemapping pass, so if you wanted the linear color with in-engine grading, you’ll lose that with the tonemapper disabled.

1 Like

Hi Brian,

Thanks for the reply.

I rendered out the Scene Colour pass but that is the same as the final image pass.

After a bit of time looking at the shader files, like you say, the code looks pretty standard when compared to the ctl. I don’t suppose you know where the in the shader files the ODT gets a gain of 1.5 applied?

Thanks for the warning about disabling the post process and there is an ongoing discussion here as to whether that is a good idea. At the moment we are testing a lot of different types of workflows and one of those tests is to replicate a vfx workflow where most of the operations in the post process would be done by a compositor in Nuke.

Oh and thanks for the heads up about the electric blue fix and fake wide gamut.

1 Like

You will not find it because the RRT is fitted with that gain builtin, it is actually 1.45. I can see your reply to my question on UDN. I will get back to you next week there as I don’t have UE4 front of me but basically, you need to increase scene-referred linear light values with that gain in Nuke and disable the Gamut Expansion and Blue Light Artifact Fix in UE4. With all those 3 tweaks, you should have a quite good matching. It will not be exact though but fine for practical purposes.

Cheers,

Thomas

2 Likes

Hey Thomas. In the TonemapCommon shader, specifically the ACESOutputTransforms functions(RGBD65, 1000 nit, etc), there is this line:

float3 aces = mul( sRGB_2_AP0, SceneReferredLinearsRGBColor * 1.5 )

That looks like the scene color is pre-multiplied. Is that not the case here? So the RRT and scene color are both modified separately?

Hi Brian, the function effectively used by UE4 in Engine/Shaders/Private/PostProcessCombineLUTs.usf is FilmToneMap defined in Engine/Shaders/Private/TonemapCommon.ush. It uses a fit that includes a 1.45 gain, the function you mention is not used AFAIK and is more a reference.

Hope that helps!

Cheers,

Thomas

Hi Jeremy, did you find a workable solution for this? Many thanks, Anthony

Welcome @Anthony,

Sorry, I should have back-posted! If you have access to UDN, the related thread with my answer is here: https://udn.unrealengine.com/questions/543111/view.html

Otherwise, without repasting the whole conversation (careful, the YAML formatting might be busted):

- !<ColorSpace>
    name: ACES sRGB ODT
    family: View
    equalitygroup: ""
    bitdepth: 32f
    isdata: false
    allocation: uniform
    allocationvars: [0, 1]
    to_reference: !<GroupTransform>
    children:
        - !<FileTransform> {src: InvRRT.sRGB.Log2_48_nits_Shaper.spi3d, interpolation: tetrahedral}
        - !<FileTransform> {src: Log2_48_nits_Shaper_to_linear.spi1d, interpolation: linear}
        - !<ColorSpaceTransform> {src: Colourspace - ACES 2065-1, dst: Model - Reference}
    from_reference: !<GroupTransform>
    children:
        - !<ColorSpaceTransform> {src: Model - Reference, dst: Colourspace - ACES 2065-1}
        - !<FileTransform> {src: Log2_48_nits_Shaper_to_linear.spi1d, interpolation: linear, direction: inverse}
        - !<FileTransform> {src: Log2_48_nits_Shaper.RRT.sRGB.spi3d, interpolation: tetrahedral}

- !<ColorSpace>
    name: UE4
    family: View
    equalitygroup: ""
    bitdepth: 32f
    isdata: false
    allocation: uniform
    allocationvars: [0, 1]
    to_reference: !<GroupTransform>
    children:
        - !<ColorSpaceTransform> {src: ACES sRGB ODT, dst: Model - Reference}
        - !<CDLTransform> {slope: [1.45, 1.45, 1.45], direction: inverse}
    from_reference: !<GroupTransform>
    children:
        - !<CDLTransform> {slope: [1.45, 1.45, 1.45]}
        - !<ColorSpaceTransform> {src: Model - Reference, dst: ACES sRGB ODT}

The assumption is that the Gamut Expansion and Blue Light Artifact Fix LMTs are disabled in the PostProcessVolume.

Cheers,

Thomas

Good morning Thomas. Thank you very much for posting. Unfortunately there appears to be an issue with the Unreal website (There was an error contacting the remote service). Hopefully it will be up again soon. Thank you again for your help.

Anthony

Hello,

In case anyone’s interested, I have a test in Unreal 4.26 using ACES 1.2 config that kind of matches the UE default tonemapped image, I wrote about it here.

I’m fairly new to ACES, I’m afraid I did some stuff wrong, it’s not perfect, although looks like a pretty close one (The scene is lit with Photometric Lights and Camera values).

2 Likes

Oh and a screenshot for spectacle (I tried to fix the vibrant blues on the OCIO viewports as well)

1 Like

Hi Peter,

The Blue Light Artifact Fix is already in the ACES OCIO config, so you can get a new colourspace that includes it, to a degree, the problem is that it does not follow the ACES block diagram so can’t be fully reproduced without changing the config significantly. Then you are also missing the Gamut Expansion part that you would need to bake as a 3D LUT. I’m not really sure those two transforms are worth the trouble they cause.

Cheers,

Thomas

1 Like

Hello Thomas,
Just started reading all of this today and I think my head is going to explode !

I have a beginners question.
If I use UE 4.26.1 to render out to Nuke which will Render out to a base light, will I be all right if I follow UE’S documentation below ? (oops ,I can include links )
go to → unrealengine docs / OpenColorIO / index.html
I would appreciate of you could point me to some document that has UE as apart of the mix wrt ACES.

Thank you so much.
Behram

1 Like

Hi Thomas,

I turned off unreal’s bluecorrect (which was only at 60%? - weird!) and the fake wide gamut expansion from it’s default viewport based on your earlier suggestion in another thread. In the above example (top-right image) I applied the Bluecorrect as a simple color matrix in a post-process shader on the Finalcolor before OCIO happens in AP0 gamut space (AFAIK from the ACES documentation, the Bluecorrect needs to be applied in ACES AP0). Unfortunately if I natively just use the ACES OCIO, the vibrant blues are becoming violet, I guess I missed something.

The reason I wrote it in Unreal is because Unfortunately you cannot Apply LMT’s in Unreal ATM, i was lucky that the Bluelight fix is easy to replicate (I’m afraid that because I’m calculating it on the GPU in Ue, the result is too inaccurate - I should not bake it in the render!).

This is how the Postprocess shader looks like:


(pregain lin-srgb with 1.45 → then go to AP0 → bluecorrect → go to AP1 lin. That’s why I used ACEScg as IDT, if I’m not mistaken AP1 linear is essentialy ACEScg)

I hope I understood everything correctly, I made this shader based on your replies from ACEScentral and UDN.

I would be really interested in creating a custom IDT that basically works like an IDT+LMT in Unreal (where we cannot assign LMT-s), unofortunately i didn’t find any material on how to achieve that!

Cheers,
Peter

1 Like

Hi Peter,

Using a blendable before the tonemapper like you are doing is the way to go for a LMT. The problem you would have here though is that the tonemapper expects sRGB encoded colours by default, thus you cannot really output ACEScg here.

sRGB —> ACES2065-1 → LMT —> ACES2065-1 —> sRGB

Cheers,

Thomas