浏览代码

Merge pull request #366 from EvgeniiG/master

Switch transmission units of Jimenez SSS to millimeters
/main
GitHub 7 年前
当前提交
e4df0571
共有 8 个文件被更改,包括 145 次插入64 次删除
  1. 19
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  2. 4
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDShaderIDs.cs
  3. 21
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs
  4. 28
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  5. 88
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs
  6. 6
      Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawSssProfile.shader
  7. 19
      Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawTransmittanceGraph.shader
  8. 24
      Assets/ScriptableRenderPipeline/ShaderLibrary/CommonMaterial.hlsl

19
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


}
// Broadcast SSS parameters to all shaders.
Shader.SetGlobalInt(HDShaderIDs._EnableSSSAndTransmission, m_DebugDisplaySettings.renderingDebugSettings.enableSSSAndTransmission ? 1 : 0);
Shader.SetGlobalInt(HDShaderIDs._TexturingModeFlags, (int)sssParameters.texturingModeFlags);
Shader.SetGlobalInt(HDShaderIDs._TransmissionFlags, (int)sssParameters.transmissionFlags);
cmd.SetGlobalVectorArray(HDShaderIDs._ThicknessRemaps, sssParameters.thicknessRemaps);
// We are currently supporting two different SSS mode: Jimenez (with 2-Gaussian profile) and Disney
// We have added the ability to switch between each other for subsurface scattering, but for transmittance this is more tricky as we need to add
// shader variant for forward, gbuffer and deferred shader. We want to avoid this.
// So for transmittance we use Disney profile formulation (that we know is more correct) in both case, and in the case of Jimenez we hack the parameters with 2-Gaussian parameters (Ideally we should fit but haven't find good fit) so it approximately match.
// Note: Jimenez SSS is in cm unit whereas Disney is in mm unit making an inconsistency here to compare model side by side
cmd.SetGlobalVectorArray(HDShaderIDs._ShapeParams, sssParameters.useDisneySSS ? sssParameters.shapeParams : sssParameters.halfRcpWeightedVariances);
cmd.SetGlobalVectorArray(HDShaderIDs._TransmissionTints, sssParameters.transmissionTints);
Shader.SetGlobalInt( HDShaderIDs._EnableSSSAndTransmission, m_DebugDisplaySettings.renderingDebugSettings.enableSSSAndTransmission ? 1 : 0);
Shader.SetGlobalInt( HDShaderIDs._TexturingModeFlags, (int)sssParameters.texturingModeFlags);
Shader.SetGlobalInt( HDShaderIDs._TransmissionFlags, (int)sssParameters.transmissionFlags);
Shader.SetGlobalInt( HDShaderIDs._UseDisneySSS, sssParameters.useDisneySSS ? 1 : 0);
cmd.SetGlobalVectorArray(HDShaderIDs._ThicknessRemaps, sssParameters.thicknessRemaps);
cmd.SetGlobalVectorArray(HDShaderIDs._ShapeParams, sssParameters.shapeParams);
cmd.SetGlobalVectorArray(HDShaderIDs._HalfRcpVariancesAndWeights, sssParameters.halfRcpVariancesAndWeights);
cmd.SetGlobalVectorArray(HDShaderIDs._TransmissionTints, sssParameters.transmissionTints);
}
}

4
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDShaderIDs.cs


internal static readonly int _AmbientOcclusionDirectLightStrenght = Shader.PropertyToID("_AmbientOcclusionDirectLightStrenght");
internal static readonly int _SkyTexture = Shader.PropertyToID("_SkyTexture");
internal static readonly int _UseDisneySSS = Shader.PropertyToID("_UseDisneySSS");
internal static readonly int _HalfRcpVariancesAndWeights = Shader.PropertyToID("_HalfRcpVariancesAndWeights");
internal static readonly int _TransmissionTints = Shader.PropertyToID("_TransmissionTints");
internal static readonly int specularLightingUAV = Shader.PropertyToID("specularLightingUAV");
internal static readonly int diffuseLightingUAV = Shader.PropertyToID("diffuseLightingUAV");

internal static readonly int _StdDev1 = Shader.PropertyToID("_StdDev1");
internal static readonly int _StdDev2 = Shader.PropertyToID("_StdDev2");
internal static readonly int _LerpWeight = Shader.PropertyToID("_LerpWeight");
internal static readonly int _HalfRcpVarianceAndWeight1 = Shader.PropertyToID("_HalfRcpVarianceAndWeight1");
internal static readonly int _HalfRcpVarianceAndWeight2 = Shader.PropertyToID("_HalfRcpVarianceAndWeight2");
internal static readonly int _TransmissionTint = Shader.PropertyToID("_TransmissionTint");
internal static readonly int _ThicknessRemap = Shader.PropertyToID("_ThicknessRemap");

