diff --git a/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli b/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli index 405452096..6451eb4cd 100644 --- a/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli +++ b/features/Skylighting/Shaders/Skylighting/Skylighting.hlsli @@ -72,13 +72,13 @@ namespace Skylighting float w = trilinearWeights.x * trilinearWeights.y * trilinearWeights.z * tangentWeight; uint3 cellTexID = (cellID + params.ArrayOrigin.xyz) % ARRAY_DIM; - sh2 probe = shScale(probeArray[cellTexID], w); + sh2 probe = SphericalHarmonics::Scale(probeArray[cellTexID], w); - sum = shAdd(sum, probe); + sum = SphericalHarmonics::Add(sum, probe); wsum += w; } - return shScale(sum, rcp(wsum + 1e-10)); + return SphericalHarmonics::Scale(sum, rcp(wsum + 1e-10)); } float getVL(SkylightingSettings params, Texture3D probeArray, float3 startPosWS, float3 endPosWS, float2 pxCoord) @@ -102,7 +102,7 @@ namespace Skylighting sh2 skylighting = Skylighting::sample(params, probeArray, samplePositionWS, float3(0, 0, 1)); - shadow += Skylighting::mixDiffuse(params, shUnproject(skylighting, worldDirNormalised)); + shadow += Skylighting::mixDiffuse(params, SphericalHarmonics::Unproject(skylighting, worldDirNormalised)); } vl += shadow; } @@ -123,10 +123,10 @@ namespace Skylighting float roughness2 = roughness * roughness; float halfAngle = clamp(4.1679 * roughness2 * roughness2 - 9.0127 * roughness2 * roughness + 4.6161 * roughness2 + 1.7048 * roughness + 0.1, 0, Math::HALF_PI); float lerpFactor = halfAngle / Math::HALF_PI; - sh2 directional = shEvaluate(dominantDir); - sh2 cosineLobe = shEvaluateCosineLobe(dominantDir) / Math::PI; - sh2 result = shAdd(shScale(directional, lerpFactor), shScale(cosineLobe, 1 - lerpFactor)); + sh2 directional = SphericalHarmonics::Evaluate(dominantDir); + sh2 cosineLobe = SphericalHarmonics::EvaluateCosineLobe(dominantDir) / Math::PI; + sh2 result = SphericalHarmonics::Add(SphericalHarmonics::Scale(directional, lerpFactor), SphericalHarmonics::Scale(cosineLobe, 1 - lerpFactor)); return result; } -} \ No newline at end of file +} diff --git a/features/Skylighting/Shaders/Skylighting/UpdateProbesCS.hlsl b/features/Skylighting/Shaders/Skylighting/UpdateProbesCS.hlsl index 39d010418..2ecf995e9 100644 --- a/features/Skylighting/Shaders/Skylighting/UpdateProbesCS.hlsl +++ b/features/Skylighting/Shaders/Skylighting/UpdateProbesCS.hlsl @@ -30,13 +30,13 @@ SamplerState samplerPointClamp : register(s0); float occlusionDepth = srcOcclusionDepth.SampleLevel(samplerPointClamp, occlusionUV, 0); float visibility = saturate((occlusionDepth + 0.0005 - cellCentreOS.z) * 1024); - sh2 occlusionSH = shScale(shEvaluate(settings.OcclusionDir.xyz), visibility * 4.0 * Math::PI); // 4 pi from monte carlo + sh2 occlusionSH = SphericalHarmonics::Scale(SphericalHarmonics::Evaluate(settings.OcclusionDir.xyz), visibility * 4.0 * Math::PI); // 4 pi from monte carlo if (isValid) { float lerpFactor = rcp(accumFrames); sh2 prevProbeSH = unitSH; if (accumFrames > 1) prevProbeSH += (outProbeArray[dtid] - unitSH) * fadeInThreshold / min(fadeInThreshold, accumFrames - 1); // inverse confidence - occlusionSH = shAdd(shScale(prevProbeSH, 1 - lerpFactor), shScale(occlusionSH, lerpFactor)); + occlusionSH = SphericalHarmonics::Add(SphericalHarmonics::Scale(prevProbeSH, 1 - lerpFactor), SphericalHarmonics::Scale(occlusionSH, lerpFactor)); } occlusionSH = lerp(unitSH, occlusionSH, min(fadeInThreshold, accumFrames) / fadeInThreshold); // confidence fade in diff --git a/package/Shaders/AmbientCompositeCS.hlsl b/package/Shaders/AmbientCompositeCS.hlsl index 586eb0986..25741d276 100644 --- a/package/Shaders/AmbientCompositeCS.hlsl +++ b/package/Shaders/AmbientCompositeCS.hlsl @@ -67,7 +67,7 @@ RWTexture2D DiffuseAmbientRW : register(u1); # endif sh2 skylighting = Skylighting::sample(skylightingSettings, SkylightingProbeArray, positionMS.xyz, normalWS); - half skylightingDiffuse = shFuncProductIntegral(skylighting, shEvaluateCosineLobe(float3(normalWS.xy, normalWS.z * 0.5 + 0.5))) / Math::PI; + half skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylighting, SphericalHarmonics::EvaluateCosineLobe(float3(normalWS.xy, normalWS.z * 0.5 + 0.5))) / Math::PI; skylightingDiffuse = Skylighting::mixDiffuse(skylightingSettings, skylightingDiffuse); visibility = skylightingDiffuse; diff --git a/package/Shaders/Common/DICETonemapper.hlsli b/package/Shaders/Common/DICETonemapper.hlsli deleted file mode 100644 index 811b9a0d2..000000000 --- a/package/Shaders/Common/DICETonemapper.hlsli +++ /dev/null @@ -1,150 +0,0 @@ -// https://www.ea.com/frostbite/news/high-dynamic-range-color-grading-and-display-in-frostbite - -// Applies exponential ("Photographic") luma compression -float RangeCompress(float x) -{ - return 1.0 - exp(-x); -} - -float RangeCompress(float val, float threshold) -{ - float v1 = val; - float v2 = threshold + (1 - threshold) * RangeCompress((val - threshold) / (1 - threshold)); - return val < threshold ? v1 : v2; -} - -float3 RangeCompress(float3 val, float threshold) -{ - return float3( - RangeCompress(val.x, threshold), - RangeCompress(val.y, threshold), - RangeCompress(val.z, threshold)); -} - -static const float PQ_constant_N = (2610.0 / 4096.0 / 4.0); -static const float PQ_constant_M = (2523.0 / 4096.0 * 128.0); -static const float PQ_constant_C1 = (3424.0 / 4096.0); -static const float PQ_constant_C2 = (2413.0 / 4096.0 * 32.0); -static const float PQ_constant_C3 = (2392.0 / 4096.0 * 32.0); - -// PQ (Perceptual Quantiser; ST.2084) encode/decode used for HDR TV and grading -float3 LinearToPQ(float3 linearCol, const float maxPqValue) -{ - linearCol /= maxPqValue; - - float3 colToPow = pow(linearCol, PQ_constant_N); - float3 numerator = PQ_constant_C1 + PQ_constant_C2 * colToPow; - float3 denominator = 1.0 + PQ_constant_C3 * colToPow; - float3 pq = pow(numerator / denominator, PQ_constant_M); - - return pq; -} - -float3 PQtoLinear(float3 linearCol, const float maxPqValue) -{ - float3 colToPow = pow(linearCol, 1.0 / PQ_constant_M); - float3 numerator = max(colToPow - PQ_constant_C1, 0.0); - float3 denominator = PQ_constant_C2 - (PQ_constant_C3 * colToPow); - float3 linearColor = pow(numerator / denominator, 1.0 / PQ_constant_N); - - linearColor *= maxPqValue; - - return linearColor; -} - -// RGB with sRGB/Rec.709 primaries to CIE XYZ -float3 RGBToXYZ(float3 c) -{ - float3x3 mat = float3x3( - 0.4124564, 0.3575761, 0.1804375, - 0.2126729, 0.7151522, 0.0721750, - 0.0193339, 0.1191920, 0.9503041); - return mul(mat, c); -} -float3 XYZToRGB(float3 c) -{ - float3x3 mat = float3x3( - 3.24045483602140870, -1.53713885010257510, -0.49853154686848090, - -0.96926638987565370, 1.87601092884249100, 0.04155608234667354, - 0.05564341960421366, -0.20402585426769815, 1.05722516245792870); - return mul(mat, c); -} -// Converts XYZ tristimulus values into cone responses for the three types of cones in the human visual system, matching long, medium, and short wavelengths. -// Note that there are many LMS color spaces; this one follows the ICtCp color space specification. -float3 XYZToLMS(float3 c) -{ - float3x3 mat = float3x3( - 0.3592, 0.6976, -0.0358, - -0.1922, 1.1004, 0.0755, - 0.0070, 0.0749, 0.8434); - return mul(mat, c); -} -float3 LMSToXYZ(float3 c) -{ - float3x3 mat = float3x3( - 2.07018005669561320, -1.32645687610302100, 0.206616006847855170, - 0.36498825003265756, 0.68046736285223520, -0.045421753075853236, - -0.04959554223893212, -0.04942116118675749, 1.187995941732803400); - return mul(mat, c); -} - -// RGB with sRGB/Rec.709 primaries to ICtCp -float3 RGBToICtCp(float3 col) -{ - col = RGBToXYZ(col); - col = XYZToLMS(col); - // 1.0f = 100 nits, 100.0f = 10k nits - col = LinearToPQ(max(0.0.xxx, col), 100.0); - - // Convert PQ-LMS into ICtCp. Note that the "S" channel is not used, - // but overlap between the cone responses for long, medium, and short wavelengths - // ensures that the corresponding part of the spectrum contributes to luminance. - - float3x3 mat = float3x3( - 0.5000, 0.5000, 0.0000, - 1.6137, -3.3234, 1.7097, - 4.3780, -4.2455, -0.1325); - - return mul(mat, col); -} - -float3 ICtCpToRGB(float3 col) -{ - float3x3 mat = float3x3( - 1.0, 0.00860514569398152, 0.11103560447547328, - 1.0, -0.00860514569398152, -0.11103560447547328, - 1.0, 0.56004885956263900, -0.32063747023212210); - col = mul(mat, col); - - // 1.0f = 100 nits, 100.0f = 10k nits - col = PQtoLinear(col, 100.0); - col = LMSToXYZ(col); - return XYZToRGB(col); -} - -// Only compress luminance starting at a certain point. Dimmer inputs are passed through without modification. -float3 ApplyHuePreservingShoulder(float3 col, float linearSegmentEnd = 0.25) -{ - float3 ictcp = RGBToICtCp(col); - - // Hue-preserving range compression requires desaturation in order to achieve a natural look. We adaptively desaturate the input based on its luminance. - float saturationAmount = pow(smoothstep(1.0, 0.3, ictcp.x), 1.3); - col = ICtCpToRGB(ictcp * float3(1, saturationAmount.xx)); - - // Non-hue preserving mapping - col = RangeCompress(col, linearSegmentEnd); - - float3 ictcpMapped = RGBToICtCp(col); - - // Smoothly ramp off saturation as brightness increases, but keep some even for very bright input - float postCompressionSaturationBoost = 0.3 * smoothstep(1.0, 0.5, ictcp.x); - - // Re-introduce some hue from the pre-compression color. Something similar could be accomplished by delaying the luma-dependent desaturation before range compression. - // Doing it here however does a better job of preserving perceptual luminance of highly saturated colors. Because in the hue-preserving path we only range-compress the max channel, - // saturated colors lose luminance. By desaturating them more aggressively first, compressing, and then re-adding some saturation, we can preserve their brightness to a greater extent. - ictcpMapped.yz = lerp(ictcpMapped.yz, ictcp.yz * ictcpMapped.x / max(1e-3, ictcp.x), postCompressionSaturationBoost); - - col = ICtCpToRGB(ictcpMapped); - - return col; -} diff --git a/package/Shaders/Common/Glints/Glints2023.hlsli b/package/Shaders/Common/Glints/Glints2023.hlsli index 5f0a62f01..bbd05cd0b 100644 --- a/package/Shaders/Common/Glints/Glints2023.hlsli +++ b/package/Shaders/Common/Glints/Glints2023.hlsli @@ -2,541 +2,544 @@ Texture2D _Glint2023NoiseMap : register(t28); -//======================================================================================= -// TOOLS -//======================================================================================= -float erfinv(float x) +namespace Glints { - float w, p; - w = -log((1.0 - x) * (1.0 + x)); - if (w < 5.000000) { - w = w - 2.500000; - p = 2.81022636e-08; - p = 3.43273939e-07 + p * w; - p = -3.5233877e-06 + p * w; - p = -4.39150654e-06 + p * w; - p = 0.00021858087 + p * w; - p = -0.00125372503 + p * w; - p = -0.00417768164 + p * w; - p = 0.246640727 + p * w; - p = 1.50140941 + p * w; - } else { - w = sqrt(w) - 3.000000; - p = -0.000200214257; - p = 0.000100950558 + p * w; - p = 0.00134934322 + p * w; - p = -0.00367342844 + p * w; - p = 0.00573950773 + p * w; - p = -0.0076224613 + p * w; - p = 0.00943887047 + p * w; - p = 1.00167406 + p * w; - p = 2.83297682 + p * w; + //======================================================================================= + // TOOLS + //======================================================================================= + float erfinv(float x) + { + float w, p; + w = -log((1.0 - x) * (1.0 + x)); + if (w < 5.000000) { + w = w - 2.500000; + p = 2.81022636e-08; + p = 3.43273939e-07 + p * w; + p = -3.5233877e-06 + p * w; + p = -4.39150654e-06 + p * w; + p = 0.00021858087 + p * w; + p = -0.00125372503 + p * w; + p = -0.00417768164 + p * w; + p = 0.246640727 + p * w; + p = 1.50140941 + p * w; + } else { + w = sqrt(w) - 3.000000; + p = -0.000200214257; + p = 0.000100950558 + p * w; + p = 0.00134934322 + p * w; + p = -0.00367342844 + p * w; + p = 0.00573950773 + p * w; + p = -0.0076224613 + p * w; + p = 0.00943887047 + p * w; + p = 1.00167406 + p * w; + p = 2.83297682 + p * w; + } + return p * x; } - return p * x; -} -float3 sampleNormalDistribution(float3 u, float mu, float sigma) -{ - //return mu + sigma * (sqrt(-2.0 * log(u.x))* cos(2.0 * pi * u.y)); - float x0 = sigma * 1.414213f * erfinv(2.0 * u.x - 1.0) + mu; - float x1 = sigma * 1.414213f * erfinv(2.0 * u.y - 1.0) + mu; - float x2 = sigma * 1.414213f * erfinv(2.0 * u.z - 1.0) + mu; - return float3(x0, x1, x2); -} - -float4 sampleNormalDistribution(float4 u, float mu, float sigma) -{ - //return mu + sigma * (sqrt(-2.0 * log(u.x))* cos(2.0 * pi * u.y)); - float x0 = sigma * 1.414213f * erfinv(2.0 * u.x - 1.0) + mu; - float x1 = sigma * 1.414213f * erfinv(2.0 * u.y - 1.0) + mu; - float x2 = sigma * 1.414213f * erfinv(2.0 * u.z - 1.0) + mu; - float x3 = sigma * 1.414213f * erfinv(2.0 * u.w - 1.0) + mu; - return float4(x0, x1, x2, x3); -} + float3 sampleNormalDistribution(float3 u, float mu, float sigma) + { + //return mu + sigma * (sqrt(-2.0 * log(u.x))* cos(2.0 * pi * u.y)); + float x0 = sigma * 1.414213f * erfinv(2.0 * u.x - 1.0) + mu; + float x1 = sigma * 1.414213f * erfinv(2.0 * u.y - 1.0) + mu; + float x2 = sigma * 1.414213f * erfinv(2.0 * u.z - 1.0) + mu; + return float3(x0, x1, x2); + } -float3 pcg3dFloat(uint3 v) -{ - v = v * 1664525u + 1013904223u; + float4 sampleNormalDistribution(float4 u, float mu, float sigma) + { + //return mu + sigma * (sqrt(-2.0 * log(u.x))* cos(2.0 * pi * u.y)); + float x0 = sigma * 1.414213f * erfinv(2.0 * u.x - 1.0) + mu; + float x1 = sigma * 1.414213f * erfinv(2.0 * u.y - 1.0) + mu; + float x2 = sigma * 1.414213f * erfinv(2.0 * u.z - 1.0) + mu; + float x3 = sigma * 1.414213f * erfinv(2.0 * u.w - 1.0) + mu; + return float4(x0, x1, x2, x3); + } - v.x += v.y * v.z; - v.y += v.z * v.x; - v.z += v.x * v.y; + float3 pcg3dFloat(uint3 v) + { + v = v * 1664525u + 1013904223u; - v ^= v >> 16u; + v.x += v.y * v.z; + v.y += v.z * v.x; + v.z += v.x * v.y; - v.x += v.y * v.z; - v.y += v.z * v.x; - v.z += v.x * v.y; + v ^= v >> 16u; - return v * (1.0 / 4294967296.0); -} + v.x += v.y * v.z; + v.y += v.z * v.x; + v.z += v.x * v.y; -float HashWithoutSine13(float3 p3) -{ - p3 = frac(p3 * .1031); - p3 += dot(p3, p3.yzx + 33.33); - return frac((p3.x + p3.y) * p3.z); -} + return v * (1.0 / 4294967296.0); + } -float2x2 Inverse(float2x2 A) -{ - return float2x2(A[1][1], -A[0][1], -A[1][0], A[0][0]) / determinant(A); -} + float HashWithoutSine13(float3 p3) + { + p3 = frac(p3 * .1031); + p3 += dot(p3, p3.yzx + 33.33); + return frac((p3.x + p3.y) * p3.z); + } -void GetGradientEllipse(float2 duvdx, float2 duvdy, out float2 ellipseMajor, out float2 ellipseMinor) -{ - float2x2 J = float2x2(duvdx, duvdy); - J = Inverse(J); - J = mul(J, transpose(J)); - - float a = J[0][0]; - float b = J[0][1]; - float c = J[1][0]; - float d = J[1][1]; - - float T = a + d; - float D = a * d - b * c; - float SQ = sqrt(abs(T * T / 3.99999 - D)); - float L1 = T / 2.0 - SQ; - float L2 = T / 2.0 + SQ; - - float2 A0 = float2(L1 - d, c); - float2 A1 = float2(L2 - d, c); - float r0 = rsqrt(L1); - float r1 = rsqrt(L2); - ellipseMajor = normalize(A0) * r0; - ellipseMinor = normalize(A1) * r1; -} + float2x2 Inverse(float2x2 A) + { + return float2x2(A[1][1], -A[0][1], -A[1][0], A[0][0]) / determinant(A); + } -float2 RotateUV(float2 uv, float rotation, float2 mid) -{ - float2 rel_uv = uv - mid; - float2 sincos_rot; - sincos(rotation, sincos_rot.y, sincos_rot.x); - return float2( - sincos_rot.x * rel_uv.x + sincos_rot.y * rel_uv.y + mid.x, - sincos_rot.x * rel_uv.y - sincos_rot.y * rel_uv.x + mid.y); -} + void GetGradientEllipse(float2 duvdx, float2 duvdy, out float2 ellipseMajor, out float2 ellipseMinor) + { + float2x2 J = float2x2(duvdx, duvdy); + J = Inverse(J); + J = mul(J, transpose(J)); + + float a = J[0][0]; + float b = J[0][1]; + float c = J[1][0]; + float d = J[1][1]; + + float T = a + d; + float D = a * d - b * c; + float SQ = sqrt(abs(T * T / 3.99999 - D)); + float L1 = T / 2.0 - SQ; + float L2 = T / 2.0 + SQ; + + float2 A0 = float2(L1 - d, c); + float2 A1 = float2(L2 - d, c); + float r0 = rsqrt(L1); + float r1 = rsqrt(L2); + ellipseMajor = normalize(A0) * r0; + ellipseMinor = normalize(A1) * r1; + } -float BilinearLerp(float4 values, float2 valuesLerp) -{ - // Values XY = float4(00, 01, 10, 11) - float resultX = lerp(values.x, values.z, valuesLerp.x); - float resultY = lerp(values.y, values.w, valuesLerp.x); - float result = lerp(resultX, resultY, valuesLerp.y); - return result; -} + float2 RotateUV(float2 uv, float rotation, float2 mid) + { + float2 rel_uv = uv - mid; + float2 sincos_rot; + sincos(rotation, sincos_rot.y, sincos_rot.x); + return float2( + sincos_rot.x * rel_uv.x + sincos_rot.y * rel_uv.y + mid.x, + sincos_rot.x * rel_uv.y - sincos_rot.y * rel_uv.x + mid.y); + } -float4 BilinearLerpParallel4(float4 values00, float4 values01, float4 values10, float4 values11, float4 valuesLerpX, float4 valuesLerpY) -{ - // Values XY = float4(00, 01, 10, 11) - float4 resultX = lerp(values00, values10, valuesLerpX); - float4 resultY = lerp(values01, values11, valuesLerpX); - float4 result = lerp(resultX, resultY, valuesLerpY); - return result; -} + float BilinearLerp(float4 values, float2 valuesLerp) + { + // Values XY = float4(00, 01, 10, 11) + float resultX = lerp(values.x, values.z, valuesLerp.x); + float resultY = lerp(values.y, values.w, valuesLerp.x); + float result = lerp(resultX, resultY, valuesLerp.y); + return result; + } -float Remap(float s, float a1, float a2, float b1, float b2) -{ - return b1 + (s - a1) * (b2 - b1) / (a2 - a1); -} + float4 BilinearLerpParallel4(float4 values00, float4 values01, float4 values10, float4 values11, float4 valuesLerpX, float4 valuesLerpY) + { + // Values XY = float4(00, 01, 10, 11) + float4 resultX = lerp(values00, values10, valuesLerpX); + float4 resultY = lerp(values01, values11, valuesLerpX); + float4 result = lerp(resultX, resultY, valuesLerpY); + return result; + } -float Remap01To(float s, float b1, float b2) -{ - return b1 + s * (b2 - b1); -} + float Remap(float s, float a1, float a2, float b1, float b2) + { + return b1 + (s - a1) * (b2 - b1) / (a2 - a1); + } -float RemapTo01(float s, float a1, float a2) -{ - return (s - a1) / (a2 - a1); -} + float Remap01To(float s, float b1, float b2) + { + return b1 + s * (b2 - b1); + } -float4 RemapTo01(float4 s, float4 a1, float4 a2) -{ - return (s - a1) / (a2 - a1); -} + float RemapTo01(float s, float a1, float a2) + { + return (s - a1) / (a2 - a1); + } -float3 GetBarycentricWeights(float2 p, float2 a, float2 b, float2 c) -{ - /*float2 v0 = b - a; - float2 v1 = c - a; - float2 v2 = p - a; - float d00 = dot(v0, v0); - float d01 = dot(v0, v1); - float d11 = dot(v1, v1); - float d20 = dot(v2, v0); - float d21 = dot(v2, v1); - float denom = d00 * d11 - d01 * d01; - float v = (d11 * d20 - d01 * d21) / denom; - float w = (d00 * d21 - d01 * d20) / denom; - float u = 1.0 - v - w; - return float3(u, v, w);*/ - - float2 v0 = b - a; - float2 v1 = c - a; - float2 v2 = p - a; - float den = v0.x * v1.y - v1.x * v0.y; - float rcpDen = rcp(den); - float v = (v2.x * v1.y - v1.x * v2.y) * rcpDen; - float w = (v0.x * v2.y - v2.x * v0.y) * rcpDen; - float u = 1.0f - v - w; - return float3(u, v, w); -} + float4 RemapTo01(float4 s, float4 a1, float4 a2) + { + return (s - a1) / (a2 - a1); + } -float4 GetBarycentricWeightsTetrahedron(float3 p, float3 v1, float3 v2, float3 v3, float3 v4) -{ - float3 c11 = v1 - v4, c21 = v2 - v4, c31 = v3 - v4, c41 = v4 - p; + float3 GetBarycentricWeights(float2 p, float2 a, float2 b, float2 c) + { + /*float2 v0 = b - a; + float2 v1 = c - a; + float2 v2 = p - a; + float d00 = dot(v0, v0); + float d01 = dot(v0, v1); + float d11 = dot(v1, v1); + float d20 = dot(v2, v0); + float d21 = dot(v2, v1); + float denom = d00 * d11 - d01 * d01; + float v = (d11 * d20 - d01 * d21) / denom; + float w = (d00 * d21 - d01 * d20) / denom; + float u = 1.0 - v - w; + return float3(u, v, w);*/ + + float2 v0 = b - a; + float2 v1 = c - a; + float2 v2 = p - a; + float den = v0.x * v1.y - v1.x * v0.y; + float rcpDen = rcp(den); + float v = (v2.x * v1.y - v1.x * v2.y) * rcpDen; + float w = (v0.x * v2.y - v2.x * v0.y) * rcpDen; + float u = 1.0f - v - w; + return float3(u, v, w); + } - float2 m1 = c31.yz / c31.x; - float2 c12 = c11.yz - c11.x * m1, c22 = c21.yz - c21.x * m1, c32 = c41.yz - c41.x * m1; + float4 GetBarycentricWeightsTetrahedron(float3 p, float3 v1, float3 v2, float3 v3, float3 v4) + { + float3 c11 = v1 - v4, c21 = v2 - v4, c31 = v3 - v4, c41 = v4 - p; - float4 uvwk = 0.0.rrrr; - float m2 = c22.y / c22.x; - uvwk.x = (c32.x * m2 - c32.y) / (c12.y - c12.x * m2); - uvwk.y = -(c32.x + c12.x * uvwk.x) / c22.x; - uvwk.z = -(c41.x + c21.x * uvwk.y + c11.x * uvwk.x) / c31.x; - uvwk.w = 1.0 - uvwk.z - uvwk.y - uvwk.x; + float2 m1 = c31.yz / c31.x; + float2 c12 = c11.yz - c11.x * m1, c22 = c21.yz - c21.x * m1, c32 = c41.yz - c41.x * m1; - return uvwk; -} + float4 uvwk = 0.0.rrrr; + float m2 = c22.y / c22.x; + uvwk.x = (c32.x * m2 - c32.y) / (c12.y - c12.x * m2); + uvwk.y = -(c32.x + c12.x * uvwk.x) / c22.x; + uvwk.z = -(c41.x + c21.x * uvwk.y + c11.x * uvwk.x) / c31.x; + uvwk.w = 1.0 - uvwk.z - uvwk.y - uvwk.x; -void UnpackFloat(float input, out float a, out float b) -{ - uint uintInput = asuint(input); - a = f16tof32(uintInput >> 16); - b = f16tof32(uintInput); -} + return uvwk; + } -void UnpackFloatParallel4(float4 input, out float4 a, out float4 b) -{ - uint4 uintInput = asuint(input); - a = f16tof32(uintInput >> 16); - b = f16tof32(uintInput); -} + void UnpackFloat(float input, out float a, out float b) + { + uint uintInput = asuint(input); + a = f16tof32(uintInput >> 16); + b = f16tof32(uintInput); + } -//======================================================================================= -// GLINTS TEST NOVEMBER 2022 -//======================================================================================= + void UnpackFloatParallel4(float4 input, out float4 a, out float4 b) + { + uint4 uintInput = asuint(input); + a = f16tof32(uintInput >> 16); + b = f16tof32(uintInput); + } -struct GlintCachedVars -{ - float2 uv; - uint gridSeed; - float footprintArea; - float gridWeight; -}; + //======================================================================================= + // GLINTS TEST NOVEMBER 2022 + //======================================================================================= -void CustomRand4Texture(float microfacetRoughness, float2 slope, float2 slopeRandOffset, out float4 outUniform, out float4 outGaussian, out float2 slopeLerp) -{ - uint2 size = 64; - float2 slope2 = abs(slope) / microfacetRoughness; - slope2 = slope2 + (slopeRandOffset * size); - slopeLerp = frac(slope2); - uint2 slopeCoord = uint2(floor(slope2)) % size; - - float4 packedRead = _Glint2023NoiseMap[slopeCoord]; - UnpackFloatParallel4(packedRead, outUniform, outGaussian); -} + struct GlintCachedVars + { + float2 uv; + uint gridSeed; + float footprintArea; + float gridWeight; + }; -float GenerateAngularBinomialValueForSurfaceCell(float4 randB, float4 randG, float2 slopeLerp, float footprintOneHitProba, float binomialSmoothWidth, float footprintMean, float footprintSTD, float microfacetCount) -{ - float4 gating; - if (binomialSmoothWidth > 0.0000001) - gating = saturate(RemapTo01(randB, footprintOneHitProba + binomialSmoothWidth, footprintOneHitProba - binomialSmoothWidth)); - else - gating = randB < footprintOneHitProba; - - float4 gauss = randG * footprintSTD + footprintMean; - gauss = clamp(floor(gauss), 0, microfacetCount); - float4 results = gating * (1.0 + gauss); - float result = BilinearLerp(results, slopeLerp); - return result; -} + void CustomRand4Texture(float microfacetRoughness, float2 slope, float2 slopeRandOffset, out float4 outUniform, out float4 outGaussian, out float2 slopeLerp) + { + uint2 size = 64; + float2 slope2 = abs(slope) / microfacetRoughness; + slope2 = slope2 + (slopeRandOffset * size); + slopeLerp = frac(slope2); + uint2 slopeCoord = uint2(floor(slope2)) % size; + + float4 packedRead = _Glint2023NoiseMap[slopeCoord]; + UnpackFloatParallel4(packedRead, outUniform, outGaussian); + } -float SampleGlintGridSimplex(float logDensity, float roughness, float densityRandomization, GlintCachedVars vars, float2 slope, float targetNDF) -{ - // Get surface space glint simplex grid cell - const float2x2 gridToSkewedGrid = float2x2(1.0, -0.57735027, 0.0, 1.15470054); - float2 skewedCoord = mul(gridToSkewedGrid, vars.uv); - int2 baseId = int2(floor(skewedCoord)); - float3 temp = float3(frac(skewedCoord), 0.0); - temp.z = 1.0 - temp.x - temp.y; - float s = step(0.0, -temp.z); - float s2 = 2.0 * s - 1.0; - int2 glint0 = baseId + int2(s, s); - int2 glint1 = baseId + int2(s, 1.0 - s); - int2 glint2 = baseId + int2(1.0 - s, s); - float3 barycentrics = float3(-temp.z * s2, s - temp.y * s2, s - temp.x * s2); - - // Generate per surface cell random numbers - float3 rand0 = pcg3dFloat(uint3(glint0 + 2147483648, vars.gridSeed)); // TODO : optimize away manual seeds - float3 rand1 = pcg3dFloat(uint3(glint1 + 2147483648, vars.gridSeed)); - float3 rand2 = pcg3dFloat(uint3(glint2 + 2147483648, vars.gridSeed)); - - // Get per surface cell per slope cell random numbers - float4 rand0SlopesB, rand1SlopesB, rand2SlopesB, rand0SlopesG, rand1SlopesG, rand2SlopesG; - float2 slopeLerp0, slopeLerp1, slopeLerp2; - CustomRand4Texture(roughness, slope, rand0.yz, rand0SlopesB, rand0SlopesG, slopeLerp0); - CustomRand4Texture(roughness, slope, rand1.yz, rand1SlopesB, rand1SlopesG, slopeLerp1); - CustomRand4Texture(roughness, slope, rand2.yz, rand2SlopesB, rand2SlopesG, slopeLerp2); - - // Compute microfacet count with randomization - float3 logDensityRand = clamp(sampleNormalDistribution(float3(rand0.x, rand1.x, rand2.x), logDensity.r, densityRandomization), 0.0, 50.0); // TODO : optimize sampleNormalDist - float3 microfacetCount = max(1e-8, vars.footprintArea.rrr * exp(logDensityRand)); - float3 microfacetCountBlended = microfacetCount * vars.gridWeight; - - // Compute binomial properties - float hitProba = roughness * targetNDF; // probability of hitting desired half vector in NDF distribution - float3 footprintOneHitProba = (1.0 - pow(abs(1.0 - hitProba.rrr), microfacetCountBlended)); // probability of hitting at least one microfacet in footprint - float3 footprintMean = (microfacetCountBlended - 1.0) * hitProba.rrr; // Expected value of number of hits in the footprint given already one hit - float3 footprintSTD = sqrt((microfacetCountBlended - 1.0) * hitProba.rrr * (1.0 - hitProba.rrr)); // Standard deviation of number of hits in the footprint given already one hit - float3 binomialSmoothWidth = 0.1 * clamp(footprintOneHitProba * 10, 0.0, 1.0) * clamp((1.0 - footprintOneHitProba) * 10, 0.0, 1.0); - - // Generate numbers of reflecting microfacets - float result0, result1, result2; - result0 = GenerateAngularBinomialValueForSurfaceCell(rand0SlopesB, rand0SlopesG, slopeLerp0, footprintOneHitProba.x, binomialSmoothWidth.x, footprintMean.x, footprintSTD.x, microfacetCountBlended.x); - result1 = GenerateAngularBinomialValueForSurfaceCell(rand1SlopesB, rand1SlopesG, slopeLerp1, footprintOneHitProba.y, binomialSmoothWidth.y, footprintMean.y, footprintSTD.y, microfacetCountBlended.y); - result2 = GenerateAngularBinomialValueForSurfaceCell(rand2SlopesB, rand2SlopesG, slopeLerp2, footprintOneHitProba.z, binomialSmoothWidth.z, footprintMean.z, footprintSTD.z, microfacetCountBlended.z); - - // Interpolate result for glint grid cell - float3 results = float3(result0, result1, result2) / microfacetCount.xyz; - float result = dot(results, barycentrics); - return result; -} + float GenerateAngularBinomialValueForSurfaceCell(float4 randB, float4 randG, float2 slopeLerp, float footprintOneHitProba, float binomialSmoothWidth, float footprintMean, float footprintSTD, float microfacetCount) + { + float4 gating; + if (binomialSmoothWidth > 0.0000001) + gating = saturate(RemapTo01(randB, footprintOneHitProba + binomialSmoothWidth, footprintOneHitProba - binomialSmoothWidth)); + else + gating = randB < footprintOneHitProba; + + float4 gauss = randG * footprintSTD + footprintMean; + gauss = clamp(floor(gauss), 0, microfacetCount); + float4 results = gating * (1.0 + gauss); + float result = BilinearLerp(results, slopeLerp); + return result; + } -void GetAnisoCorrectingGridTetrahedron(bool centerSpecialCase, inout float thetaBinLerp, float ratioLerp, float lodLerp, out float3 p0, out float3 p1, out float3 p2, out float3 p3) -{ - [branch] if (centerSpecialCase == true) // SPECIAL CASE (no anisotropy, center of blending pattern, different triangulation) + float SampleGlintGridSimplex(float logDensity, float roughness, float densityRandomization, GlintCachedVars vars, float2 slope, float targetNDF) { - float3 a = float3(0, 1, 0); - float3 b = float3(0, 0, 0); - float3 c = float3(1, 1, 0); - float3 d = float3(0, 1, 1); - float3 e = float3(0, 0, 1); - float3 f = float3(1, 1, 1); - [branch] if (lodLerp > 1.0 - ratioLerp) // Upper pyramid - { - [branch] if (RemapTo01(lodLerp, 1.0 - ratioLerp, 1.0) > thetaBinLerp) // Left-up tetrahedron (a, e, d, f) - { - p0 = a; - p1 = e; - p2 = d; - p3 = f; - } - else // Right-down tetrahedron (f, e, c, a) - { - p0 = f; - p1 = e; - p2 = c; - p3 = a; - } - } - else // Lower tetrahedron (b, a, c, e) - { - p0 = b; - p1 = a; - p2 = c; - p3 = e; - } + // Get surface space glint simplex grid cell + const float2x2 gridToSkewedGrid = float2x2(1.0, -0.57735027, 0.0, 1.15470054); + float2 skewedCoord = mul(gridToSkewedGrid, vars.uv); + int2 baseId = int2(floor(skewedCoord)); + float3 temp = float3(frac(skewedCoord), 0.0); + temp.z = 1.0 - temp.x - temp.y; + float s = step(0.0, -temp.z); + float s2 = 2.0 * s - 1.0; + int2 glint0 = baseId + int2(s, s); + int2 glint1 = baseId + int2(s, 1.0 - s); + int2 glint2 = baseId + int2(1.0 - s, s); + float3 barycentrics = float3(-temp.z * s2, s - temp.y * s2, s - temp.x * s2); + + // Generate per surface cell random numbers + float3 rand0 = pcg3dFloat(uint3(glint0 + 2147483648, vars.gridSeed)); // TODO : optimize away manual seeds + float3 rand1 = pcg3dFloat(uint3(glint1 + 2147483648, vars.gridSeed)); + float3 rand2 = pcg3dFloat(uint3(glint2 + 2147483648, vars.gridSeed)); + + // Get per surface cell per slope cell random numbers + float4 rand0SlopesB, rand1SlopesB, rand2SlopesB, rand0SlopesG, rand1SlopesG, rand2SlopesG; + float2 slopeLerp0, slopeLerp1, slopeLerp2; + CustomRand4Texture(roughness, slope, rand0.yz, rand0SlopesB, rand0SlopesG, slopeLerp0); + CustomRand4Texture(roughness, slope, rand1.yz, rand1SlopesB, rand1SlopesG, slopeLerp1); + CustomRand4Texture(roughness, slope, rand2.yz, rand2SlopesB, rand2SlopesG, slopeLerp2); + + // Compute microfacet count with randomization + float3 logDensityRand = clamp(sampleNormalDistribution(float3(rand0.x, rand1.x, rand2.x), logDensity.r, densityRandomization), 0.0, 50.0); // TODO : optimize sampleNormalDist + float3 microfacetCount = max(1e-8, vars.footprintArea.rrr * exp(logDensityRand)); + float3 microfacetCountBlended = microfacetCount * vars.gridWeight; + + // Compute binomial properties + float hitProba = roughness * targetNDF; // probability of hitting desired half vector in NDF distribution + float3 footprintOneHitProba = (1.0 - pow(abs(1.0 - hitProba.rrr), microfacetCountBlended)); // probability of hitting at least one microfacet in footprint + float3 footprintMean = (microfacetCountBlended - 1.0) * hitProba.rrr; // Expected value of number of hits in the footprint given already one hit + float3 footprintSTD = sqrt((microfacetCountBlended - 1.0) * hitProba.rrr * (1.0 - hitProba.rrr)); // Standard deviation of number of hits in the footprint given already one hit + float3 binomialSmoothWidth = 0.1 * clamp(footprintOneHitProba * 10, 0.0, 1.0) * clamp((1.0 - footprintOneHitProba) * 10, 0.0, 1.0); + + // Generate numbers of reflecting microfacets + float result0, result1, result2; + result0 = GenerateAngularBinomialValueForSurfaceCell(rand0SlopesB, rand0SlopesG, slopeLerp0, footprintOneHitProba.x, binomialSmoothWidth.x, footprintMean.x, footprintSTD.x, microfacetCountBlended.x); + result1 = GenerateAngularBinomialValueForSurfaceCell(rand1SlopesB, rand1SlopesG, slopeLerp1, footprintOneHitProba.y, binomialSmoothWidth.y, footprintMean.y, footprintSTD.y, microfacetCountBlended.y); + result2 = GenerateAngularBinomialValueForSurfaceCell(rand2SlopesB, rand2SlopesG, slopeLerp2, footprintOneHitProba.z, binomialSmoothWidth.z, footprintMean.z, footprintSTD.z, microfacetCountBlended.z); + + // Interpolate result for glint grid cell + float3 results = float3(result0, result1, result2) / microfacetCount.xyz; + float result = dot(results, barycentrics); + return result; } - else // NORMAL CASE + + void GetAnisoCorrectingGridTetrahedron(bool centerSpecialCase, inout float thetaBinLerp, float ratioLerp, float lodLerp, out float3 p0, out float3 p1, out float3 p2, out float3 p3) { - float3 a = float3(0, 1, 0); - float3 b = float3(0, 0, 0); - float3 c = float3(0.5, 1, 0); - float3 d = float3(1, 0, 0); - float3 e = float3(1, 1, 0); - float3 f = float3(0, 1, 1); - float3 g = float3(0, 0, 1); - float3 h = float3(0.5, 1, 1); - float3 i = float3(1, 0, 1); - float3 j = float3(1, 1, 1); - [branch] if (thetaBinLerp < 0.5 && thetaBinLerp * 2.0 < ratioLerp) // Prism A + [branch] if (centerSpecialCase == true) // SPECIAL CASE (no anisotropy, center of blending pattern, different triangulation) { + float3 a = float3(0, 1, 0); + float3 b = float3(0, 0, 0); + float3 c = float3(1, 1, 0); + float3 d = float3(0, 1, 1); + float3 e = float3(0, 0, 1); + float3 f = float3(1, 1, 1); [branch] if (lodLerp > 1.0 - ratioLerp) // Upper pyramid { - [branch] if (RemapTo01(lodLerp, 1.0 - ratioLerp, 1.0) > RemapTo01(thetaBinLerp * 2.0, 0.0, ratioLerp)) // Left-up tetrahedron (a, f, h, g) + [branch] if (RemapTo01(lodLerp, 1.0 - ratioLerp, 1.0) > thetaBinLerp) // Left-up tetrahedron (a, e, d, f) { p0 = a; - p1 = f; - p2 = h; - p3 = g; + p1 = e; + p2 = d; + p3 = f; } - else // Right-down tetrahedron (c, a, h, g) + else // Right-down tetrahedron (f, e, c, a) { - p0 = c; - p1 = a; - p2 = h; - p3 = g; + p0 = f; + p1 = e; + p2 = c; + p3 = a; } } - else // Lower tetrahedron (b, a, c, g) + else // Lower tetrahedron (b, a, c, e) { p0 = b; p1 = a; p2 = c; - p3 = g; + p3 = e; } } - else if (1.0 - ((thetaBinLerp - 0.5) * 2.0) > ratioLerp) // Prism B + else // NORMAL CASE { - [branch] if (lodLerp < 1.0 - ratioLerp) // Lower pyramid + float3 a = float3(0, 1, 0); + float3 b = float3(0, 0, 0); + float3 c = float3(0.5, 1, 0); + float3 d = float3(1, 0, 0); + float3 e = float3(1, 1, 0); + float3 f = float3(0, 1, 1); + float3 g = float3(0, 0, 1); + float3 h = float3(0.5, 1, 1); + float3 i = float3(1, 0, 1); + float3 j = float3(1, 1, 1); + [branch] if (thetaBinLerp < 0.5 && thetaBinLerp * 2.0 < ratioLerp) // Prism A { - [branch] if (RemapTo01(lodLerp, 0.0, 1.0 - ratioLerp) > RemapTo01(thetaBinLerp, 0.5 - (1.0 - ratioLerp) * 0.5, 0.5 + (1.0 - ratioLerp) * 0.5)) // Left-up tetrahedron (b, g, i, c) + [branch] if (lodLerp > 1.0 - ratioLerp) // Upper pyramid { - p0 = b; - p1 = g; - p2 = i; - p3 = c; + [branch] if (RemapTo01(lodLerp, 1.0 - ratioLerp, 1.0) > RemapTo01(thetaBinLerp * 2.0, 0.0, ratioLerp)) // Left-up tetrahedron (a, f, h, g) + { + p0 = a; + p1 = f; + p2 = h; + p3 = g; + } + else // Right-down tetrahedron (c, a, h, g) + { + p0 = c; + p1 = a; + p2 = h; + p3 = g; + } } - else // Right-down tetrahedron (d, b, c, i) + else // Lower tetrahedron (b, a, c, g) { - p0 = d; - p1 = b; + p0 = b; + p1 = a; p2 = c; - p3 = i; + p3 = g; } } - else // Upper tetrahedron (c, g, h, i) + else if (1.0 - ((thetaBinLerp - 0.5) * 2.0) > ratioLerp) // Prism B { - p0 = c; - p1 = g; - p2 = h; - p3 = i; - } - } - else // Prism C - { - [branch] if (lodLerp > 1.0 - ratioLerp) // Upper pyramid - { - [branch] if (RemapTo01(lodLerp, 1.0 - ratioLerp, 1.0) > RemapTo01((thetaBinLerp - 0.5) * 2.0, 1.0 - ratioLerp, 1.0)) // Left-up tetrahedron (c, j, h, i) + [branch] if (lodLerp < 1.0 - ratioLerp) // Lower pyramid + { + [branch] if (RemapTo01(lodLerp, 0.0, 1.0 - ratioLerp) > RemapTo01(thetaBinLerp, 0.5 - (1.0 - ratioLerp) * 0.5, 0.5 + (1.0 - ratioLerp) * 0.5)) // Left-up tetrahedron (b, g, i, c) + { + p0 = b; + p1 = g; + p2 = i; + p3 = c; + } + else // Right-down tetrahedron (d, b, c, i) + { + p0 = d; + p1 = b; + p2 = c; + p3 = i; + } + } + else // Upper tetrahedron (c, g, h, i) { p0 = c; - p1 = j; + p1 = g; p2 = h; p3 = i; } - else // Right-down tetrahedron (e, i, c, j) + } + else // Prism C + { + [branch] if (lodLerp > 1.0 - ratioLerp) // Upper pyramid { - p0 = e; - p1 = i; + [branch] if (RemapTo01(lodLerp, 1.0 - ratioLerp, 1.0) > RemapTo01((thetaBinLerp - 0.5) * 2.0, 1.0 - ratioLerp, 1.0)) // Left-up tetrahedron (c, j, h, i) + { + p0 = c; + p1 = j; + p2 = h; + p3 = i; + } + else // Right-down tetrahedron (e, i, c, j) + { + p0 = e; + p1 = i; + p2 = c; + p3 = j; + } + } + else // Lower tetrahedron (d, e, c, i) + { + p0 = d; + p1 = e; p2 = c; - p3 = j; + p3 = i; } } - else // Lower tetrahedron (d, e, c, i) - { - p0 = d; - p1 = e; - p2 = c; - p3 = i; - } } + + return; } - return; -} + void PrecomputeGlints(float2 uv, float2 duvdx, float2 duvdy, float screenSpaceScale, out GlintCachedVars vars[4]) + { + // ACCURATE PIXEL FOOTPRINT ELLIPSE + float2 ellipseMajor, ellipseMinor; + GetGradientEllipse(duvdx, duvdy, ellipseMajor, ellipseMinor); + float ellipseRatio = length(ellipseMajor) / (length(ellipseMinor) + 1e-8); + + // SHARED GLINT NDF VALUES + float halfScreenSpaceScaler = screenSpaceScale * 0.5; + float footprintArea = length(ellipseMajor) * halfScreenSpaceScaler * length(ellipseMinor) * halfScreenSpaceScaler * 4.0; + + // MANUAL LOD COMPENSATION + float lod = log2(length(ellipseMinor) * halfScreenSpaceScaler); + float lod0 = (int)lod; //lod >= 0.0 ? (int)(lod) : (int)(lod - 1.0); + float lod1 = lod0 + 1; + float divLod0 = pow(2.0, lod0); + float divLod1 = pow(2.0, lod1); + float lodLerp = frac(lod); + float footprintAreaLOD0 = exp2(2.0 * lod0); + float footprintAreaLOD1 = exp2(2.0 * lod1); + + // MANUAL ANISOTROPY RATIO COMPENSATION + float ratio0 = max(pow(2.0, (int)log2(ellipseRatio)), 1.0); + float ratio1 = ratio0 * 2.0; + float ratioLerp = saturate(Remap(ellipseRatio, ratio0, ratio1, 0.0, 1.0)); + + // MANUAL ANISOTROPY ROTATION COMPENSATION + float2 v1 = float2(0.0, 1.0); + float2 v2 = normalize(ellipseMajor); + float theta = atan2(v1.x * v2.y - v1.y * v2.x, v1.x * v2.x + v1.y * v2.y); + float thetaGrid = Math::HALF_PI / max(ratio0, 2.0); + float thetaBin = (int)(theta / thetaGrid) * thetaGrid; + thetaBin = thetaBin + (thetaGrid / 2.0); + float thetaBin0 = theta < thetaBin ? thetaBin - thetaGrid / 2.0 : thetaBin; + float thetaBinH = thetaBin0 + thetaGrid / 4.0; + float thetaBin1 = thetaBin0 + thetaGrid / 2.0; + float thetaBinLerp = Remap(theta, thetaBin0, thetaBin1, 0.0, 1.0); + thetaBin0 = thetaBin0 <= 0.0 ? Math::PI + thetaBin0 : thetaBin0; + + // TETRAHEDRONIZATION OF ROTATION + RATIO + LOD GRID + bool centerSpecialCase = (ratio0.x == 1.0); + float2 divLods = float2(divLod0, divLod1); + float2 footprintAreas = float2(footprintAreaLOD0, footprintAreaLOD1); + float2 ratios = float2(ratio0, ratio1); + float4 thetaBins = float4(thetaBin0, thetaBinH, thetaBin1, 0.0); // added 0.0 for center singularity case + float3 tetraA, tetraB, tetraC, tetraD; + GetAnisoCorrectingGridTetrahedron(centerSpecialCase, thetaBinLerp, ratioLerp, lodLerp, tetraA, tetraB, tetraC, tetraD); + if (centerSpecialCase == true) // Account for center singularity in barycentric computation + thetaBinLerp = Remap01To(thetaBinLerp, 0.0, ratioLerp); + float4 tetraBarycentricWeights = GetBarycentricWeightsTetrahedron(float3(thetaBinLerp, ratioLerp, lodLerp), tetraA, tetraB, tetraC, tetraD); // Compute barycentric coordinates within chosen tetrahedron + + // PREPARE NEEDED ROTATIONS + tetraA.x *= 2; + tetraB.x *= 2; + tetraC.x *= 2; + tetraD.x *= 2; + if (centerSpecialCase == true) // Account for center singularity (if center vertex => no rotation) + { + tetraA.x = (tetraA.y == 0) ? 3 : tetraA.x; + tetraB.x = (tetraB.y == 0) ? 3 : tetraB.x; + tetraC.x = (tetraC.y == 0) ? 3 : tetraC.x; + tetraD.x = (tetraD.y == 0) ? 3 : tetraD.x; + } + float2 uvRotA = RotateUV(uv, thetaBins[tetraA.x], 0.0.rr); + float2 uvRotB = RotateUV(uv, thetaBins[tetraB.x], 0.0.rr); + float2 uvRotC = RotateUV(uv, thetaBins[tetraC.x], 0.0.rr); + float2 uvRotD = RotateUV(uv, thetaBins[tetraD.x], 0.0.rr); + + // SAMPLE GLINT GRIDS + uint gridSeedA = HashWithoutSine13(float3(log2(divLods[tetraA.z]), fmod(thetaBins[tetraA.x], Math::TAU), ratios[tetraA.y])) * 4294967296.0; + uint gridSeedB = HashWithoutSine13(float3(log2(divLods[tetraB.z]), fmod(thetaBins[tetraB.x], Math::TAU), ratios[tetraB.y])) * 4294967296.0; + uint gridSeedC = HashWithoutSine13(float3(log2(divLods[tetraC.z]), fmod(thetaBins[tetraC.x], Math::TAU), ratios[tetraC.y])) * 4294967296.0; + uint gridSeedD = HashWithoutSine13(float3(log2(divLods[tetraD.z]), fmod(thetaBins[tetraD.x], Math::TAU), ratios[tetraD.y])) * 4294967296.0; + + vars[0].uv = uvRotA / divLods[tetraA.z] / float2(1.0, ratios[tetraA.y]); + vars[0].gridSeed = gridSeedA; + vars[0].footprintArea = ratios[tetraA.y] * footprintAreas[tetraA.z]; + vars[0].gridWeight = tetraBarycentricWeights.x; + vars[1].uv = uvRotB / divLods[tetraB.z] / float2(1.0, ratios[tetraB.y]); + vars[1].gridSeed = gridSeedB; + vars[1].footprintArea = ratios[tetraB.y] * footprintAreas[tetraB.z]; + vars[1].gridWeight = tetraBarycentricWeights.y; + vars[2].uv = uvRotC / divLods[tetraC.z] / float2(1.0, ratios[tetraC.y]); + vars[2].gridSeed = gridSeedC; + vars[2].footprintArea = ratios[tetraC.y] * footprintAreas[tetraC.z]; + vars[2].gridWeight = tetraBarycentricWeights.z; + vars[3].uv = uvRotA / divLods[tetraD.z] / float2(1.0, ratios[tetraD.y]); + vars[3].gridSeed = gridSeedD; + vars[3].footprintArea = ratios[tetraD.y] * footprintAreas[tetraD.z]; + vars[3].gridWeight = tetraBarycentricWeights.w; + } -void PrecomputeGlints(float2 uv, float2 duvdx, float2 duvdy, float screenSpaceScale, out GlintCachedVars vars[4]) -{ - // ACCURATE PIXEL FOOTPRINT ELLIPSE - float2 ellipseMajor, ellipseMinor; - GetGradientEllipse(duvdx, duvdy, ellipseMajor, ellipseMinor); - float ellipseRatio = length(ellipseMajor) / (length(ellipseMinor) + 1e-8); - - // SHARED GLINT NDF VALUES - float halfScreenSpaceScaler = screenSpaceScale * 0.5; - float footprintArea = length(ellipseMajor) * halfScreenSpaceScaler * length(ellipseMinor) * halfScreenSpaceScaler * 4.0; - - // MANUAL LOD COMPENSATION - float lod = log2(length(ellipseMinor) * halfScreenSpaceScaler); - float lod0 = (int)lod; //lod >= 0.0 ? (int)(lod) : (int)(lod - 1.0); - float lod1 = lod0 + 1; - float divLod0 = pow(2.0, lod0); - float divLod1 = pow(2.0, lod1); - float lodLerp = frac(lod); - float footprintAreaLOD0 = exp2(2.0 * lod0); - float footprintAreaLOD1 = exp2(2.0 * lod1); - - // MANUAL ANISOTROPY RATIO COMPENSATION - float ratio0 = max(pow(2.0, (int)log2(ellipseRatio)), 1.0); - float ratio1 = ratio0 * 2.0; - float ratioLerp = saturate(Remap(ellipseRatio, ratio0, ratio1, 0.0, 1.0)); - - // MANUAL ANISOTROPY ROTATION COMPENSATION - float2 v1 = float2(0.0, 1.0); - float2 v2 = normalize(ellipseMajor); - float theta = atan2(v1.x * v2.y - v1.y * v2.x, v1.x * v2.x + v1.y * v2.y); - float thetaGrid = Math::HALF_PI / max(ratio0, 2.0); - float thetaBin = (int)(theta / thetaGrid) * thetaGrid; - thetaBin = thetaBin + (thetaGrid / 2.0); - float thetaBin0 = theta < thetaBin ? thetaBin - thetaGrid / 2.0 : thetaBin; - float thetaBinH = thetaBin0 + thetaGrid / 4.0; - float thetaBin1 = thetaBin0 + thetaGrid / 2.0; - float thetaBinLerp = Remap(theta, thetaBin0, thetaBin1, 0.0, 1.0); - thetaBin0 = thetaBin0 <= 0.0 ? Math::PI + thetaBin0 : thetaBin0; - - // TETRAHEDRONIZATION OF ROTATION + RATIO + LOD GRID - bool centerSpecialCase = (ratio0.x == 1.0); - float2 divLods = float2(divLod0, divLod1); - float2 footprintAreas = float2(footprintAreaLOD0, footprintAreaLOD1); - float2 ratios = float2(ratio0, ratio1); - float4 thetaBins = float4(thetaBin0, thetaBinH, thetaBin1, 0.0); // added 0.0 for center singularity case - float3 tetraA, tetraB, tetraC, tetraD; - GetAnisoCorrectingGridTetrahedron(centerSpecialCase, thetaBinLerp, ratioLerp, lodLerp, tetraA, tetraB, tetraC, tetraD); - if (centerSpecialCase == true) // Account for center singularity in barycentric computation - thetaBinLerp = Remap01To(thetaBinLerp, 0.0, ratioLerp); - float4 tetraBarycentricWeights = GetBarycentricWeightsTetrahedron(float3(thetaBinLerp, ratioLerp, lodLerp), tetraA, tetraB, tetraC, tetraD); // Compute barycentric coordinates within chosen tetrahedron - - // PREPARE NEEDED ROTATIONS - tetraA.x *= 2; - tetraB.x *= 2; - tetraC.x *= 2; - tetraD.x *= 2; - if (centerSpecialCase == true) // Account for center singularity (if center vertex => no rotation) + float4 SampleGlints2023NDF(float logDensity, float roughness, float densityRandomization, GlintCachedVars vars[4], float3 H, float targetNDF, float maxNDF) { - tetraA.x = (tetraA.y == 0) ? 3 : tetraA.x; - tetraB.x = (tetraB.y == 0) ? 3 : tetraB.x; - tetraC.x = (tetraC.y == 0) ? 3 : tetraC.x; - tetraD.x = (tetraD.y == 0) ? 3 : tetraD.x; + float2 slope = H.xy; // Orthogrtaphic slope projected grid + float rescaledTargetNDF = targetNDF / maxNDF; + + float sampleA = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[0], slope, rescaledTargetNDF); + float sampleB = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[1], slope, rescaledTargetNDF); + float sampleC = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[2], slope, rescaledTargetNDF); + float sampleD = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[3], slope, rescaledTargetNDF); + return min((sampleA + sampleB + sampleC + sampleD) * (1.0 / roughness), 20) * maxNDF; // somewhat brute force way of prevent glazing angle extremities } - float2 uvRotA = RotateUV(uv, thetaBins[tetraA.x], 0.0.rr); - float2 uvRotB = RotateUV(uv, thetaBins[tetraB.x], 0.0.rr); - float2 uvRotC = RotateUV(uv, thetaBins[tetraC.x], 0.0.rr); - float2 uvRotD = RotateUV(uv, thetaBins[tetraD.x], 0.0.rr); - - // SAMPLE GLINT GRIDS - uint gridSeedA = HashWithoutSine13(float3(log2(divLods[tetraA.z]), fmod(thetaBins[tetraA.x], Math::TAU), ratios[tetraA.y])) * 4294967296.0; - uint gridSeedB = HashWithoutSine13(float3(log2(divLods[tetraB.z]), fmod(thetaBins[tetraB.x], Math::TAU), ratios[tetraB.y])) * 4294967296.0; - uint gridSeedC = HashWithoutSine13(float3(log2(divLods[tetraC.z]), fmod(thetaBins[tetraC.x], Math::TAU), ratios[tetraC.y])) * 4294967296.0; - uint gridSeedD = HashWithoutSine13(float3(log2(divLods[tetraD.z]), fmod(thetaBins[tetraD.x], Math::TAU), ratios[tetraD.y])) * 4294967296.0; - - vars[0].uv = uvRotA / divLods[tetraA.z] / float2(1.0, ratios[tetraA.y]); - vars[0].gridSeed = gridSeedA; - vars[0].footprintArea = ratios[tetraA.y] * footprintAreas[tetraA.z]; - vars[0].gridWeight = tetraBarycentricWeights.x; - vars[1].uv = uvRotB / divLods[tetraB.z] / float2(1.0, ratios[tetraB.y]); - vars[1].gridSeed = gridSeedB; - vars[1].footprintArea = ratios[tetraB.y] * footprintAreas[tetraB.z]; - vars[1].gridWeight = tetraBarycentricWeights.y; - vars[2].uv = uvRotC / divLods[tetraC.z] / float2(1.0, ratios[tetraC.y]); - vars[2].gridSeed = gridSeedC; - vars[2].footprintArea = ratios[tetraC.y] * footprintAreas[tetraC.z]; - vars[2].gridWeight = tetraBarycentricWeights.z; - vars[3].uv = uvRotA / divLods[tetraD.z] / float2(1.0, ratios[tetraD.y]); - vars[3].gridSeed = gridSeedD; - vars[3].footprintArea = ratios[tetraD.y] * footprintAreas[tetraD.z]; - vars[3].gridWeight = tetraBarycentricWeights.w; } - -float4 SampleGlints2023NDF(float logDensity, float roughness, float densityRandomization, GlintCachedVars vars[4], float3 H, float targetNDF, float maxNDF) -{ - float2 slope = H.xy; // Orthogrtaphic slope projected grid - float rescaledTargetNDF = targetNDF / maxNDF; - - float sampleA = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[0], slope, rescaledTargetNDF); - float sampleB = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[1], slope, rescaledTargetNDF); - float sampleC = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[2], slope, rescaledTargetNDF); - float sampleD = SampleGlintGridSimplex(logDensity, roughness, densityRandomization, vars[3], slope, rescaledTargetNDF); - return min((sampleA + sampleB + sampleC + sampleD) * (1.0 / roughness), 20) * maxNDF; // somewhat brute force way of prevent glazing angle extremities -} \ No newline at end of file diff --git a/package/Shaders/Common/LodLandscape.hlsli b/package/Shaders/Common/LodLandscape.hlsli index 570cbdb43..a6e2f7bac 100644 --- a/package/Shaders/Common/LodLandscape.hlsli +++ b/package/Shaders/Common/LodLandscape.hlsli @@ -1,16 +1,24 @@ -float4 AdjustLodLandscapeVertexPositionMS(float4 positionMS, row_major float4x4 world, float4 cellParams) +#ifndef __LOD_LANDSCAPE_DEPENDENCY_HLSL__ +#define __LOD_LANDSCAPE_DEPENDENCY_HLSL__ + +namespace LodLandscape { - float4 positionWS = mul(world, positionMS); - float worldXShift = positionWS.x - cellParams.x; - float worldYShift = positionWS.y - cellParams.y; - if ((abs(worldXShift) < cellParams.z) && (abs(worldYShift) < cellParams.w)) { - positionMS.z -= (230 + positionWS.z / 1e9); + float4 AdjustLodLandscapeVertexPositionMS(float4 positionMS, row_major float4x4 world, float4 cellParams) + { + float4 positionWS = mul(world, positionMS); + float worldXShift = positionWS.x - cellParams.x; + float worldYShift = positionWS.y - cellParams.y; + if ((abs(worldXShift) < cellParams.z) && (abs(worldYShift) < cellParams.w)) { + positionMS.z -= (230 + positionWS.z / 1e9); + } + return positionMS; } - return positionMS; -} -float4 AdjustLodLandscapeVertexPositionCS(float4 positionCS) -{ - positionCS.z += min(1, 1e-4 * max(0, positionCS.z - 70000)) * 0.5; - return positionCS; + float4 AdjustLodLandscapeVertexPositionCS(float4 positionCS) + { + positionCS.z += min(1, 1e-4 * max(0, positionCS.z - 70000)) * 0.5; + return positionCS; + } } + +#endif // __LOD_LANDSCAPE_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/MotionBlur.hlsli b/package/Shaders/Common/MotionBlur.hlsli index a9efde6b5..722b89201 100644 --- a/package/Shaders/Common/MotionBlur.hlsli +++ b/package/Shaders/Common/MotionBlur.hlsli @@ -1,8 +1,18 @@ -float2 GetSSMotionVector(float4 a_wsPosition, float4 a_previousWSPosition, uint a_eyeIndex = 0) +#ifndef __MOTION_BLUR_DEPENDENCY_HLSL__ +#define __MOTION_BLUR_DEPENDENCY_HLSL__ + +#include "Common/FrameBuffer.hlsli" + +namespace MotionBlur { - float4 screenPosition = mul(CameraViewProjUnjittered[a_eyeIndex], a_wsPosition); - float4 previousScreenPosition = mul(CameraPreviousViewProjUnjittered[a_eyeIndex], a_previousWSPosition); - screenPosition.xy = screenPosition.xy / screenPosition.ww; - previousScreenPosition.xy = previousScreenPosition.xy / previousScreenPosition.ww; - return float2(-0.5, 0.5) * (screenPosition.xy - previousScreenPosition.xy); + float2 GetSSMotionVector(float4 a_wsPosition, float4 a_previousWSPosition, uint a_eyeIndex = 0) + { + float4 screenPosition = mul(CameraViewProjUnjittered[a_eyeIndex], a_wsPosition); + float4 previousScreenPosition = mul(CameraPreviousViewProjUnjittered[a_eyeIndex], a_previousWSPosition); + screenPosition.xy = screenPosition.xy / screenPosition.ww; + previousScreenPosition.xy = previousScreenPosition.xy / previousScreenPosition.ww; + return float2(-0.5, 0.5) * (screenPosition.xy - previousScreenPosition.xy); + } } + +#endif // __MOTION_BLUR_DEPENDENCY_HLSL__ diff --git a/package/Shaders/Common/PBR.hlsli b/package/Shaders/Common/PBR.hlsli index a7bc8b15f..341582e1d 100644 --- a/package/Shaders/Common/PBR.hlsli +++ b/package/Shaders/Common/PBR.hlsli @@ -1,3 +1,10 @@ +#ifndef __PBR_DEPENDENCY_HLSL__ +#define __PBR_DEPENDENCY_HLSL__ + +#include "Common/Color.hlsli" +#include "Common/Math.hlsli" +#include "Common/SharedData.hlsli" + namespace PBR { namespace Flags @@ -39,11 +46,13 @@ namespace PBR static const uint LandTile5HasGlint = (1 << 17); } -#include "Common/Math.hlsli" #if defined(GLINT) # include "Common/Glints/Glints2023.hlsli" #else - typedef float GlintCachedVars; + namespace Glints + { + typedef float GlintCachedVars; + } #endif struct SurfaceProperties @@ -65,7 +74,7 @@ namespace PBR float GlintLogMicrofacetDensity; float GlintMicrofacetRoughness; float GlintDensityRandomization; - GlintCachedVars GlintCache[4]; + Glints::GlintCachedVars GlintCache[4]; }; SurfaceProperties InitSurfaceProperties() @@ -182,14 +191,14 @@ namespace PBR #if defined(GLINT) float3 GetSpecularDirectLightMultiplierMicrofacetWithGlint(float roughness, float3 specularColor, float NdotL, float NdotV, float NdotH, float VdotH, float glintH, - float logDensity, float microfacetRoughness, float densityRandomization, GlintCachedVars glintCache[4], + float logDensity, float microfacetRoughness, float densityRandomization, Glints::GlintCachedVars glintCache[4], out float3 F) { float D = GetNormalDistributionFunctionGGX(roughness, NdotH); [branch] if (logDensity > 1.1) { float D_max = GetNormalDistributionFunctionGGX(roughness, 1); - D = SampleGlints2023NDF(logDensity, microfacetRoughness, densityRandomization, glintCache, glintH, D, D_max); + D = Glints::SampleGlints2023NDF(logDensity, microfacetRoughness, densityRandomization, glintCache, glintH, D, D_max); } float G = GetVisibilityFunctionSmithJointApprox(roughness, NdotV, NdotL); F = GetFresnelFactorSchlick(specularColor, VdotH); @@ -618,4 +627,6 @@ namespace PBR return specularLobeWeight * wetnessStrength; } -} \ No newline at end of file +} + +#endif // __PBR_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/Permutation.hlsli b/package/Shaders/Common/Permutation.hlsli index c7473694e..ad1237c6f 100644 --- a/package/Shaders/Common/Permutation.hlsli +++ b/package/Shaders/Common/Permutation.hlsli @@ -1,3 +1,5 @@ +#ifndef __PERMUTATION_DEPENDENCY_HLSL__ +#define __PERMUTATION_DEPENDENCY_HLSL__ namespace LightingTechnique { @@ -61,4 +63,6 @@ cbuffer PerShader : register(b4) uint VertexShaderDescriptor; uint PixelShaderDescriptor; uint ExtraShaderDescriptor; -}; \ No newline at end of file +}; + +#endif // __PERMUTATION_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/Random.hlsli b/package/Shaders/Common/Random.hlsli index 53aa986b6..054d09a2f 100644 --- a/package/Shaders/Common/Random.hlsli +++ b/package/Shaders/Common/Random.hlsli @@ -1,5 +1,5 @@ -#ifndef CS_RANDOM -#define CS_RANDOM +#ifndef __RANDOM_DEPENDENCY_HLSL__ +#define __RANDOM_DEPENDENCY_HLSL__ namespace Random { @@ -252,4 +252,4 @@ namespace Random } -#endif \ No newline at end of file +#endif // __RANDOM_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/ShadowSampling.hlsli b/package/Shaders/Common/ShadowSampling.hlsli index 266e04528..2b425c7aa 100644 --- a/package/Shaders/Common/ShadowSampling.hlsli +++ b/package/Shaders/Common/ShadowSampling.hlsli @@ -1,4 +1,9 @@ +#ifndef __SHADOW_SAMPLING_DEPENDENCY_HLSL__ +#define __SHADOW_SAMPLING_DEPENDENCY_HLSL__ + #include "Common/Math.hlsli" +#include "Common/Random.hlsli" +#include "Common/SharedData.hlsli" Texture2DArray SharedTexShadowMapSampler : register(t25); @@ -21,233 +26,238 @@ struct PerGeometry StructuredBuffer SharedPerShadow : register(t26); -float GetShadowDepth(float3 positionWS, uint eyeIndex) +namespace ShadowSampling { - float4 positionCSShifted = mul(CameraViewProj[eyeIndex], float4(positionWS, 1)); - return positionCSShifted.z / positionCSShifted.w; -} + float GetShadowDepth(float3 positionWS, uint eyeIndex) + { + float4 positionCSShifted = mul(CameraViewProj[eyeIndex], float4(positionWS, 1)); + return positionCSShifted.z / positionCSShifted.w; + } -float Get3DFilteredShadow(float3 positionWS, float3 viewDirection, float2 screenPosition, uint eyeIndex) -{ - PerGeometry sD = SharedPerShadow[0]; + float Get3DFilteredShadow(float3 positionWS, float3 viewDirection, float2 screenPosition, uint eyeIndex) + { + PerGeometry sD = SharedPerShadow[0]; - float fadeFactor = 1.0 - pow(saturate(dot(positionWS, positionWS) / sD.ShadowLightParam.z), 8); - uint sampleCount = ceil(8.0 * (1.0 - saturate(length(positionWS) / sqrt(sD.ShadowLightParam.z)))); + float fadeFactor = 1.0 - pow(saturate(dot(positionWS, positionWS) / sD.ShadowLightParam.z), 8); + uint sampleCount = ceil(8.0 * (1.0 - saturate(length(positionWS) / sqrt(sD.ShadowLightParam.z)))); - if (sampleCount == 0) - return 1.0; + if (sampleCount == 0) + return 1.0; - float rcpSampleCount = rcp(sampleCount); + float rcpSampleCount = rcp((float)sampleCount); - uint3 seed = Random::pcg3d(uint3(screenPosition.xy, screenPosition.x * Math::PI)); + uint3 seed = Random::pcg3d(uint3(screenPosition.xy, screenPosition.x * Math::PI)); - float2 compareValue; - compareValue.x = mul(transpose(sD.ShadowMapProj[eyeIndex][0]), float4(positionWS, 1)).z - 0.01; - compareValue.y = mul(transpose(sD.ShadowMapProj[eyeIndex][1]), float4(positionWS, 1)).z - 0.01; + float2 compareValue; + compareValue.x = mul(transpose(sD.ShadowMapProj[eyeIndex][0]), float4(positionWS, 1)).z - 0.01; + compareValue.y = mul(transpose(sD.ShadowMapProj[eyeIndex][1]), float4(positionWS, 1)).z - 0.01; - float shadow = 0.0; - if (sD.EndSplitDistances.z >= GetShadowDepth(positionWS, eyeIndex)) { - for (uint i = 0; i < sampleCount; i++) { - float3 rnd = Random::R3Modified(i + FrameCount * sampleCount, seed / 4294967295.f); + float shadow = 0.0; + if (sD.EndSplitDistances.z >= GetShadowDepth(positionWS, eyeIndex)) { + for (uint i = 0; i < sampleCount; i++) { + float3 rnd = Random::R3Modified(i + FrameCount * sampleCount, seed / 4294967295.f); - // https://stats.stackexchange.com/questions/8021/how-to-generate-uniformly-distributed-points-in-the-3-d-unit-ball - float phi = rnd.x * Math::TAU; - float cos_theta = rnd.y * 2 - 1; - float sin_theta = sqrt(1 - cos_theta); - float r = rnd.z; - float4 sincos_phi; - sincos(phi, sincos_phi.y, sincos_phi.x); - float3 sampleOffset = viewDirection * (float(i) - float(sampleCount) * 0.5) * 64 * rcpSampleCount; - sampleOffset += float3(r * sin_theta * sincos_phi.x, r * sin_theta * sincos_phi.y, r * cos_theta) * 64; + // https://stats.stackexchange.com/questions/8021/how-to-generate-uniformly-distributed-points-in-the-3-d-unit-ball + float phi = rnd.x * Math::TAU; + float cos_theta = rnd.y * 2 - 1; + float sin_theta = sqrt(1 - cos_theta); + float r = rnd.z; + float4 sincos_phi; + sincos(phi, sincos_phi.y, sincos_phi.x); + float3 sampleOffset = viewDirection * (float(i) - float(sampleCount) * 0.5) * 64 * rcpSampleCount; + sampleOffset += float3(r * sin_theta * sincos_phi.x, r * sin_theta * sincos_phi.y, r * cos_theta) * 64; - uint cascadeIndex = sD.EndSplitDistances.x < GetShadowDepth(positionWS.xyz + viewDirection * (sampleOffset.x + sampleOffset.y), eyeIndex); // Stochastic cascade sampling + uint cascadeIndex = sD.EndSplitDistances.x < GetShadowDepth(positionWS.xyz + viewDirection * (sampleOffset.x + sampleOffset.y), eyeIndex); // Stochastic cascade sampling - float3 positionLS = mul(transpose(sD.ShadowMapProj[eyeIndex][cascadeIndex]), float4(positionWS + sampleOffset, 1)); + float3 positionLS = mul(transpose(sD.ShadowMapProj[eyeIndex][cascadeIndex]), float4(positionWS + sampleOffset, 1)); - float4 depths = SharedTexShadowMapSampler.GatherRed(LinearSampler, float3(saturate(positionLS.xy), cascadeIndex), 0); - shadow += dot(depths > compareValue[cascadeIndex], 0.25); + float4 depths = SharedTexShadowMapSampler.GatherRed(LinearSampler, float3(saturate(positionLS.xy), cascadeIndex), 0); + shadow += dot(depths > compareValue[cascadeIndex], 0.25); + } + } else { + shadow = 1.0; } - } else { - shadow = 1.0; - } - return lerp(1.0, shadow * rcpSampleCount, fadeFactor); -} + return lerp(1.0, shadow * rcpSampleCount, fadeFactor); + } -float Get2DFilteredShadowCascade(float noise, float2x2 rotationMatrix, float sampleOffsetScale, float2 baseUV, float cascadeIndex, float compareValue, uint eyeIndex) -{ - const uint sampleCount = 8; + float Get2DFilteredShadowCascade(float noise, float2x2 rotationMatrix, float sampleOffsetScale, float2 baseUV, float cascadeIndex, float compareValue, uint eyeIndex) + { + const uint sampleCount = 8; - float layerIndexRcp = rcp(1 + cascadeIndex); + float layerIndexRcp = rcp(1 + cascadeIndex); - float visibility = 0; + float visibility = 0; #if defined(WATER) - sampleOffsetScale *= 8; + sampleOffsetScale *= 8; #endif - for (uint sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex) { - float2 sampleOffset = mul(Random::SpiralSampleOffsets8[sampleIndex], rotationMatrix); + for (uint sampleIndex = 0; sampleIndex < sampleCount; ++sampleIndex) { + float2 sampleOffset = mul(Random::SpiralSampleOffsets8[sampleIndex], rotationMatrix); + + float2 sampleUV = layerIndexRcp * sampleOffset * sampleOffsetScale + baseUV; - float2 sampleUV = layerIndexRcp * sampleOffset * sampleOffsetScale + baseUV; + float4 depths = SharedTexShadowMapSampler.GatherRed(LinearSampler, float3(saturate(sampleUV), cascadeIndex), 0); + visibility += dot(depths > compareValue, 0.25); + } - float4 depths = SharedTexShadowMapSampler.GatherRed(LinearSampler, float3(saturate(sampleUV), cascadeIndex), 0); - visibility += dot(depths > compareValue, 0.25); + return visibility * rcp((float)sampleCount); } - return visibility * rcp(sampleCount); -} + float Get2DFilteredShadow(float noise, float2x2 rotationMatrix, float3 positionWS, uint eyeIndex) + { + PerGeometry sD = SharedPerShadow[0]; -float Get2DFilteredShadow(float noise, float2x2 rotationMatrix, float3 positionWS, uint eyeIndex) -{ - PerGeometry sD = SharedPerShadow[0]; + float shadowMapDepth = GetShadowDepth(positionWS, eyeIndex); - float shadowMapDepth = GetShadowDepth(positionWS, eyeIndex); + if (sD.EndSplitDistances.z >= shadowMapDepth) { + float fadeFactor = 1 - pow(saturate(dot(positionWS.xyz, positionWS.xyz) / sD.ShadowLightParam.z), 8); - if (sD.EndSplitDistances.z >= shadowMapDepth) { - float fadeFactor = 1 - pow(saturate(dot(positionWS.xyz, positionWS.xyz) / sD.ShadowLightParam.z), 8); + float4x3 lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][0]; + float cascadeIndex = 0; - float4x3 lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][0]; - float cascadeIndex = 0; + if (sD.EndSplitDistances.x < shadowMapDepth) { + lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][1]; + cascadeIndex = 1; + } - if (sD.EndSplitDistances.x < shadowMapDepth) { - lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][1]; - cascadeIndex = 1; - } + float3 positionLS = mul(transpose(lightProjectionMatrix), float4(positionWS.xyz, 1)).xyz; - float3 positionLS = mul(transpose(lightProjectionMatrix), float4(positionWS.xyz, 1)).xyz; + float shadowVisibility = Get2DFilteredShadowCascade(noise, rotationMatrix, sD.ShadowSampleParam.z, positionLS.xy, cascadeIndex, positionLS.z, eyeIndex); - float shadowVisibility = Get2DFilteredShadowCascade(noise, rotationMatrix, sD.ShadowSampleParam.z, positionLS.xy, cascadeIndex, positionLS.z, eyeIndex); + if (cascadeIndex < 1 && sD.StartSplitDistances.y < shadowMapDepth) { + float3 cascade1PositionLS = mul(transpose(sD.ShadowMapProj[eyeIndex][1]), float4(positionWS.xyz, 1)).xyz; - if (cascadeIndex < 1 && sD.StartSplitDistances.y < shadowMapDepth) { - float3 cascade1PositionLS = mul(transpose(sD.ShadowMapProj[eyeIndex][1]), float4(positionWS.xyz, 1)).xyz; + float cascade1ShadowVisibility = Get2DFilteredShadowCascade(noise, rotationMatrix, sD.ShadowSampleParam.z, cascade1PositionLS.xy, 1, cascade1PositionLS.z, eyeIndex); - float cascade1ShadowVisibility = Get2DFilteredShadowCascade(noise, rotationMatrix, sD.ShadowSampleParam.z, cascade1PositionLS.xy, 1, cascade1PositionLS.z, eyeIndex); + float cascade1BlendFactor = smoothstep(0, 1, (shadowMapDepth - sD.StartSplitDistances.y) / (sD.EndSplitDistances.x - sD.StartSplitDistances.y)); + shadowVisibility = lerp(shadowVisibility, cascade1ShadowVisibility, cascade1BlendFactor); + } - float cascade1BlendFactor = smoothstep(0, 1, (shadowMapDepth - sD.StartSplitDistances.y) / (sD.EndSplitDistances.x - sD.StartSplitDistances.y)); - shadowVisibility = lerp(shadowVisibility, cascade1ShadowVisibility, cascade1BlendFactor); + return lerp(1.0, shadowVisibility, fadeFactor); } - return lerp(1.0, shadowVisibility, fadeFactor); + return 1.0; } - return 1.0; -} - -float GetWorldShadow(float3 positionWS, float depth, float3 offset, uint eyeIndex) -{ - float worldShadow = 1.0; + float GetWorldShadow(float3 positionWS, float depth, float3 offset, uint eyeIndex) + { + float worldShadow = 1.0; #if defined(TERRAIN_SHADOWS) - float terrainShadow = TerrainShadows::GetTerrainShadow(positionWS + offset + CameraPosAdjust[eyeIndex].xyz, LinearSampler); - worldShadow = terrainShadow; - if (worldShadow == 0.0) - return 0.0; + float terrainShadow = TerrainShadows::GetTerrainShadow(positionWS + offset + CameraPosAdjust[eyeIndex].xyz, LinearSampler); + worldShadow = terrainShadow; + if (worldShadow == 0.0) + return 0.0; #endif #if defined(CLOUD_SHADOWS) - worldShadow *= CloudShadows::GetCloudShadowMult(positionWS + offset, LinearSampler); - if (worldShadow == 0.0) - return 0.0; + worldShadow *= CloudShadows::GetCloudShadowMult(positionWS + offset, LinearSampler); + if (worldShadow == 0.0) + return 0.0; #endif - return worldShadow; -} + return worldShadow; + } -float GetVL(float3 startPosWS, float3 endPosWS, float3 normal, float noise, inout float shadow, uint eyeIndex) -{ - float startDepth = length(startPosWS); + float GetVL(float3 startPosWS, float3 endPosWS, float3 normal, float noise, inout float shadow, uint eyeIndex) + { + float startDepth = length(startPosWS); - // Simulate blurring world shadows on the surface - normal *= 8.0; + // Simulate blurring world shadows on the surface + normal *= 8.0; - float worldShadow = GetWorldShadow(startPosWS, startDepth, normal, eyeIndex); + float worldShadow = GetWorldShadow(startPosWS, startDepth, normal, eyeIndex); - shadow = worldShadow; + shadow = worldShadow; - float phase = dot(normalize(startPosWS.xyz), DirLightDirectionShared.xyz) * 0.5 + 0.5; + float phase = dot(normalize(startPosWS.xyz), DirLightDirectionShared.xyz) * 0.5 + 0.5; - worldShadow *= phase; + worldShadow *= phase; - PerGeometry sD = SharedPerShadow[0]; + PerGeometry sD = SharedPerShadow[0]; - float fadeFactor = 1.0 - saturate(length(endPosWS) / 4096.0); - uint sampleCount = ceil(4.0 * fadeFactor); + float fadeFactor = 1.0 - saturate(length(endPosWS) / 4096.0); + uint sampleCount = ceil(4.0 * fadeFactor); - if (sampleCount == 0) - return worldShadow; + if (sampleCount == 0) + return worldShadow; - float2 rotation; - sincos(Math::TAU * noise, rotation.y, rotation.x); - float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); - - float stepSize = rcp(sampleCount); + float2 rotation; + sincos(Math::TAU * noise, rotation.y, rotation.x); + float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); - float3 worldDir = endPosWS - startPosWS; + float stepSize = rcp((float)sampleCount); - // Offset starting position - startPosWS += worldDir * stepSize * noise; + float3 worldDir = endPosWS - startPosWS; - sD.EndSplitDistances.x = SharedData::GetScreenDepth(sD.EndSplitDistances.x); - sD.EndSplitDistances.y = SharedData::GetScreenDepth(sD.EndSplitDistances.y); - sD.StartSplitDistances.y = SharedData::GetScreenDepth(sD.StartSplitDistances.y); + // Offset starting position + startPosWS += worldDir * stepSize * noise; - float vlShadow = 0; + sD.EndSplitDistances.x = SharedData::GetScreenDepth(sD.EndSplitDistances.x); + sD.EndSplitDistances.y = SharedData::GetScreenDepth(sD.EndSplitDistances.y); + sD.StartSplitDistances.y = SharedData::GetScreenDepth(sD.StartSplitDistances.y); - for (uint i = 0; i < sampleCount; i++) { - float3 samplePositionWS = startPosWS + worldDir * saturate(i * stepSize); - float2 sampleOffset = mul(Random::SpiralSampleOffsets8[(float(i * 2) + noise * 8) % 8].xy, rotationMatrix); + float vlShadow = 0; - float cascadeIndex = 0; - float4x3 lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][0]; - float shadowRange = sD.EndSplitDistances.x; + for (uint i = 0; i < sampleCount; i++) { + float3 samplePositionWS = startPosWS + worldDir * saturate(i * stepSize); + float2 sampleOffset = mul(Random::SpiralSampleOffsets8[(float(i * 2) + noise * 8) % 8].xy, rotationMatrix); - if (sD.EndSplitDistances.x < length(samplePositionWS) + 8.0 * dot(sampleOffset, float2(1, 1))) // Stochastic cascade sampling - { - lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][1]; - cascadeIndex = 1; - shadowRange = sD.EndSplitDistances.y - sD.StartSplitDistances.y; - } + float cascadeIndex = 0; + float4x3 lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][0]; + float shadowRange = sD.EndSplitDistances.x; - float3 samplePositionLS = mul(transpose(lightProjectionMatrix), float4(samplePositionWS.xyz, 1)).xyz; + if (sD.EndSplitDistances.x < length(samplePositionWS) + 8.0 * dot(sampleOffset, float2(1, 1))) // Stochastic cascade sampling + { + lightProjectionMatrix = sD.ShadowMapProj[eyeIndex][1]; + cascadeIndex = 1; + shadowRange = sD.EndSplitDistances.y - sD.StartSplitDistances.y; + } - samplePositionLS.xy += 8.0 * sampleOffset * rcp(shadowRange); + float3 samplePositionLS = mul(transpose(lightProjectionMatrix), float4(samplePositionWS.xyz, 1)).xyz; - float4 depths = SharedTexShadowMapSampler.GatherRed(LinearSampler, float3(saturate(samplePositionLS.xy), cascadeIndex), 0); + samplePositionLS.xy += 8.0 * sampleOffset * rcp(shadowRange); - vlShadow += dot(depths > (samplePositionLS.z - 0.0005), 0.25); - } - return lerp(worldShadow, min(worldShadow, vlShadow * stepSize), fadeFactor); -} + float4 depths = SharedTexShadowMapSampler.GatherRed(LinearSampler, float3(saturate(samplePositionLS.xy), cascadeIndex), 0); -float GetEffectShadow(float3 worldPosition, float3 viewDirection, float2 screenPosition, uint eyeIndex) -{ - float worldShadow = GetWorldShadow(worldPosition, length(worldPosition), 0.0, eyeIndex); - if (worldShadow != 0.0) { - float shadow = Get3DFilteredShadow(worldPosition, viewDirection, screenPosition, eyeIndex); - return min(worldShadow, shadow); + vlShadow += dot(depths > (samplePositionLS.z - 0.0005), 0.25); + } + return lerp(worldShadow, min(worldShadow, vlShadow * stepSize), fadeFactor); } - return worldShadow; -} + float GetEffectShadow(float3 worldPosition, float3 viewDirection, float2 screenPosition, uint eyeIndex) + { + float worldShadow = GetWorldShadow(worldPosition, length(worldPosition), 0.0, eyeIndex); + if (worldShadow != 0.0) { + float shadow = Get3DFilteredShadow(worldPosition, viewDirection, screenPosition, eyeIndex); + return min(worldShadow, shadow); + } -float GetLightingShadow(float noise, float3 worldPosition, uint eyeIndex) -{ - float2 rotation; - sincos(Math::TAU * noise, rotation.y, rotation.x); - float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); - return Get2DFilteredShadow(noise, rotationMatrix, worldPosition, eyeIndex); -} + return worldShadow; + } -float GetWaterShadow(float noise, float3 worldPosition, uint eyeIndex) -{ - float worldShadow = GetWorldShadow(worldPosition, length(worldPosition), 0.0, eyeIndex); - if (worldShadow != 0.0) { + float GetLightingShadow(float noise, float3 worldPosition, uint eyeIndex) + { float2 rotation; sincos(Math::TAU * noise, rotation.y, rotation.x); float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); - float shadow = Get2DFilteredShadow(noise, rotationMatrix, worldPosition, eyeIndex); - return shadow; + return Get2DFilteredShadow(noise, rotationMatrix, worldPosition, eyeIndex); } - return worldShadow; -} \ No newline at end of file + float GetWaterShadow(float noise, float3 worldPosition, uint eyeIndex) + { + float worldShadow = GetWorldShadow(worldPosition, length(worldPosition), 0.0, eyeIndex); + if (worldShadow != 0.0) { + float2 rotation; + sincos(Math::TAU * noise, rotation.y, rotation.x); + float2x2 rotationMatrix = float2x2(rotation.x, rotation.y, -rotation.y, rotation.x); + float shadow = Get2DFilteredShadow(noise, rotationMatrix, worldPosition, eyeIndex); + return shadow; + } + + return worldShadow; + } +} + +#endif // __SHADOW_SAMPLING_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/SharedData.hlsli b/package/Shaders/Common/SharedData.hlsli index 7852b293c..fd0f04116 100644 --- a/package/Shaders/Common/SharedData.hlsli +++ b/package/Shaders/Common/SharedData.hlsli @@ -1,5 +1,5 @@ -#ifndef SHARED_DATA -#define SHARED_DATA +#ifndef __SHARED_DATA_DEPENDENCY_HLSL__ +#define __SHARED_DATA_DEPENDENCY_HLSL__ #include "Common/FrameBuffer.hlsli" #include "Common/VR.hlsli" @@ -206,4 +206,4 @@ namespace SharedData #endif // PSHADER -#endif // SHARED_DATA \ No newline at end of file +#endif // __SHARED_DATA_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/Skinned.hlsli b/package/Shaders/Common/Skinned.hlsli index 80bc9ab29..47da64bc7 100644 --- a/package/Shaders/Common/Skinned.hlsli +++ b/package/Shaders/Common/Skinned.hlsli @@ -1,3 +1,6 @@ +#ifndef __SKINNED_DEPENDENCY_HLSL__ +#define __SKINNED_DEPENDENCY_HLSL__ + cbuffer PreviousBonesBuffer : register(b9) { float4 PreviousBones[240] : packoffset(c0); @@ -8,39 +11,44 @@ cbuffer BonesBuffer : register(b10) float4 Bones[240] : packoffset(c0); } -float3x4 GetBoneTransformMatrix(float4 bonePositions[240], int4 boneIndices, float3 pivot, float4 boneWeights) +namespace Skinned { - float3x4 pivotMatrix = transpose(float4x3(0.0.xxx, 0.0.xxx, 0.0.xxx, pivot)); - - float3x4 boneMatrix1 = - float3x4(bonePositions[boneIndices.x], bonePositions[boneIndices.x + 1], bonePositions[boneIndices.x + 2]); - float3x4 boneMatrix2 = - float3x4(bonePositions[boneIndices.y], bonePositions[boneIndices.y + 1], bonePositions[boneIndices.y + 2]); - float3x4 boneMatrix3 = - float3x4(bonePositions[boneIndices.z], bonePositions[boneIndices.z + 1], bonePositions[boneIndices.z + 2]); - float3x4 boneMatrix4 = - float3x4(bonePositions[boneIndices.w], bonePositions[boneIndices.w + 1], bonePositions[boneIndices.w + 2]); - - float3x4 unitMatrix = float3x4(1.0.xxxx, 1.0.xxxx, 1.0.xxxx); - float3x4 weightMatrix1 = unitMatrix * boneWeights.x; - float3x4 weightMatrix2 = unitMatrix * boneWeights.y; - float3x4 weightMatrix3 = unitMatrix * boneWeights.z; - float3x4 weightMatrix4 = unitMatrix * boneWeights.w; - - return (boneMatrix1 - pivotMatrix) * weightMatrix1 + - (boneMatrix2 - pivotMatrix) * weightMatrix2 + - (boneMatrix3 - pivotMatrix) * weightMatrix3 + - (boneMatrix4 - pivotMatrix) * weightMatrix4; -} + float3x4 GetBoneTransformMatrix(float4 bonePositions[240], int4 boneIndices, float3 pivot, float4 boneWeights) + { + float3x4 pivotMatrix = transpose(float4x3(0.0.xxx, 0.0.xxx, 0.0.xxx, pivot)); -float3x3 GetBoneRSMatrix(float4 bonePositions[240], int4 boneIndices, float4 boneWeights) -{ - float3x3 result; - for (int rowIndex = 0; rowIndex < 3; ++rowIndex) { - result[rowIndex] = boneWeights.xxx * bonePositions[boneIndices.x + rowIndex].xyz + - boneWeights.yyy * bonePositions[boneIndices.y + rowIndex].xyz + - boneWeights.zzz * bonePositions[boneIndices.z + rowIndex].xyz + - boneWeights.www * bonePositions[boneIndices.w + rowIndex].xyz; + float3x4 boneMatrix1 = + float3x4(bonePositions[boneIndices.x], bonePositions[boneIndices.x + 1], bonePositions[boneIndices.x + 2]); + float3x4 boneMatrix2 = + float3x4(bonePositions[boneIndices.y], bonePositions[boneIndices.y + 1], bonePositions[boneIndices.y + 2]); + float3x4 boneMatrix3 = + float3x4(bonePositions[boneIndices.z], bonePositions[boneIndices.z + 1], bonePositions[boneIndices.z + 2]); + float3x4 boneMatrix4 = + float3x4(bonePositions[boneIndices.w], bonePositions[boneIndices.w + 1], bonePositions[boneIndices.w + 2]); + + float3x4 unitMatrix = float3x4(1.0.xxxx, 1.0.xxxx, 1.0.xxxx); + float3x4 weightMatrix1 = unitMatrix * boneWeights.x; + float3x4 weightMatrix2 = unitMatrix * boneWeights.y; + float3x4 weightMatrix3 = unitMatrix * boneWeights.z; + float3x4 weightMatrix4 = unitMatrix * boneWeights.w; + + return (boneMatrix1 - pivotMatrix) * weightMatrix1 + + (boneMatrix2 - pivotMatrix) * weightMatrix2 + + (boneMatrix3 - pivotMatrix) * weightMatrix3 + + (boneMatrix4 - pivotMatrix) * weightMatrix4; + } + + float3x3 GetBoneRSMatrix(float4 bonePositions[240], int4 boneIndices, float4 boneWeights) + { + float3x3 result; + for (int rowIndex = 0; rowIndex < 3; ++rowIndex) { + result[rowIndex] = boneWeights.xxx * bonePositions[boneIndices.x + rowIndex].xyz + + boneWeights.yyy * bonePositions[boneIndices.y + rowIndex].xyz + + boneWeights.zzz * bonePositions[boneIndices.z + rowIndex].xyz + + boneWeights.www * bonePositions[boneIndices.w + rowIndex].xyz; + } + return result; } - return result; } + +#endif // __SKINNED_DEPENDENCY_HLSL__ \ No newline at end of file diff --git a/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli b/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli index 35693da4b..c9d1b4f45 100644 --- a/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli +++ b/package/Shaders/Common/Spherical Harmonics/SphericalHarmonics.hlsli @@ -1,4 +1,3 @@ - // SphericalHarmonics.hlsl from https://github.com/sebh/HLSL-Spherical-Harmonics // Great documents about spherical harmonics: @@ -55,148 +54,151 @@ // float3 rgbColor = max(0.0f, shUnproject(shR, shG, shB, rayDir)); // A "max" is usually recomended to avoid negative values (can happen with SH) // -#ifndef SPHERICAL_HARMONICS_HLSL -#define SPHERICAL_HARMONICS_HLSL +#ifndef __SPHERICAL_HARMONICS_DEPENDENCY_HLSL__ +#define __SPHERICAL_HARMONICS_DEPENDENCY_HLSL__ #include "Common/Math.hlsli" -// Generates a uniform distribution of directions over a unit sphere. -// Adapted from http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#fragment-SamplingFunctionDefinitions-6 -// azimuthX and zenithY are both in [0, 1]. You can use random value, stratified, etc. -// Top and bottom sphere pole (+-zenith) are along the Y axis. -float3 shGetUniformSphereSample(float azimuthX, float zenithY) -{ - float phi = 2.0f * Math::PI * azimuthX; - float z = 1.0f - 2.0f * zenithY; - float r = sqrt(max(0.0f, 1.0f - z * z)); - return float3(r * cos(phi), z, r * sin(phi)); -} - #define sh2 float4 // TODO sh3 -sh2 shZero() -{ - return float4(0.0f, 0.0f, 0.0f, 0.0f); -} - -// Evaluates spherical harmonics basis for a direction dir. -// This follows [2] Appendix A2 order when storing in x, y, z and w. -// (evaluating the associated Legendre polynomials using the polynomial forms) -sh2 shEvaluate(float3 dir) -{ - sh2 result; - result.x = 0.28209479177387814347403972578039f; // L=0 , M= 0 - result.y = -0.48860251190291992158638462283836f * dir.y; // L=1 , M=-1 - result.z = 0.48860251190291992158638462283836f * dir.z; // L=1 , M= 0 - result.w = -0.48860251190291992158638462283836f * dir.x; // L=1 , M= 1 - return result; -} - -// Recovers the value of a SH function in the direction dir. -float shUnproject(sh2 functionSh, float3 dir) -{ - sh2 sh = shEvaluate(dir); - return dot(functionSh, sh); -} - -float3 shUnproject(sh2 functionShX, sh2 functionShY, sh2 functionShZ, float3 dir) -{ - sh2 sh = shEvaluate(dir); - return float3(dot(functionShX, sh), dot(functionShY, sh), dot(functionShZ, sh)); -} - -// Projects a cosine lobe function, with peak value in direction dir, into SH. (from [4]) -// The integral over the unit sphere of the SH representation is PI. -sh2 shEvaluateCosineLobe(float3 dir) -{ - sh2 result; - result.x = 0.8862269254527580137f; // L=0 , M= 0 - result.y = -1.0233267079464884885f * dir.y; // L=1 , M=-1 - result.z = 1.0233267079464884885f * dir.z; // L=1 , M= 0 - result.w = -1.0233267079464884885f * dir.x; // L=1 , M= 1 - return result; -} - -// Projects a Henyey-Greenstein phase function, with peak value in direction dir, into SH. (from [11]) -// The integral over the unit sphere of the SH representation is 1. -sh2 shEvaluatePhaseHG(float3 dir, float g) -{ - sh2 result; - const float factor = 0.48860251190291992158638462283836 * g; - result.x = 0.28209479177387814347403972578039; // L=0 , M= 0 - result.y = -factor * dir.y; // L=1 , M=-1 - result.z = factor * dir.z; // L=1 , M= 0 - result.w = -factor * dir.x; // L=1 , M= 1 - return result; -} - -// Adds two SH functions together. -sh2 shAdd(sh2 shL, sh2 shR) -{ - return shL + shR; -} - -// Scales a SH function uniformly by v. -sh2 shScale(sh2 sh, float v) -{ - return sh * v; -} - -// Operates a rotation of a SH function. -sh2 shRotate(sh2 sh, float3x3 rotation) -{ - // TODO verify and optimize - sh2 result; - result.x = sh.x; - float3 tmp = float3(sh.w, sh.y, sh.z); // undo direction component shuffle to match source/function space - result.yzw = mul(tmp, rotation).yzx; // apply rotation and re-shuffle - return result; -} - -// Integrates the product of two SH functions over the unit sphere. -float shFuncProductIntegral(sh2 shL, sh2 shR) -{ - return dot(shL, shR); -} - -// Computes the SH coefficients of a SH function representing the result of the multiplication of two SH functions. (from [4]) -// If sources have N bands, this product will result in 2N*1 bands as signal multiplication can add frequencies (think about two lobes intersecting). -// To avoid that, the result can be truncated to N bands. It will just have a lower frequency, i.e. less details. (from [2], SH Products p.7) -// Note: - the code from [4] has been adapted to match the mapping from [2] we use. -// - !!! Be aware that this code has note yet be tested !!! -sh2 shProduct(sh2 shL, sh2 shR) -{ - const float factor = 1.0f / (2.0f * sqrt(Math::PI)); - return factor * sh2( - dot(shL, shR), - shL.y * shR.w + shL.w * shR.y, - shL.z * shR.w + shL.w * shR.z, - shL.w * shR.w + shL.w * shR.w); -} - -// Convolves a SH function using a Hanning filtering. This helps reducing ringing and negative values. (from [2], Windowing p.16) -// A lower value of w will reduce ringing (like the frequency of a filter) -sh2 shHanningConvolution(sh2 sh, float w) -{ - sh2 result = sh; - float invW = 1.0 / w; - float factorBand1 = (1.0 + cos(Math::PI * invW)) / 2.0f; - result.y *= factorBand1; - result.z *= factorBand1; - result.w *= factorBand1; - return result; -} - -// Convolves a SH function using a cosine lob. This is tipically used to transform radiance to irradiance. (from [3], eq.7 & eq.8) -sh2 shDiffuseConvolution(sh2 sh) +namespace SphericalHarmonics { - sh2 result = sh; - // L0 - result.x *= Math::PI; - // L1 - result.yzw *= 2.0943951023931954923f; - return result; + // Generates a uniform distribution of directions over a unit sphere. + // Adapted from http://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations.html#fragment-SamplingFunctionDefinitions-6 + // azimuthX and zenithY are both in [0, 1]. You can use random value, stratified, etc. + // Top and bottom sphere pole (+-zenith) are along the Y axis. + float3 GetUniformSphereSample(float azimuthX, float zenithY) + { + float phi = 2.0f * Math::PI * azimuthX; + float z = 1.0f - 2.0f * zenithY; + float r = sqrt(max(0.0f, 1.0f - z * z)); + return float3(r * cos(phi), z, r * sin(phi)); + } + + sh2 Zero() + { + return float4(0.0f, 0.0f, 0.0f, 0.0f); + } + + // Evaluates spherical harmonics basis for a direction dir. + // This follows [2] Appendix A2 order when storing in x, y, z and w. + // (evaluating the associated Legendre polynomials using the polynomial forms) + sh2 Evaluate(float3 dir) + { + sh2 result; + result.x = 0.28209479177387814347403972578039f; // L=0 , M= 0 + result.y = -0.48860251190291992158638462283836f * dir.y; // L=1 , M=-1 + result.z = 0.48860251190291992158638462283836f * dir.z; // L=1 , M= 0 + result.w = -0.48860251190291992158638462283836f * dir.x; // L=1 , M= 1 + return result; + } + + // Recovers the value of a SH function in the direction dir. + float Unproject(sh2 functionSh, float3 dir) + { + sh2 sh = Evaluate(dir); + return dot(functionSh, sh); + } + + float3 Unproject(sh2 functionShX, sh2 functionShY, sh2 functionShZ, float3 dir) + { + sh2 sh = Evaluate(dir); + return float3(dot(functionShX, sh), dot(functionShY, sh), dot(functionShZ, sh)); + } + + // Projects a cosine lobe function, with peak value in direction dir, into SH. (from [4]) + // The integral over the unit sphere of the SH representation is PI. + sh2 EvaluateCosineLobe(float3 dir) + { + sh2 result; + result.x = 0.8862269254527580137f; // L=0 , M= 0 + result.y = -1.0233267079464884885f * dir.y; // L=1 , M=-1 + result.z = 1.0233267079464884885f * dir.z; // L=1 , M= 0 + result.w = -1.0233267079464884885f * dir.x; // L=1 , M= 1 + return result; + } + + // Projects a Henyey-Greenstein phase function, with peak value in direction dir, into SH. (from [11]) + // The integral over the unit sphere of the SH representation is 1. + sh2 EvaluatePhaseHG(float3 dir, float g) + { + sh2 result; + const float factor = 0.48860251190291992158638462283836 * g; + result.x = 0.28209479177387814347403972578039; // L=0 , M= 0 + result.y = -factor * dir.y; // L=1 , M=-1 + result.z = factor * dir.z; // L=1 , M= 0 + result.w = -factor * dir.x; // L=1 , M= 1 + return result; + } + + // Adds two SH functions together. + sh2 Add(sh2 shL, sh2 shR) + { + return shL + shR; + } + + // Scales a SH function uniformly by v. + sh2 Scale(sh2 sh, float v) + { + return sh * v; + } + + // Operates a rotation of a SH function. + sh2 Rotate(sh2 sh, float3x3 rotation) + { + // TODO verify and optimize + sh2 result; + result.x = sh.x; + float3 tmp = float3(sh.w, sh.y, sh.z); // undo direction component shuffle to match source/function space + result.yzw = mul(tmp, rotation).yzx; // apply rotation and re-shuffle + return result; + } + + // Integrates the product of two SH functions over the unit sphere. + float FuncProductIntegral(sh2 shL, sh2 shR) + { + return dot(shL, shR); + } + + // Computes the SH coefficients of a SH function representing the result of the multiplication of two SH functions. (from [4]) + // If sources have N bands, this product will result in 2N*1 bands as signal multiplication can add frequencies (think about two lobes intersecting). + // To avoid that, the result can be truncated to N bands. It will just have a lower frequency, i.e. less details. (from [2], SH Products p.7) + // Note: - the code from [4] has been adapted to match the mapping from [2] we use. + // - !!! Be aware that this code has note yet be tested !!! + sh2 Product(sh2 shL, sh2 shR) + { + const float factor = 1.0f / (2.0f * sqrt(Math::PI)); + return factor * sh2( + dot(shL, shR), + shL.y * shR.w + shL.w * shR.y, + shL.z * shR.w + shL.w * shR.z, + shL.w * shR.w + shL.w * shR.w); + } + + // Convolves a SH function using a Hanning filtering. This helps reducing ringing and negative values. (from [2], Windowing p.16) + // A lower value of w will reduce ringing (like the frequency of a filter) + sh2 HanningConvolution(sh2 sh, float w) + { + sh2 result = sh; + float invW = 1.0 / w; + float factorBand1 = (1.0 + cos(Math::PI * invW)) / 2.0f; + result.y *= factorBand1; + result.z *= factorBand1; + result.w *= factorBand1; + return result; + } + + // Convolves a SH function using a cosine lob. This is tipically used to transform radiance to irradiance. (from [3], eq.7 & eq.8) + sh2 DiffuseConvolution(sh2 sh) + { + sh2 result = sh; + // L0 + result.x *= Math::PI; + // L1 + result.yzw *= 2.0943951023931954923f; + return result; + } } -#endif // SPHERICAL_HARMONICS_HLSL +#endif // __SPHERICAL_HARMONICS_DEPENDENCY_HLSL__ diff --git a/package/Shaders/DeferredCompositeCS.hlsl b/package/Shaders/DeferredCompositeCS.hlsl index a117451bb..44de84215 100644 --- a/package/Shaders/DeferredCompositeCS.hlsl +++ b/package/Shaders/DeferredCompositeCS.hlsl @@ -60,7 +60,7 @@ Texture2D SpecularSSGITexture : register(t10); positionWS.xyz = positionWS.xyz / positionWS.w; if (depth == 1.0) { - MotionVectorsRW[dispatchID.xy] = GetSSMotionVector(positionWS, positionWS, eyeIndex); // Apply sky motion vectors + MotionVectorsRW[dispatchID.xy] = MotionBlur::GetSSMotionVector(positionWS, positionWS, eyeIndex); // Apply sky motion vectors } half pbrWeight = masks2.z; @@ -105,7 +105,7 @@ Texture2D SpecularSSGITexture : register(t10); sh2 skylighting = Skylighting::sample(skylightingSettings, SkylightingProbeArray, positionMS.xyz, normalWS); sh2 specularLobe = Skylighting::fauxSpecularLobeSH(normalWS, -V, roughness); - half skylightingSpecular = shFuncProductIntegral(skylighting, specularLobe); + half skylightingSpecular = SphericalHarmonics::FuncProductIntegral(skylighting, specularLobe); skylightingSpecular = Skylighting::mixSpecular(skylightingSettings, skylightingSpecular); half3 specularIrradiance = 1; diff --git a/package/Shaders/DistantTree.hlsl b/package/Shaders/DistantTree.hlsl index a3557177f..5ba05c284 100644 --- a/package/Shaders/DistantTree.hlsl +++ b/package/Shaders/DistantTree.hlsl @@ -244,7 +244,7 @@ PS_OUTPUT main(PS_INPUT input) psout.Diffuse.xyz = diffuseColor * baseColor.xyz; psout.Diffuse.w = 1; - psout.MotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); + psout.MotionVector = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); psout.Normal.xy = GBuffer::EncodeNormal(FrameBuffer::WorldToView(normal, false, eyeIndex)); psout.Normal.zw = 0; diff --git a/package/Shaders/Effect.hlsl b/package/Shaders/Effect.hlsl index 5af223230..a004ba0c0 100644 --- a/package/Shaders/Effect.hlsl +++ b/package/Shaders/Effect.hlsl @@ -216,12 +216,12 @@ VS_OUTPUT main(VS_INPUT input) precise int4 actualIndices = 765.01.xxxx * input.BoneIndices.xyzw; # if defined(MOTIONVECTORS_NORMALS) float3x4 previousBoneTransformMatrix = - GetBoneTransformMatrix(PreviousBones, actualIndices, PreviousBonesPivot[eyeIndex], input.BoneWeights); + Skinned::GetBoneTransformMatrix(PreviousBones, actualIndices, PreviousBonesPivot[eyeIndex], input.BoneWeights); precise float4 previousWorldPosition = float4(mul(inputPosition, transpose(previousBoneTransformMatrix)), 1); # endif float3x4 boneTransformMatrix = - GetBoneTransformMatrix(Bones, actualIndices, BonesPivot[eyeIndex], input.BoneWeights); + Skinned::GetBoneTransformMatrix(Bones, actualIndices, BonesPivot[eyeIndex], input.BoneWeights); precise float4 worldPosition = float4(mul(inputPosition, transpose(boneTransformMatrix)), 1); float4 viewPos = mul(viewProj, worldPosition); # else @@ -234,7 +234,7 @@ VS_OUTPUT main(VS_INPUT input) vsout.Position = viewPos; # if defined(SKINNED) - float3x3 boneRSMatrix = GetBoneRSMatrix(Bones, actualIndices, input.BoneWeights); + float3x3 boneRSMatrix = Skinned::GetBoneRSMatrix(Bones, actualIndices, input.BoneWeights); float3x3 boneRSMatrixTr = transpose(boneRSMatrix); # endif @@ -529,7 +529,7 @@ float3 GetLightingColor(float3 msPosition, float3 worldPosition, float4 screenPo float3 ambientColor = mul(DirectionalAmbientShared, float4(0, 0, 1, 1)); color = ambientColor; - color += dirLightColor * GetEffectShadow(worldPosition, normalize(worldPosition), screenPosition, eyeIndex); + color += dirLightColor * ShadowSampling::GetEffectShadow(worldPosition, normalize(worldPosition), screenPosition, eyeIndex); } # if !defined(LIGHT_LIMIT_FIX) @@ -756,7 +756,7 @@ PS_OUTPUT main(PS_INPUT input) float3 screenSpaceNormal = normalize(input.ScreenSpaceNormal); # endif psout.NormalGlossiness = float4(GBuffer::EncodeNormal(screenSpaceNormal), 0.0, psout.Diffuse.w); - float2 screenMotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); + float2 screenMotionVector = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); psout.MotionVectors = float4(screenMotionVector, 0.0, psout.Diffuse.w); # endif @@ -765,7 +765,7 @@ PS_OUTPUT main(PS_INPUT input) psout.Reflectance = float4(0.0.xxx, psout.Diffuse.w); # elif defined(MOTIONVECTORS_NORMALS) - float2 screenMotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); + float2 screenMotionVector = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); psout.MotionVectors = screenMotionVector; # if (defined(MEMBRANE) && defined(SKINNED) && defined(NORMALS)) diff --git a/package/Shaders/Lighting.hlsl b/package/Shaders/Lighting.hlsl index ba5fe5ed4..6ba0bf442 100644 --- a/package/Shaders/Lighting.hlsl +++ b/package/Shaders/Lighting.hlsl @@ -194,7 +194,7 @@ VS_OUTPUT main(VS_INPUT input) # endif ); # if defined(LODLANDNOISE) || defined(LODLANDSCAPE) - inputPosition = AdjustLodLandscapeVertexPositionMS(inputPosition, float4x4(World[eyeIndex], float4(0, 0, 0, 1)), HighDetailRange[eyeIndex]); + inputPosition = LodLandscape::AdjustLodLandscapeVertexPositionMS(inputPosition, float4x4(World[eyeIndex], float4(0, 0, 0, 1)), HighDetailRange[eyeIndex]); # endif // defined(LODLANDNOISE) || defined(LODLANDSCAPE) \ precise float4 previousInputPosition = inputPosition; @@ -211,11 +211,11 @@ VS_OUTPUT main(VS_INPUT input) precise int4 actualIndices = 765.01.xxxx * input.BoneIndices.xyzw; float3x4 previousWorldMatrix = - GetBoneTransformMatrix(PreviousBones, actualIndices, PreviousBonesPivot[eyeIndex], input.BoneWeights); + Skinned::GetBoneTransformMatrix(PreviousBones, actualIndices, PreviousBonesPivot[eyeIndex], input.BoneWeights); precise float4 previousWorldPosition = float4(mul(inputPosition, transpose(previousWorldMatrix)), 1); - float3x4 worldMatrix = GetBoneTransformMatrix(Bones, actualIndices, BonesPivot[eyeIndex], input.BoneWeights); + float3x4 worldMatrix = Skinned::GetBoneTransformMatrix(Bones, actualIndices, BonesPivot[eyeIndex], input.BoneWeights); precise float4 worldPosition = float4(mul(inputPosition, transpose(worldMatrix)), 1); float4 viewPos = mul(ViewProj[eyeIndex], worldPosition); @@ -251,7 +251,7 @@ VS_OUTPUT main(VS_INPUT input) # endif # if defined(SKINNED) - float3x3 boneRSMatrix = GetBoneRSMatrix(Bones, actualIndices, input.BoneWeights); + float3x3 boneRSMatrix = Skinned::GetBoneRSMatrix(Bones, actualIndices, input.BoneWeights); # endif # if !defined(MODELSPACENORMALS) @@ -1646,7 +1646,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace pbrSurfaceProperties.GlintDensityRandomization = clamp(glintParameters.w, 0, 5); # if defined(GLINT) - PBR::PrecomputeGlints(uvOriginal, ddx(uvOriginal), ddy(uvOriginal), pbrSurfaceProperties.GlintScreenSpaceScale, pbrSurfaceProperties.GlintCache); + PBR::Glints::PrecomputeGlints(uvOriginal, ddx(uvOriginal), ddy(uvOriginal), pbrSurfaceProperties.GlintScreenSpaceScale, pbrSurfaceProperties.GlintCache); # endif baseColor.xyz *= 1 - pbrSurfaceProperties.Metallic; @@ -1777,7 +1777,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float minWetnessAngle = 0; minWetnessAngle = saturate(max(minWetnessValue, worldSpaceNormal.z)); # if defined(SKYLIGHTING) - float wetnessOcclusion = inWorld ? pow(saturate(shUnproject(skylightingSH, float3(0, 0, 1))), 2) : 0; + float wetnessOcclusion = inWorld ? pow(saturate(SphericalHarmonics::Unproject(skylightingSH, float3(0, 0, 1))), 2) : 0; # else float wetnessOcclusion = inWorld; # endif @@ -1869,7 +1869,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace } # if !defined(DEFERRED) else if (!InInterior && inWorld) { - dirLightColorMultiplier *= GetLightingShadow(screenNoise, input.WorldPosition.xyz, eyeIndex); + dirLightColorMultiplier *= ShadowSampling::GetLightingShadow(screenNoise, input.WorldPosition.xyz, eyeIndex); } # endif @@ -2279,7 +2279,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace float3 reflectionDiffuseColor = diffuseColor + directionalAmbientColor; # if defined(SKYLIGHTING) - float skylightingDiffuse = shFuncProductIntegral(skylightingSH, shEvaluateCosineLobe(float3(worldSpaceNormal.xy, worldSpaceNormal.z * 0.5 + 0.5))) / Math::PI; + float skylightingDiffuse = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(worldSpaceNormal.xy, worldSpaceNormal.z * 0.5 + 0.5))) / Math::PI; skylightingDiffuse = lerp(1.0, skylightingDiffuse, Skylighting::getFadeOutFactor(input.WorldPosition.xyz)); skylightingDiffuse = Skylighting::mixDiffuse(skylightingSettings, skylightingDiffuse); # if !defined(TRUE_PBR) @@ -2348,7 +2348,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif # endif // defined (ENVMAP) || defined (MULTI_LAYER_PARALLAX) || defined(EYE) - float2 screenMotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); + float2 screenMotionVector = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); # if defined(WETNESS_EFFECTS) # if !(defined(FACEGEN) || defined(FACEGEN_RGB_TINT) || defined(EYE)) || defined(TREE_ANIM) diff --git a/package/Shaders/RunGrass.hlsl b/package/Shaders/RunGrass.hlsl index c79da0b97..82a468121 100644 --- a/package/Shaders/RunGrass.hlsl +++ b/package/Shaders/RunGrass.hlsl @@ -460,7 +460,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif uint eyeIndex = Stereo::GetEyeIndexPS(input.HPosition, VPOSOffset); - psout.MotionVectors = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); + psout.MotionVectors = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); float3 viewDirection = -normalize(input.WorldPosition.xyz); float3 normal = normalize(input.VertexNormal.xyz); @@ -673,7 +673,7 @@ PS_OUTPUT main(PS_INPUT input, bool frontFace # endif sh2 skylightingSH = Skylighting::sample(skylightingSettings, SkylightingProbeArray, positionMSSkylight, normal); - float skylighting = shFuncProductIntegral(skylightingSH, shEvaluateCosineLobe(float3(normal.xy, normal.z * 0.5 + 0.5))) / Math::PI; + float skylighting = SphericalHarmonics::FuncProductIntegral(skylightingSH, SphericalHarmonics::EvaluateCosineLobe(float3(normal.xy, normal.z * 0.5 + 0.5))) / Math::PI; skylighting = lerp(1.0, skylighting, Skylighting::getFadeOutFactor(input.WorldPosition)); skylighting = Skylighting::mixDiffuse(skylightingSettings, skylighting); diff --git a/package/Shaders/Sky.hlsl b/package/Shaders/Sky.hlsl index f49474b01..426ea7f69 100644 --- a/package/Shaders/Sky.hlsl +++ b/package/Shaders/Sky.hlsl @@ -240,7 +240,7 @@ PS_OUTPUT main(PS_INPUT input) psout.Color = float4(0, 0, 0, 1.0); # endif // OCCLUSION - float2 screenMotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); + float2 screenMotionVector = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition, eyeIndex); psout.MotionVectors = float4(screenMotionVector, 0, psout.Color.w); psout.Normal = float4(0.5, 0.5, 0, psout.Color.w); diff --git a/package/Shaders/Utility.hlsl b/package/Shaders/Utility.hlsl index 72240ef11..ff75d34ee 100644 --- a/package/Shaders/Utility.hlsl +++ b/package/Shaders/Utility.hlsl @@ -157,13 +157,13 @@ VS_OUTPUT main(VS_INPUT input) # endif # if defined(LOD_LANDSCAPE) - positionMS = AdjustLodLandscapeVertexPositionMS(positionMS, World[eyeIndex], HighDetailRange[eyeIndex]); + positionMS = LodLandscape::AdjustLodLandscapeVertexPositionMS(positionMS, World[eyeIndex], HighDetailRange[eyeIndex]); # endif # if defined(SKINNED) precise int4 boneIndices = 765.01.xxxx * input.BoneIndices.xyzw; - float3x4 worldMatrix = GetBoneTransformMatrix(Bones, boneIndices, CameraPosAdjust[eyeIndex].xyz, input.BoneWeights); + float3x4 worldMatrix = Skinned::GetBoneTransformMatrix(Bones, boneIndices, CameraPosAdjust[eyeIndex].xyz, input.BoneWeights); precise float4 positionWS = float4(mul(positionMS, transpose(worldMatrix)), 1); positionCS = mul(CameraViewProj[eyeIndex], positionWS); @@ -177,7 +177,7 @@ VS_OUTPUT main(VS_INPUT input) # endif # if defined(LOD_LANDSCAPE) - vsout.PositionCS = AdjustLodLandscapeVertexPositionCS(positionCS); + vsout.PositionCS = LodLandscape::AdjustLodLandscapeVertexPositionCS(positionCS); # elif defined(RENDER_SHADOWMAP_PB) float3 positionCSPerspective = positionCS.xyz / positionCS.w; float3 shadowDirection = normalize(normalize(positionCSPerspective) + float3(0, 0, ParabolaParam.y)); @@ -191,7 +191,7 @@ VS_OUTPUT main(VS_INPUT input) # if defined(RENDER_NORMAL) float3 normalVS = float3(1, 1, 1); # if defined(SKINNED) - float3x3 boneRSMatrix = GetBoneRSMatrix(Bones, boneIndices, input.BoneWeights); + float3x3 boneRSMatrix = Skinned::GetBoneRSMatrix(Bones, boneIndices, input.BoneWeights); normalMS = normalize(mul(normalMS, transpose(boneRSMatrix))); normalVS = mul(CameraView[eyeIndex], float4(normalMS, 0)).xyz; # else diff --git a/package/Shaders/Water.hlsl b/package/Shaders/Water.hlsl index 682cc451a..cd600ffa5 100644 --- a/package/Shaders/Water.hlsl +++ b/package/Shaders/Water.hlsl @@ -554,7 +554,7 @@ float3 GetWaterSpecularColor(PS_INPUT input, float3 normal, float3 viewDirection sh2 skylighting = Skylighting::sample(skylightingSettings, SkylightingProbeArray, positionMSSkylight, normal); sh2 specularLobe = Skylighting::fauxSpecularLobeSH(normal, -viewDirection, 0.0); - float skylightingSpecular = shFuncProductIntegral(skylighting, specularLobe); + float skylightingSpecular = SphericalHarmonics::FuncProductIntegral(skylighting, specularLobe); skylightingSpecular = lerp(1.0, skylightingSpecular, Skylighting::getFadeOutFactor(input.WPosition.xyz)); skylightingSpecular = Skylighting::mixSpecular(skylightingSettings, skylightingSpecular); @@ -733,7 +733,7 @@ DiffuseOutput GetWaterDiffuseColor(PS_INPUT input, float3 normal, float3 viewDir # endif sh2 skylightingSH = Skylighting::sample(skylightingSettings, SkylightingProbeArray, positionMSSkylight, float3(0, 0, 1)); - float skylighting = shUnproject(skylightingSH, float3(0, 0, 1)); + float skylighting = SphericalHarmonics::Unproject(skylightingSH, float3(0, 0, 1)); skylighting = lerp(1.0, skylighting, Skylighting::getFadeOutFactor(input.WPosition.xyz)); float3 refractionDiffuseColorSkylight = Skylighting::mixDiffuse(skylightingSettings, skylighting); @@ -915,7 +915,7 @@ PS_OUTPUT main(PS_INPUT input) float3 sunColor = GetSunColor(normal, viewDirection); if (!(PixelShaderDescriptor & WaterFlags::Interior)) { - sunColor *= GetWaterShadow(screenNoise, input.WPosition.xyz, eyeIndex); + sunColor *= ShadowSampling::GetWaterShadow(screenNoise, input.WPosition.xyz, eyeIndex); } # if defined(VC) @@ -950,7 +950,7 @@ PS_OUTPUT main(PS_INPUT input) float VdotN = dot(viewDirection, normal); psout.WaterMask = float4(0, 0, VdotN, 0); - psout.MotionVector = GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition); + psout.MotionVector = MotionBlur::GetSSMotionVector(input.WorldPosition, input.PreviousWorldPosition); # endif return psout;