﻿// Copyright (c) .NET Foundation and Contributors (https://dotnetfoundation.org/ & https://stride3d.net) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.

namespace Stride.Rendering.Materials
{
    class MaterialSubsurfaceScatteringScatteringProfileCustomVarying : IMaterialSubsurfaceScatteringScatteringProfile
    {
        compose ComputeColor FalloffMap;
        
        stage stream float3 falloff;

        override void Prepare(void)
        {
            // Calculate the falloff here and only once for all lights.
            streams.falloff = FalloffMap.Compute().rgb;    // TODO: Try supplying the texture using a streams variable instead? Might solve the issue with less code.
        }

        float3 Gaussian(float variance, float dd, float3 falloff)
        {
            // We use a falloff to modulate the shape of the profile. Big falloffs
            // spreads the shape making it wider, while small falloffs make it
            // narrower.
            const float3 adjustedFalloff = 0.001 + falloff;
            const float3 adjustedFalloffSquared = adjustedFalloff * adjustedFalloff;

            const float twoVariance = 2.0 * variance;
            const float twoPiVariance = 3.14 * twoVariance;
            
            const float3 adjustedFalloffSquaredTwoVariance = adjustedFalloffSquared * twoVariance;
            
            return exp(dd / adjustedFalloffSquaredTwoVariance) / twoPiVariance;
        }

        float3 Compute(float dd)
        {
            // We used the red channel of the original skin profile defined in
            // [d'Eon07] for all three channels. We noticed it can be used for green
            // and blue channels (scaled using the falloff parameter) without
            // introducing noticeable differences and allowing for total control over
            // the profile. For example, it allows to create blue SSS gradients, which
            // could be useful in case of rendering blue creatures.
            
            return 0.233 * Gaussian(0.0064, dd, streams.falloff) + // We consider this one to be directly bounced light, accounted by the strength parameter (see @STRENGTH)
                   0.100 * Gaussian(0.0484, dd, streams.falloff) +
                   0.118 * Gaussian(0.187,  dd, streams.falloff) +
                   0.113 * Gaussian(0.567,  dd, streams.falloff) +
                   0.358 * Gaussian(1.99,   dd, streams.falloff) +
                   0.078 * Gaussian(7.41,   dd, streams.falloff);
        }
    };
}
