Rasagar/Library/PackageCache/com.unity.render-pipelines.core/ShaderLibrary/SphericalHarmonics.hlsl
2024-08-26 23:07:20 +03:00

212 lines
5.8 KiB
HLSL

#ifndef UNITY_SPHERICAL_HARMONICS_INCLUDED
#define UNITY_SPHERICAL_HARMONICS_INCLUDED
#ifdef UNITY_COLORSPACE_GAMMA
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
#endif
// SH Basis coefs
#define kSHBasis0 0.28209479177387814347f // {0, 0} : 1/2 * sqrt(1/Pi)
#define kSHBasis1 0.48860251190291992159f // {1, 0} : 1/2 * sqrt(3/Pi)
#define kSHBasis2 1.09254843059207907054f // {2,-2} : 1/2 * sqrt(15/Pi)
#define kSHBasis3 0.31539156525252000603f // {2, 0} : 1/4 * sqrt(5/Pi)
#define kSHBasis4 0.54627421529603953527f // {2, 2} : 1/4 * sqrt(15/Pi)
static const float kSHBasisCoef[] = { kSHBasis0, -kSHBasis1, kSHBasis1, -kSHBasis1, kSHBasis2, -kSHBasis2, kSHBasis3, -kSHBasis2, kSHBasis4 };
// Clamped cosine convolution coefs (pre-divided by PI)
// See https://seblagarde.wordpress.com/2012/01/08/pi-or-not-to-pi-in-game-lighting-equation/
#define kClampedCosine0 (1.0f)
#define kClampedCosine1 (2.0f / 3.0f)
#define kClampedCosine2 (1.0f / 4.0f)
static const float kClampedCosineCoefs[] = { kClampedCosine0, kClampedCosine1, kClampedCosine1, kClampedCosine1, kClampedCosine2, kClampedCosine2, kClampedCosine2, kClampedCosine2, kClampedCosine2 };
// Ref: "Efficient Evaluation of Irradiance Environment Maps" from ShaderX 2
real3 SHEvalLinearL0L1(real3 N, real4 shAr, real4 shAg, real4 shAb)
{
real4 vA = real4(N, 1.0);
real3 x1;
// Linear (L1) + constant (L0) polynomial terms
x1.r = dot(shAr, vA);
x1.g = dot(shAg, vA);
x1.b = dot(shAb, vA);
return x1;
}
real3 SHEvalLinearL1(real3 N, real3 shAr, real3 shAg, real3 shAb)
{
real3 x1;
x1.r = dot(shAr, N);
x1.g = dot(shAg, N);
x1.b = dot(shAb, N);
return x1;
}
real3 SHEvalLinearL2(real3 N, real4 shBr, real4 shBg, real4 shBb, real4 shC)
{
real3 x2;
// 4 of the quadratic (L2) polynomials
real4 vB = N.xyzz * N.yzzx;
x2.r = dot(shBr, vB);
x2.g = dot(shBg, vB);
x2.b = dot(shBb, vB);
// Final (5th) quadratic (L2) polynomial
real vC = N.x * N.x - N.y * N.y;
real3 x3 = shC.rgb * vC;
return x2 + x3;
}
#if !HALF_IS_FLOAT
half3 SampleSH9(half4 SHCoefficients[7], half3 N)
{
half4 shAr = SHCoefficients[0];
half4 shAg = SHCoefficients[1];
half4 shAb = SHCoefficients[2];
half4 shBr = SHCoefficients[3];
half4 shBg = SHCoefficients[4];
half4 shBb = SHCoefficients[5];
half4 shCr = SHCoefficients[6];
// Linear + constant polynomial terms
half3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
// Quadratic polynomials
res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return res;
}
half3 SampleSH4_L1(half4 SHCoefficients[3], half3 N)
{
half4 shAr = SHCoefficients[0];
half4 shAg = SHCoefficients[1];
half4 shAb = SHCoefficients[2];
// Linear + constant polynomial terms
half3 res = SHEvalLinearL1(N, shAr.xyz, shAg.xyz, shAb.xyz);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return res;
}
#endif
float3 SampleSH9(float4 SHCoefficients[7], float3 N)
{
float4 shAr = SHCoefficients[0];
float4 shAg = SHCoefficients[1];
float4 shAb = SHCoefficients[2];
float4 shBr = SHCoefficients[3];
float4 shBg = SHCoefficients[4];
float4 shBb = SHCoefficients[5];
float4 shCr = SHCoefficients[6];
// Linear + constant polynomial terms
float3 res = SHEvalLinearL0L1(N, shAr, shAg, shAb);
// Quadratic polynomials
res += SHEvalLinearL2(N, shBr, shBg, shBb, shCr);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return res;
}
float3 SampleSH9(StructuredBuffer<float4> data, float3 N)
{
real4 SHCoefficients[7];
SHCoefficients[0] = data[0];
SHCoefficients[1] = data[1];
SHCoefficients[2] = data[2];
SHCoefficients[3] = data[3];
SHCoefficients[4] = data[4];
SHCoefficients[5] = data[5];
SHCoefficients[6] = data[6];
return SampleSH9(SHCoefficients, N);
}
float3 SampleSH4_L1(float4 SHCoefficients[3], float3 N)
{
float4 shAr = SHCoefficients[0];
float4 shAg = SHCoefficients[1];
float4 shAb = SHCoefficients[2];
// Linear + constant polynomial terms
float3 res = SHEvalLinearL1(N, (float3)shAr, (float3)shAg, (float3)shAb);
#ifdef UNITY_COLORSPACE_GAMMA
res = LinearToSRGB(res);
#endif
return res;
}
void GetCornetteShanksPhaseFunction(out float3 zh, float anisotropy)
{
float g = anisotropy;
zh.x = 0.282095f;
zh.y = 0.293162f * g * (4.0f + (g * g)) / (2.0f + (g * g));
zh.z = (0.126157f + 1.44179f * (g * g) + 0.324403f * (g * g) * (g * g)) / (2.0f + (g * g));
}
void ConvolveZonal(inout float sh[27], float3 zh)
{
for (int l = 0; l <= 2; l++)
{
float n = sqrt((4.0f * PI) / (2 * l + 1));
float k = zh[l];
float p = n * k;
for (int m = -l; m <= l; m++)
{
int i = l * (l + 1) + m;
for (int c = 0; c < 3; c++)
{
sh[c * 9 + i] = sh[c * 9 + i] * p;
}
}
}
}
// Packs coefficients so that we can use Peter-Pike Sloan's shader code.
// The function does not perform premultiplication with coefficients of SH basis functions, caller need to do it
// See SetSHEMapConstants() in "Stupid Spherical Harmonics Tricks".
// Constant + linear
void PackSH(RWStructuredBuffer<float4> buffer, float sh[27])
{
int c = 0;
for (c = 0; c < 3; c++)
{
buffer[c] = float4(sh[c * 9 + 3], sh[c * 9 + 1], sh[c * 9 + 2], sh[c * 9 + 0] - sh[c * 9 + 6]);
}
// Quadratic (4/5)
for (c = 0; c < 3; c++)
{
buffer[3 + c] = float4(sh[c * 9 + 4], sh[c * 9 + 5], sh[c * 9 + 6] * 3.0f, sh[c * 9 + 7]);
}
// Quadratic (5)
buffer[6] = float4(sh[0 * 9 + 8], sh[1 * 9 + 8], sh[2 * 9 + 8], 1.0f);
}
#endif // UNITY_SPHERICAL_HARMONICS_INCLUDED