}
// Computes F(x)/P(x), s.t. x = sqrt(r^2 + t^2).
float3 ComputeBilateralWeight(float3 S, float r, float t, float rcpDistScale, float rcpPdf)
float3 ComputeBilateralWeight(float3 S, float r, float t, float rcpPdf)
// Reducing the integration distance is equivalent to stretching the integration axis.
float3 val = KernelValCircle(sqrt(r * r + t * t) * rcpDistScale, S);
float3 val = KernelValCircle(sqrt(r * r + t * t), S);
// Rescaling of the PDF is handled via 'totalWeight'.
// Rescaling of the PDF is handled by 'totalWeight'.
millimPerUnit, scaledPixPerMm, rcpDistScale, totalIrradiance, totalWeight) \
millimPerUnit, pixelsPerMm, totalIrradiance, totalWeight) \
{ \
float r = kernel[profileID][i][0]; \
/* The relative sample position is known at compile time. */ \
float2 position = centerPosUnSS + vec * scaledPixPerMm; \
float2 position = centerPosUnSS + vec * pixelsPerMm; \
float3 irradiance = LOAD_TEXTURE2D(_IrradianceSource, position).rgb; \
\
/* TODO: see if making this a [branch] improves performance. */ \
float d = LinearEyeDepth(z, _ZBufferParams); \
float t = millimPerUnit * d - (millimPerUnit * centerDepthVS); \
float p = kernel[profileID][i][1]; \
float3 w = ComputeBilateralWeight(shapeParam, r, t, rcpDistScale, p); \
float3 w = ComputeBilateralWeight(shapeParam, r, t, p); \
\
totalIrradiance += w * irradiance; \
totalWeight += w; \
/* Our blur is energy-preserving, so 'centerWeight' should be set to 0. */ \
/* We do not terminate the loop since we want to gather the contribution */ \
/* of the remaining samples (e.g. in case of hair covering skin). */ \
/* Note: See comment in the output of deferred.shader */ \
millimPerUnit, scaledPixPerMm, rcpDistScale, totalIrradiance, totalWeight) \
millimPerUnit, pixelsPerMm, totalIrradiance, totalWeight) \
{ \
float centerRcpPdf = kernel[profileID][0][1]; \
float3 centerWeight = KernelValCircle(0, shapeParam) * centerRcpPdf; \
for (uint i = 1; i < n; i++) \
{ \
SSS_ITER(i, n, kernel, profileID, shapeParam, centerPosUnSS, centerDepthVS, \
millimPerUnit, scaledPixPerMm, rcpDistScale, totalIrradiance, totalWeight) \
millimPerUnit, pixelsPerMm, totalIrradiance, totalWeight) \
} \
}
float3 cornerPosVS = ComputeViewSpacePosition(cornerPosSS, centerDepth, _InvProjMatrix);
// Compute the view-space dimensions of the pixel as a quad projected onto geometry.
float2 unitsPerPixel = 2 * (cornerPosVS.xy - centerPosVS.xy);
float2 unitsPerPixel = 2 * abs(cornerPosVS.xy - centerPosVS.xy);
float metersPerUnit = _WorldScales[profileID];
float millimPerUnit = MILLIMETERS_PER_METER * metersPerUnit;
float2 scaledPixPerMm = distScale * rcp(millimPerUnit * unitsPerPixel);
// Rescaling the filter is equivalent to inversely scaling the world.
float metersPerUnit = _WorldScales[profileID] / distScale;
float millimPerUnit = MILLIMETERS_PER_METER * metersPerUnit;
float2 pixelsPerMm = rcp(millimPerUnit * unitsPerPixel);
// Take the first (central) sample.
// TODO: copy its neighborhood into LDS.
float maxDistInPixels = maxDistance * max(scaledPixPerMm.x, scaledPixPerMm.y);
float maxDistInPixels = maxDistance * max(pixelsPerMm.x, pixelsPerMm.y);
[branch]
if (distScale == 0 || maxDistInPixels < 1)
{
#else
SSS_LOOP(SSS_N_SAMPLES_FAR_FIELD, _FilterKernelsFarField,
profileID, shapeParam, centerPosition, centerPosVS.z,
millimPerUnit, scaledPixPerMm, rcp(distScale),
totalIrradiance, totalWeight)
millimPerUnit, pixelsPerMm, totalIrradiance, totalWeight)
#endif
}
else
#else
SSS_LOOP(SSS_N_SAMPLES_NEAR_FIELD, _FilterKernelsNearField,
profileID, shapeParam, centerPosition, centerPosVS.z,
millimPerUnit, scaledPixPerMm, rcp(distScale),
totalIrradiance, totalWeight)
millimPerUnit, pixelsPerMm, totalIrradiance, totalWeight)
float metersPerUnit = _WorldScales[profileID] * SSS_BASIC_DISTANCE_SCALE;
float centimPerUnit = CENTIMETERS_PER_METER * metersPerUnit;
float2 scaledPixPerCm = distScale * rcp(centimPerUnit * unitsPerPixel);
float unitScale = centimPerUnit / distScale;
// Rescaling the filter is equivalent to inversely scaling the world.
float metersPerUnit = _WorldScales[profileID] / distScale * SSS_BASIC_DISTANCE_SCALE;
float centimPerUnit = CENTIMETERS_PER_METER * metersPerUnit;
float2 pixelsPerCm = rcp(centimPerUnit * unitsPerPixel);
float scaledStepSize = scaledPixPerCm.x;
float2 unitDirection = float2(1, 0);
float2 unitDirection = float2(1, 0);
float scaledStepSize = scaledPixPerCm.y;
float2 unitDirection = float2(0, 1);
float2 unitDirection = float2(0, 1);
float2 scaledDirection = scaledPixPerCm * unitDirection;
float2 scaledDirection = pixelsPerCm * unitDirection;
#if (RBG_BILATERAL_WEIGHTS != 0)
#if RBG_BILATERAL_WEIGHTS
float3 halfRcpVariance = _HalfRcpWeightedVariances[profileID].rgb;
#else
float halfRcpVariance = _HalfRcpWeightedVariances[profileID].a;
// We perform point sampling. Therefore, we can avoid the cost
// of filtering if we stay within the bounds of the current pixel.
// We use the value of 1 instead of 0.5 as an optimization.
float maxDistInPixels = scaledStepSize * maxDistance ;
float maxDistInPixels = maxDistance * max(pixelsPerCm.x, pixelsPerCm.y) ;
[branch]
if (distScale == 0 || maxDistInPixels < 1)
[flatten]
if (any(sampleIrradiance))
{
#if SSS_BILATERAL
float zDistance = unitScale * sampleDepth - (unitScale * centerPosVS.z);
float zDistance = centimPerUnit * sampleDepth - (centimPerUnit * centerPosVS.z);
#endif
totalIrradiance += sampleWeight * sampleIrradiance;
totalWeight += sampleWeight;