예제 #1
0
        public void Init(float toeStrength, float toeLength, float shoulderStrength, float shoulderLength, float shoulderAngle, float gamma)
        {
            DirectParams srcParams = default(DirectParams);

            toeLength        = Mathf.Pow(Mathf.Clamp01(toeLength), 2.2f);
            toeStrength      = Mathf.Clamp01(toeStrength);
            shoulderAngle    = Mathf.Clamp01(shoulderAngle);
            shoulderStrength = Mathf.Clamp(shoulderStrength, 1E-05f, 0.99999f);
            shoulderLength   = Mathf.Max(0f, shoulderLength);
            gamma            = Mathf.Max(1E-05f, gamma);
            float num  = toeLength * 0.5f;
            float num2 = (1f - toeStrength) * num;
            float num3 = 1f - num2;
            float num4 = num + num3;
            float num5 = (1f - shoulderStrength) * num3;
            float x    = num + num5;
            float y    = num2 + num5;
            float num6 = RuntimeUtilities.Exp2(shoulderLength) - 1f;
            float w    = num4 + num6;

            srcParams.x0         = num;
            srcParams.y0         = num2;
            srcParams.x1         = x;
            srcParams.y1         = y;
            srcParams.W          = w;
            srcParams.gamma      = gamma;
            srcParams.overshootX = srcParams.W * 2f * shoulderAngle * shoulderLength;
            srcParams.overshootY = 0.5f * shoulderAngle * shoulderLength;
            InitSegments(srcParams);
        }
예제 #2
0
        private void InitSegments(DirectParams srcParams)
        {
            DirectParams directParams = srcParams;

            whitePoint              = srcParams.W;
            inverseWhitePoint       = 1f / srcParams.W;
            directParams.W          = 1f;
            directParams.x0        /= srcParams.W;
            directParams.x1        /= srcParams.W;
            directParams.overshootX = srcParams.overshootX / srcParams.W;
            float num  = 0f;
            float num2 = 0f;

            AsSlopeIntercept(out float m, out float b, directParams.x0, directParams.x1, directParams.y0, directParams.y1);
            float   gamma   = srcParams.gamma;
            Segment segment = segments[1];

            segment.offsetX         = 0f - b / m;
            segment.offsetY         = 0f;
            segment.scaleX          = 1f;
            segment.scaleY          = 1f;
            segment.lnA             = gamma * Mathf.Log(m);
            segment.B               = gamma;
            num                     = EvalDerivativeLinearGamma(m, b, gamma, directParams.x0);
            num2                    = EvalDerivativeLinearGamma(m, b, gamma, directParams.x1);
            directParams.y0         = Mathf.Max(1E-05f, Mathf.Pow(directParams.y0, directParams.gamma));
            directParams.y1         = Mathf.Max(1E-05f, Mathf.Pow(directParams.y1, directParams.gamma));
            directParams.overshootY = Mathf.Pow(1f + directParams.overshootY, directParams.gamma) - 1f;
            x0 = directParams.x0;
            x1 = directParams.x1;
            Segment segment2 = segments[0];

            segment2.offsetX = 0f;
            segment2.offsetY = 0f;
            segment2.scaleX  = 1f;
            segment2.scaleY  = 1f;
            SolveAB(out float lnA, out float B, directParams.x0, directParams.y0, num);
            segment2.lnA = lnA;
            segment2.B   = B;
            Segment segment3 = segments[2];
            float   x        = 1f + directParams.overshootX - directParams.x1;
            float   y        = 1f + directParams.overshootY - directParams.y1;

            SolveAB(out float lnA2, out float B2, x, y, num2);
            segment3.offsetX = 1f + directParams.overshootX;
            segment3.offsetY = 1f + directParams.overshootY;
            segment3.scaleX  = -1f;
            segment3.scaleY  = -1f;
            segment3.lnA     = lnA2;
            segment3.B       = B2;
            float num3 = segments[2].Eval(1f);
            float num4 = 1f / num3;

            segments[0].offsetY *= num4;
            segments[0].scaleY  *= num4;
            segments[1].offsetY *= num4;
            segments[1].scaleY  *= num4;
            segments[2].offsetY *= num4;
            segments[2].scaleY  *= num4;
        }
예제 #3
0
        public void Init(float toeStrength, float toeLength, float shoulderStrength, float shoulderLength,
                         float shoulderAngle, float gamma)
        {
            var dstParams = new DirectParams();

            // This is not actually the display gamma. It's just a UI space to avoid having to
            // enter small numbers for the input.
            const float kPerceptualGamma = 2.2f;

            // Constraints
            {
                toeLength        = Mathf.Pow(Mathf.Clamp01(toeLength), kPerceptualGamma);
                toeStrength      = Mathf.Clamp01(toeStrength);
                shoulderAngle    = Mathf.Clamp01(shoulderAngle);
                shoulderStrength = Mathf.Clamp(shoulderStrength, 1e-5f, 1f - 1e-5f);
                shoulderLength   = Mathf.Max(0f, shoulderLength);
                gamma            = Mathf.Max(1e-5f, gamma);
            }

            // Apply base params
            {
                // Toe goes from 0 to 0.5
                var x0 = toeLength * 0.5f;
                var y0 = (1f - toeStrength) * x0; // Lerp from 0 to x0

                var remainingY = 1f - y0;

                var initialW = x0 + remainingY;

                var y1_offset = (1f - shoulderStrength) * remainingY;
                var x1        = x0 + y1_offset;
                var y1        = y0 + y1_offset;

                // Filmic shoulder strength is in F stops
                var extraW = RuntimeUtilities.Exp2(shoulderLength) - 1f;

                var W = initialW + extraW;

                dstParams.x0 = x0;
                dstParams.y0 = y0;
                dstParams.x1 = x1;
                dstParams.y1 = y1;
                dstParams.W  = W;

                // Bake the linear to gamma space conversion
                dstParams.gamma = gamma;
            }

            dstParams.overshootX = dstParams.W * 2f * shoulderAngle * shoulderLength;
            dstParams.overshootY = 0.5f * shoulderAngle * shoulderLength;

            InitSegments(dstParams);
        }
예제 #4
0
        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;
            }
        }