|
|
|
|
|
|
bsdfData.enableTransmission = transmissionMode != SSS_TRSM_MODE_NONE && (_EnableSSSAndTransmission > 0); |
|
|
|
bsdfData.useThinObjectMode = transmissionMode == SSS_TRSM_MODE_THIN; |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
float3 unL = -lightToSurface; |
|
|
|
float3 L = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? normalize(unL) : -lightData.forward; |
|
|
|
|
|
|
|
float NdotL = dot(bsdfData.normalWS, L); |
|
|
|
float illuminance = saturate(NdotL); |
|
|
|
|
|
|
|
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; |
|
|
|
} |
|
|
|
|
|
|
|
[branch] if (illuminance > 0.0) |
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|