Skip to content

Commit ffa2aed

Browse files
committed
Improve the performance and the quality of the SSS pass
1 parent b0cc6b4 commit ffa2aed

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,57 @@ Shader "Hidden/HDRenderPipeline/CombineSubsurfaceScattering"
134134
// TODO: ask Morten if there is a better way to do this.
135135
float3 totalWeight = sampleWeight;
136136

137-
[unroll]
138-
for (int i = 1; i < N_SAMPLES; i++)
137+
uint i; // Sample index
138+
139+
[unroll] // Gather samples from the center to the left (up).
140+
for (i = 1; i <= N_SAMPLES / 2; i++)
139141
{
140142
samplePosition = posInput.unPositionSS + rotatedDirection * _FilterKernels[profileID][i].a;
141143
sampleWeight = _FilterKernels[profileID][i].rgb;
142144

143145
rawDepth = LOAD_TEXTURE2D(_MainDepthTexture, samplePosition).r;
144146
sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
145147

148+
if (any(sampleIrradiance) == false)
149+
{
150+
// The irradiance is 0. There could be two reasons for this.
151+
// Most likely, the surface fragment does not have an SSS material.
152+
// Alternatively, the surface fragment could be completely shadowed.
153+
// Our blur is energy-preserving, so 'sampleWeight' should be 0.
154+
// We can save some bandwidth by terminating the loop early.
155+
break;
156+
}
157+
158+
// Apply bilateral weighting.
159+
// Ref #1: Skin Rendering by Pseudo–Separable Cross Bilateral Filtering.
160+
// Ref #2: Separable SSS, Supplementary Materials, Section E.
161+
float sampleDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
162+
float zDistance = invDistScale * sampleDepth - (invDistScale * centerPosVS.z);
163+
sampleWeight *= exp(-zDistance * zDistance * halfRcpVariance);
164+
165+
totalIrradiance += sampleWeight * sampleIrradiance;
166+
totalWeight += sampleWeight;
167+
}
168+
169+
[unroll] // Gather samples from the center to the right (down).
170+
for (; i < N_SAMPLES; i++)
171+
{
172+
samplePosition = posInput.unPositionSS + rotatedDirection * _FilterKernels[profileID][i].a;
173+
sampleWeight = _FilterKernels[profileID][i].rgb;
174+
175+
rawDepth = LOAD_TEXTURE2D(_MainDepthTexture, samplePosition).r;
176+
sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
177+
178+
if (any(sampleIrradiance) == false)
179+
{
180+
// The irradiance is 0. There could be two reasons for this.
181+
// Most likely, the surface fragment does not have an SSS material.
182+
// Alternatively, the surface fragment could be completely shadowed.
183+
// Our blur is energy-preserving, so 'sampleWeight' should be 0.
184+
// We can save some bandwidth by terminating the loop early.
185+
break;
186+
}
187+
146188
// Apply bilateral weighting.
147189
// Ref #1: Skin Rendering by Pseudo–Separable Cross Bilateral Filtering.
148190
// Ref #2: Separable SSS, Supplementary Materials, Section E.

Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,14 @@ public void UpdateKernelAndVarianceData()
9292

9393
Vector3 weightSum = new Vector3(0, 0, 0);
9494

95+
float rcpNumSamples = 1.0f / numSamples;
96+
9597
// Importance sample the linear combination of two Gaussians.
9698
for (uint i = 0; i < numSamples; i++)
9799
{
98-
float u = (i + 0.5f) / numSamples;
100+
float u = (i <= numSamples / 2) ? 0.5f - i * rcpNumSamples // The center and to the left
101+
: (i + 0.5f) * rcpNumSamples; // From the center to the right
102+
99103
float pos = GaussianCombinationCdfInverse(u, maxStdDev1, maxStdDev2, lerpWeight);
100104
float pdf = GaussianCombination(pos, maxStdDev1, maxStdDev2, lerpWeight);
101105

0 commit comments

Comments
 (0)