#pragma kernel SkinLut #pragma kernel ShadowLut #pragma multi_compile_local _ _PRODUCTION #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #define _PROFILE_WIDTH 8.166 float _ScatterRadius; float _PositionShift; float _Intensity; int _SampleCount; int _ApplyTonemap; uint _TextureSize; RWTexture2D _SSSLut; static const float VARIANCE[6] = { 0.0064, 0.0484, 0.1870, 0.5670, 1.9900, 7.4100 }; static const float3 WEIGHTS[6] = { float3(0.233, 0.455, 0.649), float3(0.100, 0.336, 0.344), float3(0.118, 0.198, 0.000), float3(0.113, 0.007, 0.007), float3(0.358, 0.004, 0.000), float3(0.078, 0.000, 0.000) }; float Gaussian(float v, float r) { return rcp(2.0 * PI * v) * exp((-r * r) / (2.0 * v)); } float3 RadianceScatter(float r) { float3 result = 0.0; for (int i = 0; i < 6; i++) { result += WEIGHTS[i] * Gaussian(VARIANCE[i], r); } return result; } float3 IntegrateDiffuseScattering_Ring(float theta, float r) { float3 totalScatter = 0; float3 totalWeight = 0; float increment = PI / _SampleCount; float x = -HALF_PI; while (x < HALF_PI) { float diffuse = saturate(cos(theta + x)); float distance = abs(2.0 * r * sin(x / 2.0)); float3 radiance = RadianceScatter(distance); totalScatter += radiance * diffuse; totalWeight += radiance; x += increment; } return totalScatter / totalWeight; } float newPenumbra(float pos, float penumbraWidth) { return saturate((pos * penumbraWidth - _PROFILE_WIDTH) / (penumbraWidth - _PROFILE_WIDTH)); } float3 IntegrateShadowScattering(float penumbraLocation, float penumbraWidth) { float3 totalScatter = 0; float3 totalWeights = 0; float increment = (_PROFILE_WIDTH * 2) / _SampleCount; penumbraWidth = max(penumbraWidth, _PROFILE_WIDTH + 1e-5); float x = -_PROFILE_WIDTH; while (x <= _PROFILE_WIDTH) { float light = newPenumbra(penumbraLocation + x / penumbraWidth, penumbraWidth); float distance = abs(x); float3 weights = RadianceScatter(distance); totalWeights += weights; totalScatter += light * weights; x += increment; } return totalScatter / totalWeights; } float3 FilmicTonemap(float3 color) { return (color * (6.2 * color + 0.5)) / (color * (6.2 * color + 1.7) + 0.06); } [numthreads(8,8,1)] void SkinLut (uint3 id : SV_DispatchThreadID) { if (id.x > _TextureSize || id.y > _TextureSize) { return; } float2 uv = id.xy / float2(_TextureSize, _TextureSize); #if UNITY_UV_STARTS_AT_TOP && _PRODUCTION uv.y = 1.0 - uv.y; #endif float theta = acos((uv.x * 2.0 - 1.0)) + _PositionShift; float r = rcp(max(uv.y, 0.001) * _ScatterRadius); float3 scatter = IntegrateDiffuseScattering_Ring(theta, r) * _Intensity; if (_ApplyTonemap == 1) { scatter = FilmicTonemap(scatter); } _SSSLut[id.xy] = float4(scatter, 1.0); //_SSSLut[id.xy] = theta; } [numthreads(8, 8, 1)] void ShadowLut(uint3 id : SV_DispatchThreadID) { if (id.x > _TextureSize || id.y > _TextureSize) { return; } float2 uv = id.xy / float2(_TextureSize, _TextureSize); #if UNITY_UV_STARTS_AT_TOP && _PRODUCTION uv.y = 1.0 - uv.y; #endif float penumbraLocation = uv.x + _PositionShift; float penumbraWidth = rcp(max(uv.y, 0.001) * _ScatterRadius); float3 scatter = IntegrateShadowScattering(penumbraLocation, penumbraWidth) * _Intensity; if (_ApplyTonemap == 1) { scatter = FilmicTonemap(scatter); } _SSSLut[id.xy] = float4(scatter, 1.0); }