21
Assets/ScriptableRenderPipeline/HDRenderPipeline/Lighting/TilePass/TilePass.cs


int enableSSSAndTransmission = Shader.GetGlobalInt(HDShaderIDs._EnableSSSAndTransmission);
int texturingModeFlags = Shader.GetGlobalInt(HDShaderIDs._TexturingModeFlags);
int transmissionFlags = Shader.GetGlobalInt(HDShaderIDs._TransmissionFlags);
int useDisneySSS = Shader.GetGlobalInt(HDShaderIDs._UseDisneySSS);
Vector4[] halfRcpVariancesAndWeights = Shader.GetGlobalVectorArray(HDShaderIDs._HalfRcpVariancesAndWeights);
Texture skyTexture = Shader.GetGlobalTexture(HDShaderIDs._SkyTexture);

cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs._SkyTexture, skyTexture ? skyTexture : m_DefaultTexture2DArray);
// Set SSS parameters.
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._EnableSSSAndTransmission, enableSSSAndTransmission);
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._TexturingModeFlags, texturingModeFlags);
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._TransmissionFlags, transmissionFlags);
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._ThicknessRemaps, thicknessRemaps);
// We are currently supporting two different SSS mode: Jimenez (with 2-Gaussian profile) and Disney
// We have added the ability to switch between each other for subsurface scattering, but for transmittance this is more tricky as we need to add
// shader variant for forward, gbuffer and deferred shader. We want to avoid this.
// So for transmittance we use Disney profile formulation (that we know is more correct) in both case, and in the case of Jimenez we hack the parameters with 2-Gaussian parameters (Ideally we should fit but haven't find good fit) so it approximately match.
// Note: Jimenez SSS is in cm unit whereas Disney is in mm unit making an inconsistency here to compare model side by side
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._ShapeParams, shapeParams);
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._TransmissionTints, transmissionTints);
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._EnableSSSAndTransmission, enableSSSAndTransmission);
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._TexturingModeFlags, texturingModeFlags);
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._TransmissionFlags, transmissionFlags);
cmd.SetComputeIntParam( deferredComputeShader, HDShaderIDs._UseDisneySSS, useDisneySSS);
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._ThicknessRemaps, thicknessRemaps);
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._ShapeParams, shapeParams);
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._TransmissionTints, transmissionTints);
cmd.SetComputeVectorArrayParam(deferredComputeShader, HDShaderIDs._HalfRcpVariancesAndWeights, halfRcpVariancesAndWeights);
cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs.specularLightingUAV, colorBuffers[0]);
cmd.SetComputeTextureParam(deferredComputeShader, kernel, HDShaderIDs.diffuseLightingUAV, colorBuffers[1]);

28
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


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
//-----------------------------------------------------------------------------

if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance(_ShapeParams[subsurfaceProfile].rgb,
_TransmissionTints[subsurfaceProfile].rgb,
bsdfData.thickness, bsdfData.subsurfaceRadius);
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);

// (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);
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;

// (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;
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;

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


m_FilterKernelNearField[i].y = 1.0f / KernelPdf(r, s);
}
m_MaxRadius = m_FilterKernelNearField[SssConstants.SSS_N_SAMPLES_NEAR_FIELD - 1].x;
// Importance sample the far field kernel.
for (int i = 0, n = SssConstants.SSS_N_SAMPLES_FAR_FIELD; i < n; i++)
{

m_FilterKernelFarField[i].x = r;
m_FilterKernelFarField[i].y = 1.0f / KernelPdf(r, s);
}
m_MaxRadius = m_FilterKernelFarField[SssConstants.SSS_N_SAMPLES_FAR_FIELD - 1].x;
// Old SSS Model >>>
UpdateKernelAndVarianceData();

