// Note: in the enum StencilBits, Standard is before SSS and the stencil is setup to greater equal. So the code below is draw all stencil bit except SSS
// Note: in the enum StencilBits, Standard is before SSS and the stencil is setup to greater equal. So the code below is draw all stencil bit except SSS
// Note: in the enum StencilBits, Standard is before SSS and the stencil is setup to greater equal. So the code below is draw all stencil bit except SSS
publicreadonlyGUIContentsssTransmittancePreview1=newGUIContent("Shows the fraction of light passing through the object for thickness values from the remap.");
publicreadonlyGUIContentsssTransmittancePreview2=newGUIContent("Can be thought of as a cross section of a slab of material illuminated by a white light from the left.");
publicreadonlyGUIContentsssProfileStdDev1=newGUIContent("Standard Deviation #1","Determines the shape of the 1st Gaussian filter. Increases the strength and the radius of the blur of the corresponding color channel.");
publicreadonlyGUIContentsssProfileStdDev2=newGUIContent("Standard Deviation #2","Determines the shape of the 2nd Gaussian filter. Increases the strength and the radius of the blur of the corresponding color channel.");
publicreadonlyGUIContentsssProfileLerpWeight=newGUIContent("Filter Interpolation","Controls linear interpolation between the two Gaussian filters.");
publicreadonlyGUIContentsssTexturingMode=newGUIContent("Texturing Mode","Specifies when the diffuse texture should be applied.");
publicreadonlyGUIContentsssTransmittancePreview1=newGUIContent("Shows the fraction of light passing through the object for thickness values from the remap.");
publicreadonlyGUIContentsssTransmittancePreview2=newGUIContent("Can be thought of as a cross section of a slab of material illuminated by a white light from the left.");
publicreadonlyGUIContentsssProfileScatterDistance1=newGUIContent("Scatter Distance #1","The radius (in centimeters) of the 1st Gaussian filter, one per color channel. Alpha is ignored. The blur is energy-preserving, so a wide filter results in a large area with small contributions of individual samples. Smaller values increase the sharpness.");
publicreadonlyGUIContentsssProfileScatterDistance2=newGUIContent("Scatter Distance #2","The radius (in centimeters) of the 2nd Gaussian filter, one per color channel. Alpha is ignored. The blur is energy-preserving, so a wide filter results in a large area with small contributions of individual samples. Smaller values increase the sharpness.");
publicreadonlyGUIContentsssProfileLerpWeight=newGUIContent("Filter Interpolation","Controls linear interpolation between the two Gaussian filters.");
publicreadonlyGUIContentsssTexturingMode=newGUIContent("Texturing Mode","Specifies when the diffuse texture should be applied.");
newGUIContent("Pre- and post-scatter","Texturing is performed during both the lighting and the SSS passes. Slightly blurs the diffuse texture. Choose this mode if your diffuse texture contains little to no SSS lighting."),
newGUIContent("Post-scatter","Texturing is performed only during the SSS pass. Effectively preserves the sharpness of the diffuse texture. Choose this mode if your diffuse texture already contains SSS lighting (e.g. a photo of skin).")
// NdotV can be negative for visible pixels due to the perspective projection, the normal mapping and decals.
// This can produce visible artifacts with direct specular lighting (white point, black point) and indirect specular (artifact with cubemap fetch)
// A way to reduce artifact is to limit NdotV value to not be negative and calculate reflection vector for cubemap with a shifted normal (i.e what depends on the view)
// This is what provide this function
// Note: NdotV return by this function is always positive, no need for saturate
float GetShiftedNdotV(inout float3 N, float3 V, float NdotV)
// 'NdotV' can become negative for visible pixels due to the perspective projection, normal mapping and decals.
// This can produce visible artifacts under specular lighting, both direct (overly dark/bright pixels) and indirect (incorrect cubemap direction).
// One way of avoiding these artifacts is to limit the value of 'NdotV' to a small positive number,
// and calculate the reflection vector for the cubemap fetch using a normal shifted into view.
float3 GetViewShiftedNormal(float3 N, float3 V, float NdotV, float minNdotV)
const float limit = 0.0001; // Epsilon value that avoid divide by 0 (several BSDF divide by NdotV)
if (NdotV < limit)
if (NdotV < minNdotV)
// We do not renormalize the normal because { abs(length(N) - 1.0) < limit } + It is use for cubemap
N += (-NdotV + limit) * V;
NdotV = limit;
// We do not renormalize the normal to save a few clock cycles.
// The magnitude difference is typically negligible, and the normal is only used to compute
// the reflection vector for the IBL cube map fetch (which does not depend on the magnitude).
N += (-NdotV + minNdotV) * V;
return NdotV;
return N;
}
// Generates an orthonormal basis from a unit vector.