in unity/Assets/PostProcessingV2/Runtime/Utils/HableCurve.cs [121:226]
void InitSegments(DirectParams srcParams)
{
var paramsCopy = srcParams;
whitePoint = srcParams.W;
inverseWhitePoint = 1f / srcParams.W;
// normalize params to 1.0 range
paramsCopy.W = 1f;
paramsCopy.x0 /= srcParams.W;
paramsCopy.x1 /= srcParams.W;
paramsCopy.overshootX = srcParams.overshootX / srcParams.W;
float toeM = 0f;
float shoulderM = 0f;
{
float m, b;
AsSlopeIntercept(out m, out b, paramsCopy.x0, paramsCopy.x1, paramsCopy.y0, paramsCopy.y1);
float g = srcParams.gamma;
// Base function of linear section plus gamma is
// y = (mx+b)^g
//
// which we can rewrite as
// y = exp(g*ln(m) + g*ln(x+b/m))
//
// and our evaluation function is (skipping the if parts):
/*
float x0 = (x - offsetX) * scaleX;
y0 = exp(m_lnA + m_B*log(x0));
return y0*scaleY + m_offsetY;
*/
var midSegment = segments[1];
midSegment.offsetX = -(b / m);
midSegment.offsetY = 0f;
midSegment.scaleX = 1f;
midSegment.scaleY = 1f;
midSegment.lnA = g * Mathf.Log(m);
midSegment.B = g;
toeM = EvalDerivativeLinearGamma(m, b, g, paramsCopy.x0);
shoulderM = EvalDerivativeLinearGamma(m, b, g, paramsCopy.x1);
// apply gamma to endpoints
paramsCopy.y0 = Mathf.Max(1e-5f, Mathf.Pow(paramsCopy.y0, paramsCopy.gamma));
paramsCopy.y1 = Mathf.Max(1e-5f, Mathf.Pow(paramsCopy.y1, paramsCopy.gamma));
paramsCopy.overshootY = Mathf.Pow(1f + paramsCopy.overshootY, paramsCopy.gamma) - 1f;
}
this.x0 = paramsCopy.x0;
this.x1 = paramsCopy.x1;
// Toe section
{
var toeSegment = segments[0];
toeSegment.offsetX = 0;
toeSegment.offsetY = 0f;
toeSegment.scaleX = 1f;
toeSegment.scaleY = 1f;
float lnA, B;
SolveAB(out lnA, out B, paramsCopy.x0, paramsCopy.y0, toeM);
toeSegment.lnA = lnA;
toeSegment.B = B;
}
// Shoulder section
{
// Use the simple version that is usually too flat
var shoulderSegment = segments[2];
float x0 = (1f + paramsCopy.overshootX) - paramsCopy.x1;
float y0 = (1f + paramsCopy.overshootY) - paramsCopy.y1;
float lnA, B;
SolveAB(out lnA, out B, x0, y0, shoulderM);
shoulderSegment.offsetX = (1f + paramsCopy.overshootX);
shoulderSegment.offsetY = (1f + paramsCopy.overshootY);
shoulderSegment.scaleX = -1f;
shoulderSegment.scaleY = -1f;
shoulderSegment.lnA = lnA;
shoulderSegment.B = B;
}
// Normalize so that we hit 1.0 at our white point. We wouldn't have do this if we
// skipped the overshoot part.
{
// Evaluate shoulder at the end of the curve
float scale = segments[2].Eval(1f);
float invScale = 1f / scale;
segments[0].offsetY *= invScale;
segments[0].scaleY *= invScale;
segments[1].offsetY *= invScale;
segments[1].scaleY *= invScale;
segments[2].offsetY *= invScale;
segments[2].scaleY *= invScale;
}
}