public int numProfiles; // Excluding the neutral profile
public SubsurfaceScatteringProfile[] profiles;
// Below are the cached values. TODO: uncomment when SSS profile asset serialization is fixed.
/*[NonSerialized]*/ public int texturingModeFlags; // 1 bit/profile; 0 = PreAndPostScatter, 1 = PostScatter
/*[NonSerialized]*/ public int transmissionFlags; // 2 bit/profile; 0 = inf. thick, 1 = thin, 2 = regular
/*[NonSerialized]*/ public Vector4[] thicknessRemaps; // Remap: 0 = start, 1 = end - start
/*[NonSerialized]*/ public Vector4[] worldScales; // Size of the world unit in meters (only the X component is used)
/*[NonSerialized]*/ public Vector4[] shapeParams; // RGB = S = 1 / D, A = filter radius
/*[NonSerialized]*/ public Vector4[] transmissionTints; // RGB = color, A = unused
/*[NonSerialized]*/ public Vector4[] filterKernels; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
/*[NonSerialized]*/ public int texturingModeFlags; // 1 bit/profile; 0 = PreAndPostScatter, 1 = PostScatter
/*[NonSerialized]*/ public int transmissionFlags; // 2 bit/profile; 0 = inf. thick, 1 = thin, 2 = regular
/*[NonSerialized]*/ public Vector4[] thicknessRemaps; // Remap: 0 = start, 1 = end - start
/*[NonSerialized]*/ public Vector4[] worldScales; // Size of the world unit in meters (only the X component is used)
/*[NonSerialized]*/ public Vector4[] shapeParams; // RGB = S = 1 / D, A = filter radius
/*[NonSerialized]*/ public Vector4[] transmissionTints; // RGB = color, A = unused
/*[NonSerialized]*/ public Vector4[] filterKernels; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
/*[NonSerialized]*/ public Vector4[] halfRcpWeightedVariances;
/*[NonSerialized]*/ public Vector4[] filterKernelsBasic;
/*[NonSerialized]*/ public Vector4[] halfRcpWeightedVariances;
/*[NonSerialized]*/ public Vector4[] halfRcpVariancesAndWeights;
/*[NonSerialized]*/ public Vector4[] filterKernelsBasic;
// <<< Old SSS Model
// --- Public Methods ---

numProfiles = 1;
profiles = new SubsurfaceScatteringProfile[numProfiles];
profiles[0] = null;
texturingModeFlags = 0;
transmissionFlags = 0;
thicknessRemaps = null;
worldScales = null;
shapeParams = null;
transmissionTints = null;
filterKernels = null;
numProfiles = 1;
profiles = new SubsurfaceScatteringProfile[numProfiles];
profiles[0] = null;
texturingModeFlags = 0;
transmissionFlags = 0;
thicknessRemaps = null;
worldScales = null;
shapeParams = null;
transmissionTints = null;
filterKernels = null;
useDisneySSS = true;
halfRcpWeightedVariances = null;
filterKernelsBasic = null;
useDisneySSS = true;
halfRcpWeightedVariances = null;
halfRcpVariancesAndWeights = null;
filterKernelsBasic = null;
// <<< Old SSS Model
UpdateCache();

