uint _EnableSSSAndTransmission; // Globally toggles subsurface and transmission scattering on/off
uint _TexturingModeFlags; // 1 bit/profile; 0 = PreAndPostScatter, 1 = PostScatter
uint _TransmissionFlags; // 2 bit/profile; 0 = inf. thick, 1 = thin, 2 = regular
// Old SSS Model >>>
uint _UseDisneySSS;
float4 _HalfRcpVariancesAndWeights[SSS_N_PROFILES][2]; // 2x Gaussians in RGB, A is interpolation weights
// <<< Old SSS Model
float4 _TransmissionTints[SSS_N_PROFILES]; // RGB = color, A = unused
float4 _TransmissionTints[SSS_N_PROFILES]; // RGB = 1/4 * color, A = unused
CBUFFER_END
//-----------------------------------------------------------------------------
bsdfData.enableTransmission = transmissionMode != SSS_TRSM_MODE_NONE && (_EnableSSSAndTransmission > 0);
bsdfData.useThinObjectMode = transmissionMode == SSS_TRSM_MODE_THIN;
if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance(_ShapeParams[subsurfaceProfile].rgb,
_TransmissionTints[subsurfaceProfile].rgb,
bsdfData.thickness, bsdfData.subsurfaceRadius);
}
bool performPostScatterTexturing = IsBitSet(_TexturingModeFlags, subsurfaceProfile);
bool enableSssAndTransmission = true;
{
bsdfData.diffuseColor = sqrt(bsdfData.diffuseColor);
}
}
if (bsdfData.enableTransmission)
{
if (_UseDisneySSS)
{
bsdfData.transmittance = ComputeTransmittance(_ShapeParams[subsurfaceProfile].rgb,
_TransmissionTints[subsurfaceProfile].rgb,
bsdfData.thickness, bsdfData.subsurfaceRadius);
}
else
{
bsdfData.transmittance = ComputeTransmittanceJimenez(_HalfRcpVariancesAndWeights[subsurfaceProfile][0].rgb,
_HalfRcpVariancesAndWeights[subsurfaceProfile][0].a,
_HalfRcpVariancesAndWeights[subsurfaceProfile][1].rgb,
_HalfRcpVariancesAndWeights[subsurfaceProfile][1].a,
_TransmissionTints[subsurfaceProfile].rgb,
bsdfData.thickness, bsdfData.subsurfaceRadius);
}
bsdfData.transmittance *= bsdfData.diffuseColor; // Premultiply
}
}
diffuseLighting = bsdfData.diffuseColor * diffuseTerm;
}
// Currently, we only model diffuse transmission. Specular transmission is not yet supported.
// We assume that the back side of the object is a uniformly illuminated infinite plane
// (we reuse the illumination) with the reversed normal of the current sample.
// We apply wrapped lighting instead of the regular Lambertian diffuse
// to compensate for these approximations.
float3 EvaluateTransmission(BSDFData bsdfData, float NdotL, float3 lightColor, float diffuseScale, float shadow)
{
float illuminance = ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = bsdfData.useThinObjectMode ? shadow : 1;
illuminance *= shadow;
float3 backLight = lightColor * (Lambert() * illuminance * diffuseScale);
return backLight * bsdfData.transmittance; // Premultiplied with the diffuse color
}
//-----------------------------------------------------------------------------
// EvaluateBSDF_Directional (supports directional and box projector lights)
//-----------------------------------------------------------------------------
diffuseLighting = float3(0, 0, 0); // TODO: check whether using 'out' instead of 'inout' increases the VGPR pressure
specularLighting = float3(0, 0, 0); // TODO: check whether using 'out' instead of 'inout' increases the VGPR pressure
float3 cookie = float3(1, 1, 1);
float shadow = 1;
float shadow = 1;
[branch] if (lightData.shadowIndex >= 0)
{
float3 positionLS = mul(lightToSurface, transpose(lightToWorld));
float2 positionNDC = positionLS.xy;
float clipFactor = 1.0f ;
float clipFactor;
// Remap the texture coordinates from [-1, 1]^2 to [0, 1]^2.
float2 coord = positionNDC * 0.5 + 0.5;
// Tile the texture if the 'repeat' wrap mode is enabled.
coord = frac(coord);
clipFactor = 1;
}
else
{
// We let the sampler handle tiling or clamping to border.
// Note: tiling (the repeat mode) is not currently supported.
float4 c = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
float4 cookie = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
// Use premultiplied alpha to save 1x VGPR.
cookie = c.rgb * c.a * clipFactor;
// Premultiply.
cookie.a *= clipFactor;
lightData.color *= cookie.rgb;
lightData.diffuseScale *= cookie.a;
lightData.specularScale *= cookie.a;
}
[branch] if (illuminance > 0.0)
diffuseLighting *= (cookie * lightData.color) * (illuminance * lightData.diffuseScale);
specularLighting *= (cookie * lightData.color) * (illuminance * lightData.specularScale);
diffuseLighting *= lightData.color * (illuminance * lightData.diffuseScale);
specularLighting *= lightData.color * (illuminance * lightData.specularScale);
// Currently, we only model diffuse transmission. Specular transmission is not yet supported.
// We assume that the back side of the object is a uniformly illuminated infinite plane
// (we reuse the illumination) with the reversed normal of the current sample.
// We apply wrapped lighting instead of the regular Lambertian diffuse
// to compensate for these approximations.
illuminance = ComputeWrappedDiffuseLighting(NdotL, SSS_WRAP_LIGHT);
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = bsdfData.useThinObjectMode ? shadow : 1;
illuminance *= shadow;
float3 backLight = (cookie * lightData.color) * (Lambert() * illuminance * lightData.diffuseScale);
// TODO: multiplication by 'diffuseColor' and 'transmittance' is the same for each light.
float3 transmittedLight = backLight * (bsdfData.diffuseColor * bsdfData.transmittance);
diffuseLighting += transmittedLight;
diffuseLighting += EvaluateTransmission(bsdfData, NdotL, lightData.color, lightData.diffuseScale, shadow);
}
}
// For point light and directional GetAngleAttenuation() return 1
float3 lightToSurface = positionWS - lightData.positionWS;
float3 unL = -lightToSurface;
float3 L = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? normalize(unL) : -lightData.forward;
float3 unL = -lightToSurface;
float3 L = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? normalize(unL) : -lightData.forward;
float NdotL = dot(bsdfData.normalWS, L);
float illuminance = saturate(NdotL);
// Note: lightData.invSqrAttenuationRadius is 0 when applyRangeAttenuation is false
float NdotL = dot(bsdfData.normalWS, L);
float illuminance = saturate(NdotL * attenuation);
// Premultiply.
lightData.diffuseScale *= attenuation;
lightData.specularScale *= attenuation;
float3 cookie = float3(1, 1, 1);
float shadow = 1;
float shadow = 1;
[branch] if (lightData.shadowIndex >= 0)
{
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
float3 positionLS = mul(lightToSurface, transpose(lightToWorld));
float4 cookie;
float4 c = SampleCookieCube(lightLoopContext, positionLS, lightData.cookieIndex);
// Use premultiplied alpha to save 1x VGPR.
cookie = c.rgb * c.a;
cookie = SampleCookieCube(lightLoopContext, positionLS, lightData.cookieIndex);
}
else
{
float2 coord = positionNDC * 0.5 + 0.5;
// We let the sampler handle clamping to border.
float4 c = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
cookie = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
// Use premultiplied alpha to save 1x VGPR.
cookie = c.rgb * (c.a * clipFactor);
cookie.a *= clipFactor;
// Premultiply.
lightData.color *= cookie.rgb;
lightData.diffuseScale *= cookie.a;
lightData.specularScale *= cookie.a;
bsdfData.roughness = max(bsdfData.roughness, lightData.minRoughness); // Simulate that a punctual ligth have a radius with this hack
diffuseLighting *= (cookie.rgb * lightData.color) * (illuminance * lightData.diffuseScale);
specularLighting *= (cookie.rgb * lightData.color) * (illuminance * lightData.specularScale);
diffuseLighting *= lightData.color * (illuminance * lightData.diffuseScale);
specularLighting *= lightData.color * (illuminance * lightData.specularScale);
// Currently, we only model diffuse transmission. Specular transmission is not yet supported.
// We assume that the back side of the object is a uniformly illuminated infinite plane
// (we reuse the illumination) with the reversed normal of the current sample.
// We apply wrapped lighting instead of the regular Lambertian diffuse
// to compensate for these approximations.
illuminance = ComputeWrappedDiffuseLighting(NdotL, SSS_WRAP_LIGHT) * attenuation;
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = bsdfData.useThinObjectMode ? shadow : 1;
illuminance *= shadow;
float3 backLight = (cookie.rgb * lightData.color) * (Lambert() * illuminance * lightData.diffuseScale);
// TODO: multiplication by 'diffuseColor' and 'transmittance' is the same for each light.
float3 transmittedLight = backLight * (bsdfData.diffuseColor * bsdfData.transmittance);
diffuseLighting += transmittedLight;
diffuseLighting += EvaluateTransmission(bsdfData, NdotL, lightData.color, lightData.diffuseScale, shadow);
}
}