ACEScc to Linear and back to ACEScc

Howdy,

I am currently developing a color grading tool that I am trying to make compatible with ACES workflows. Our tool uses the basic flow to calculate the effect:

Camera Scene Space → Converted to Linear → Calculate and apply effect in Linear → Convert back to camera scene space & output.
We have it working great with log formats such as SLOG-3, LogC and DaVinci Intermediate so far.

I am trying to implement ACEScc into this workflow but am having issues with the equation. When we use the equations given in the documentation, we get a broken and incorrect image. We may be using the wrong equation but wanted to ask here for some assistance.

Would someone be able to confirm the correct ACEScc → Linear Gamma equation as well as the reverse? (Linear Gamma → ACEScc)?
In this case I’m using standard Linear gamma and not LinearAP1

Thank you!

Specification is here: ACEScc Specification - ACES Technical Documentation

CTL reference is here: aces-input-and-colorspaces/ACEScc at 465fd38c279fb45cfc5f6cec4b40ae51339e5c3e · ampas/aces-input-and-colorspaces · GitHub

Also see ACEScct, which for most users, has replaced ACEScc (ACEScct has a toe much like other manufacturers’ log curves)

Specification: ACEScct Specification - ACES Technical Documentation

CTL reference: aces-input-and-colorspaces/ACEScct at 465fd38c279fb45cfc5f6cec4b40ae51339e5c3e · ampas/aces-input-and-colorspaces · GitHub

1 Like

When you say “standard linear gamma” I’m guessing you mean linear Rec.709/sRGB, which is what historically people meant when they said simply “linear”. It is not really correct to call that “standard linear”, and there is no standard. Linear data (or indeed any encoding) always needs the primaries defined to be meaningful.

Since AP1 is larger than the Rec.709 gamut, some positive ACEScc values will map to negative linear Rec.709 values, and your algorithm needs to handle that appropriately. Although the same applies to camera log encodings, and you say you have it working with those.

ACEScc is a simple logarithmic curve, rather than a piecewise curve with linear and logarithmic sections, like camera log curves and ACEScct. The linear portion of camera log curves extends below linear zero, whereas a true logarithmic curve never reaches zero (ACEScc has a small ‘cheat’ at the bottom end so it can represent zero, but not negative values). This makes ACEScc behave slightly differently under grading operations than ACEScct or camera log encodings, so this could be affecting what you are seeing.

Thank you for this! I am sending this over to my dev.

I was referring to Linear Rec.709/sRGB. It’s obvious that I am not the developer haha— I am leading the project but am not doing development. We have stalled on the ACES implementation and our team is two-large. I am trying to gather information to help support the development of the project.

Right now, I’ve sent the developer this info. The plugin is accepting an ACEScct/AP1 signal from a CST color management setup upstream and then converting it back to Linear (and I believe leaves the color space untouched so it would be AP1 as well). Then converting back to ACEScct/AP1 to pass downstream.

@nick @sdyer
This is our current implementation of ACEScct to Linear and back. Any advice would be super helpful. We are stuck on this.

__device__ float ACESCCToLinear(float value) 
{
    const float ACESCC_THRESHOLD2 = 15.99929538702341f;
    const float ACESCC_THRESHOLD1 = 0.155251141552511f;

    if (value <= ACESCC_THRESHOLD1) 
    {
        return (value - 0.0729055341958355f) / 10.5402377416545f;
    }
    else if (value >= ACESCC_THRESHOLD2)
    {
        return 65504.0f;
    }
    else
    {
        return std::pow(2.f, value * 17.52f - 9.72f);
    }
}

__device__ float linearToACESCC(float linear) 
{
    if (linear <= 0.0078125f)
    {
        return 10.5402377416545f * linear + 0.0729055341958355f;
    }
    else 
    {
        return (std::log(linear) / std::log(2.0f) + 9.72f) / 17.52f;
    }
}

The functions you have there look like ACEScct, not ACEScc. But they are named ACESCCToLinear and linearToACESCC. Are you sure you are not using an external CST to ACEScc, and then applying the ACEScct linearisation to the result? That would work above the ACEScct break point, but be completely wrong below it.

My developer isn’t native english native speaking so the names aren’t correct but we’re applying the ACEScct math and not ACEScc. (Or so I’m told).

We are taking aces AP1/ACEScct signal and trying to linearize it and then after processing in linear, convert back from linear to AP1/ACEScct. Somewhere we’re getting a break as the conversion right now totally breaks image.

There does not appear to be anything wrong with the code you posted. I have run it, and the functions correctly convert ACEScct to ACEScg and ACEScg to ACEScct. Your issue must be elsewhere in your plugin code.

Interesting. So when you run the code— your image should not change at all as the conversion, round trip, shouldn’t introduce any visual changes. Is that correct?

You can send a linear ramp to see what you get at the end and figure it out from there

Yes. Your two functions round trip perfectly.

this is interesting because we currently have Slog-3, Log-C and DaVinci Intermediate gammas working correctly with the rest of the code. If there were errors in other areas of the plugin, they should also be problematic in the other gammas. Those 3 gammas are converted to linear and back with no issues.

Perhaps a place to start is to create an image with some noted values, 0 / 0.18 / 0.5 / 1.0 / 10.0 etc and convert them to ACEScct in a different application and pipe those into your system. then check only the linearization part and see if the numbers are correct. Could do the same for checking the lin to ACEScct part with linear input values.

Another option is convert to ACEScct, but then convert out to one of your other working log transfer functions and see if the numbers are correct for that space. Again same on maybe linearizing SLog3 based patches via SLog3 function and output to ACEScct.

You should be able to at least shrink the problem down to one of the processes unless both are somehow broken.

I don’t know, but I wonder if everything else is the same in your comparisons. When you are using ACEScct do you have Resolve in ACES mode? What mode was it in when using other log spaces? Is it possible that the way Resolve hands off image data to a plugin is different in ACES mode?