halfRcpWeightedVariances = new Vector4[SssConstants.SSS_N_PROFILES];
}
if (halfRcpVariancesAndWeights == null || halfRcpVariancesAndWeights.Length != 2 * SssConstants.SSS_N_PROFILES)
{
halfRcpVariancesAndWeights = new Vector4[2 * SssConstants.SSS_N_PROFILES];
}
const int filterKernelsLen = SssConstants.SSS_N_PROFILES * SssConstants.SSS_BASIC_N_SAMPLES;
if (filterKernelsBasic == null || filterKernelsBasic.Length != filterKernelsLen)
{

}
// Old SSS Model >>>
halfRcpWeightedVariances[i] = Vector4.one;
halfRcpWeightedVariances[i] = Vector4.one;
halfRcpVariancesAndWeights[2 * i + 0] = Vector4.one;
halfRcpVariancesAndWeights[2 * i + 1] = Vector4.one;
for (int j = 0, n = SssConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{

worldScales[i] = new Vector4(profiles[i].worldScale, 0, 0, 0);
shapeParams[i] = profiles[i].shapeParameter;
shapeParams[i].w = profiles[i].maxRadius;
transmissionTints[i] = profiles[i].transmissionTint;
transmissionTints[i] = profiles[i].transmissionTint * 0.25f; // Premultiplied
for (int j = 0, n = SssConstants.SSS_N_SAMPLES_NEAR_FIELD; j < n; j++)
{

// Old SSS Model >>>
halfRcpWeightedVariances[i] = profiles[i].halfRcpWeightedVariances;
Vector4 stdDev1 = ((1.0f / 3.0f) * SssConstants.SSS_BASIC_DISTANCE_SCALE) * profiles[i].scatterDistance1;
Vector4 stdDev2 = ((1.0f / 3.0f) * SssConstants.SSS_BASIC_DISTANCE_SCALE) * profiles[i].scatterDistance2;
// Multiply by 0.1 to convert from millimeters to centimeters. Apply the distance scale.
// Rescale by 4 to counter rescaling of transmission tints.
float a = 0.1f * SssConstants.SSS_BASIC_DISTANCE_SCALE;
halfRcpVariancesAndWeights[2 * i + 0] = new Vector4(a * a * 0.5f / (stdDev1.x * stdDev1.x), a * a * 0.5f / (stdDev1.y * stdDev1.y), a * a * 0.5f / (stdDev1.z * stdDev1.z), 4 * (1.0f - profiles[i].lerpWeight));
halfRcpVariancesAndWeights[2 * i + 1] = new Vector4(a * a * 0.5f / (stdDev2.x * stdDev2.x), a * a * 0.5f / (stdDev2.y * stdDev2.y), a * a * 0.5f / (stdDev2.z * stdDev2.z), 4 * profiles[i].lerpWeight);
for (int j = 0, n = SssConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{

Vector2 R = m_ThicknessRemap.vector2Value;
bool transmissionEnabled = m_TransmissionMode.intValue != (int)SubsurfaceScatteringProfile.TransmissionMode.None;
// Draw the profile.
m_ProfileMaterial.SetFloat(HDShaderIDs._MaxRadius, r);
m_ProfileMaterial.SetVector(HDShaderIDs._ShapeParam, S);
// Old SSS Model >>>

float rMax = Mathf.Max(m_ScatterDistance1.colorValue.r, m_ScatterDistance1.colorValue.g, m_ScatterDistance1.colorValue.b,
m_ScatterDistance2.colorValue.r, m_ScatterDistance2.colorValue.g, m_ScatterDistance2.colorValue.b);
Vector4 stdDev1 = new Vector4(s * m_ScatterDistance1.colorValue.r, s * m_ScatterDistance1.colorValue.g, s * m_ScatterDistance1.colorValue.b);
Vector4 stdDev2 = new Vector4(s * m_ScatterDistance2.colorValue.r, s * m_ScatterDistance2.colorValue.g, s * m_ScatterDistance2.colorValue.b);
Vector4 stdDev1 = s * m_ScatterDistance1.colorValue;
Vector4 stdDev2 = s * m_ScatterDistance2.colorValue;
// Draw the profile.
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(256, 256), m_ProfileImage, m_ProfileMaterial, ScaleMode.ScaleToFit, 1.0f);
EditorGUILayout.Space();

EditorGUILayout.Space();
// Draw the transmittance graph.
// Old SSS Model >>>
// Multiply by 0.1 to convert from millimeters to centimeters. Apply the distance scale.
float a = 0.1f * SssConstants.SSS_BASIC_DISTANCE_SCALE;
Vector4 halfRcpVarianceAndWeight1 = new Vector4(a * a * 0.5f / (stdDev1.x * stdDev1.x), a * a * 0.5f / (stdDev1.y * stdDev1.y), a * a * 0.5f / (stdDev1.z * stdDev1.z), 4 * (1.0f - m_LerpWeight.floatValue));
Vector4 halfRcpVarianceAndWeight2 = new Vector4(a * a * 0.5f / (stdDev2.x * stdDev2.x), a * a * 0.5f / (stdDev2.y * stdDev2.y), a * a * 0.5f / (stdDev2.z * stdDev2.z), 4 * m_LerpWeight.floatValue);
m_TransmittanceMaterial.SetVector(HDShaderIDs._HalfRcpVarianceAndWeight1, halfRcpVarianceAndWeight1);
m_TransmittanceMaterial.SetVector(HDShaderIDs._HalfRcpVarianceAndWeight2, halfRcpVarianceAndWeight2);
// <<< Old SSS Model
// Draw the transmittance graph.
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(16, 16), m_TransmittanceImage, m_TransmittanceMaterial, ScaleMode.ScaleToFit, 16.0f);
serializedObject.ApplyModifiedProperties();

6
Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawSssProfile.shader


// N.b.: we multiply by the surface albedo of the actual geometry during shading.
// Apply gamma for visualization only. Do not apply gamma to the color.
return float4(pow(M, 1.0 / 3.0) * A, 1);
return float4(sqrt(M) * A, 1);
#else
float r = (2 * length(input.texcoord - 0.5)) * _MaxRadius * SSS_BASIC_DISTANCE_SCALE;
float3 var1 = _StdDev1.rgb * _StdDev1.rgb;

float3 magnitude = lerp(exp(-r * r / (2 * var1)) / (TWO_PI * var1),
exp(-r * r / (2 * var2)) / (TWO_PI * var2), _LerpWeight);
return float4(magnitude, 1);
// N.b.: we multiply by the surface albedo of the actual geometry during shading.
// Apply gamma for visualization only.
return float4(sqrt(magnitude), 1);
#endif
}
ENDHLSL

19
Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawTransmittanceGraph.shader


// Inputs & outputs
//-------------------------------------------------------------------------------------
uint _UseDisneySSS;
float4 _HalfRcpVarianceAndWeight1, _HalfRcpVarianceAndWeight2;
float4 _ShapeParam, _TransmissionTint, _ThicknessRemap;
//-------------------------------------------------------------------------------------

float4 Frag(Varyings input) : SV_Target
{
float d = (_ThicknessRemap.x + input.texcoord.x * (_ThicknessRemap.y - _ThicknessRemap.x));
float3 T = ComputeTransmittance(_ShapeParam.rgb, float3(1, 1, 1), d, 1);
float3 T;
if (_UseDisneySSS)
{
T = ComputeTransmittance(_ShapeParam.rgb, float3(0.25, 0.25, 0.25), d, 1);
}
else
{
T = ComputeTransmittanceJimenez(_HalfRcpVarianceAndWeight1.rgb,
_HalfRcpVarianceAndWeight1.a,
_HalfRcpVarianceAndWeight2.rgb,
_HalfRcpVarianceAndWeight2.a,
float3(0.25, 0.25, 0.25), d, 1);
}
return float4(pow(T, 1.0 / 3) * _TransmissionTint.rgb, 1);
return float4(sqrt(T) * _TransmissionTint.rgb, 1);
}
ENDHLSL
}

24
Assets/ScriptableRenderPipeline/ShaderLibrary/CommonMaterial.hlsl


// Computes the fraction of light passing through the object.
// Evaluate Int{0, inf}{2 * Pi * r * R(sqrt(r^2 + d^2))}, where R is the diffusion profile.
// Note: 'volumeAlbedo' should be premultiplied by 0.25.
// Ref: Approximate Reflectance Profiles for Efficient Subsurface Scattering by Pixar (BSSRDF only).
float3 ComputeTransmittance(float3 S, float3 volumeAlbedo, float thickness, float radiusScale)
{

float3 expOneThird = exp(((-1.0 / 3.0) * thickness) * S);
return 0.25 * (expOneThird + 3 * expOneThird * expOneThird * expOneThird) * volumeAlbedo;
// Premultiply & optimize: T = (1/4 * A) * (e^(-t * S) + 3 * e^(-1/3 * t * S))
return volumeAlbedo * (expOneThird * expOneThird * expOneThird + 3 * expOneThird);
}
// Evaluates transmittance for a linear combination of two normalized 2D Gaussians.
// Ref: Real-Time Realistic Skin Translucency (2010), equation 9 (modified).
// Note: 'volumeAlbedo' should be premultiplied by 0.25, correspondingly 'lerpWeight' by 4,
// and 'halfRcpVariance1' should be prescaled by (0.1 * SssConstants.SSS_BASIC_DISTANCE_SCALE)^2.
float3 ComputeTransmittanceJimenez(float3 halfRcpVariance1, float lerpWeight1,
float3 halfRcpVariance2, float lerpWeight2,
float3 volumeAlbedo, float thickness, float radiusScale)
{
// Thickness and SSS radius are decoupled for artists.
// In theory, we should modify the thickness by the inverse of the radius scale of the profile.
// thickness /= radiusScale;
float t2 = thickness * thickness;
// T = A * lerp(exp(-t2 * halfRcpVariance1), exp(-t2 * halfRcpVariance2), lerpWeight2)
return volumeAlbedo * (exp(-t2 * halfRcpVariance1) * lerpWeight1 + exp(-t2 * halfRcpVariance2) * lerpWeight2);
return saturate((-NdotL + w) / ((1 + w) * (1 + w)));
return saturate((NdotL + w) / ((1 + w) * (1 + w)));
}
// MACRO from Legacy Untiy

正在加载...
取消
保存