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.

1 Like

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.

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.

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

1 Like

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