Skip to content

Commit fe44644

Browse files
HDRenderPipeline: Repalce surface albedo + volume mean free path by scattering distance
1 parent fd38b8d commit fe44644

2 files changed

Lines changed: 39 additions & 34 deletions

File tree

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

Lines changed: 35 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public class SubsurfaceScatteringProfile : ScriptableObject
2323
public enum TexturingMode : uint { PreAndPostScatter = 0, PostScatter = 1 };
2424
public enum TransmissionMode : uint { None = SssConstants.SSS_TRSM_MODE_NONE, ThinObject = SssConstants.SSS_TRSM_MODE_THIN, Regular };
2525

26-
public Color surfaceAlbedo; // Color, 0 to 1
26+
[ColorUsageAttribute(false, true, 0f, 8f, 0.125f, 3f)]
27+
public Color scatteringDistance; // HDR Color (similar to length of volume mean free path in mm (but it is not))
2728
public Color volumeAlbedo; // Color, 0 to 1
2829
public float lenVolMeanFreePath; // Length of the volume mean free path (in millimeters)
2930
public TexturingMode texturingMode;
@@ -37,7 +38,7 @@ public enum TransmissionMode : uint { None = SssConstants.SSS_TRSM_MODE_NONE, Th
3738
[SerializeField]
3839
Vector3 m_VolumeShapeParam; // RGB = shape parameter: S = 1 / D
3940
[SerializeField]
40-
float m_ScatteringDistance; // Filter radius (in millimeters)
41+
float m_KernelSize; // Filter radius (in millimeters)
4142
[SerializeField]
4243
Vector2[] m_FilterKernelNearField; // X = radius, Y = reciprocal of the PDF
4344
[SerializeField]
@@ -47,7 +48,7 @@ public enum TransmissionMode : uint { None = SssConstants.SSS_TRSM_MODE_NONE, Th
4748

4849
public SubsurfaceScatteringProfile()
4950
{
50-
surfaceAlbedo = Color.white;
51+
scatteringDistance = Color.white;
5152
volumeAlbedo = Color.white;
5253
lenVolMeanFreePath = 0.5f;
5354
texturingMode = TexturingMode.PreAndPostScatter;
@@ -75,20 +76,17 @@ public void BuildKernel()
7576
m_SurfaceShapeParam = new Vector3();
7677

7778
// Evaluate the fit for diffuse surface transmission.
78-
m_SurfaceShapeParam.x = FindFitForS(surfaceAlbedo.r);
79-
m_SurfaceShapeParam.y = FindFitForS(surfaceAlbedo.g);
80-
m_SurfaceShapeParam.z = FindFitForS(surfaceAlbedo.b);
79+
// We substitute s = 1 / d in all formulas. so s = m_SurfaceShapeParam
8180
m_VolumeShapeParam.x = FindFitForS(volumeAlbedo.r);
8281
m_VolumeShapeParam.y = FindFitForS(volumeAlbedo.g);
8382
m_VolumeShapeParam.z = FindFitForS(volumeAlbedo.b);
8483

8584
// Compute { 1 / D = S / L } as you can substitute s = 1 / d in all formulas.
86-
m_SurfaceShapeParam *= 1.0f / lenVolMeanFreePath;
8785
m_VolumeShapeParam *= 1.0f / lenVolMeanFreePath;
8886

89-
// We importance sample the color channel with the highest albedo value,
87+
// We importance sample the color channel with the highest s value,
9088
// since higher albedo values result in scattering over a larger distance.
91-
// S(A) is a monotonically decreasing function.
89+
// s is a monotonically decreasing function.
9290
float s = Mathf.Min(m_SurfaceShapeParam.x, m_SurfaceShapeParam.y, m_SurfaceShapeParam.z);
9391

9492
// Importance sample the normalized diffusion profile for the computed value of 's'.
@@ -110,7 +108,7 @@ public void BuildKernel()
110108
m_FilterKernelNearField[i].y = 1.0f / KernelPdf(r, s);
111109
}
112110

113-
m_ScatteringDistance = m_FilterKernelNearField[SssConstants.SSS_N_SAMPLES_NEAR_FIELD - 1].x;
111+
m_KernelSize = m_FilterKernelNearField[SssConstants.SSS_N_SAMPLES_NEAR_FIELD - 1].x;
114112

115113
// Importance sample the far field kernel.
116114
for (int i = 0; i < SssConstants.SSS_N_SAMPLES_FAR_FIELD; i++)
@@ -137,10 +135,10 @@ public Vector3 volumeShapeParameter
137135
get { return m_VolumeShapeParam; }
138136
}
139137

140-
public float scatteringDistance
138+
public float kernelSize
141139
{
142140
// Set in BuildKernel().
143-
get { return m_ScatteringDistance; }
141+
get { return m_KernelSize; }
144142
}
145143

146144
public Vector2[] filterKernelNearField
@@ -348,7 +346,7 @@ public void UpdateCache()
348346
thicknessRemaps[2 * i + 1] = profiles[i].thicknessRemap.y - profiles[i].thicknessRemap.x;
349347
worldScales[i] = profiles[i].worldScale;
350348
surfaceShapeParams[i] = profiles[i].surfaceShapeParameter;
351-
surfaceShapeParams[i].w = profiles[i].scatteringDistance;
349+
surfaceShapeParams[i].w = profiles[i].kernelSize;
352350
volumeShapeParams[i] = profiles[i].volumeShapeParameter;
353351
volumeAlbedos[i] = profiles[i].volumeAlbedo;
354352

@@ -441,10 +439,10 @@ private class Styles
441439
public readonly GUIContent sssTransmittancePreview0 = new GUIContent("Transmittance Preview");
442440
public readonly GUIContent sssTransmittancePreview1 = new GUIContent("Shows the fraction of light passing through the object for thickness values from the remap.");
443441
public readonly GUIContent sssTransmittancePreview2 = new GUIContent("Can be viewed as a cross section of a slab of material illuminated by white light from the left.");
444-
public readonly GUIContent sssProfileSurfaceAlbedo = new GUIContent("Surface Albedo", "Color which determines the shape of the profile. Alpha is ignored. Typically, it is similar to the diffuse color.");
442+
public readonly GUIContent sssProfileScatteringDistance = new GUIContent("Scattering distance", "Color which determines the shape of the profile. Alpha is ignored. Typically, it is desired subsurface color.");
445443
public readonly GUIContent sssProfileVolumeAlbedo = new GUIContent("Volume Albedo", "Color which tints transmitted light. Alpha is ignored. Typically, it is a more saturated version of the diffuse color.");
446444
public readonly GUIContent sssProfileLenVolMeanFreePath = new GUIContent("Volume Mean Free Path", "The length of the volume mean free path (in millimeters) describes the average distance a photon travels within the volume before an extinction event occurs. Determines the effective radius of the filter.");
447-
public readonly GUIContent sssProfileScatteringDistance = new GUIContent("Scattering Distance", "Effective radius of the filter (in millimeters). The blur is energy-preserving, so a wide filter results in a large area with small contributions of individual samples. Reducing the distance increases the sharpness of the result.");
445+
public readonly GUIContent sssProfileKernelSize = new GUIContent("Kernel size", "Effective radius of the filter (in millimeters). The blur is energy-preserving, so a wide filter results in a large area with small contributions of individual samples. Reducing the distance increases the sharpness of the result.");
448446
public readonly GUIContent sssTexturingMode = new GUIContent("Texturing Mode", "Specifies when the diffuse texture should be applied.");
449447
public readonly GUIContent[] sssTexturingModeOptions = new GUIContent[2]
450448
{
@@ -464,6 +462,10 @@ private class Styles
464462

465463
public readonly GUIStyle centeredMiniBoldLabel = new GUIStyle(GUI.skin.label);
466464

465+
public readonly GUIContent SSSText = new GUIContent("Subsurface scattering options", "Subsurface scattering options");
466+
public readonly GUIContent transmissionText = new GUIContent("Transmission options", "Transmission options");
467+
468+
467469
public Styles()
468470
{
469471
centeredMiniBoldLabel.alignment = TextAnchor.MiddleCenter;
@@ -488,15 +490,15 @@ private static Styles styles
488490

489491
private RenderTexture m_ProfileImage, m_TransmittanceImage;
490492
private Material m_ProfileMaterial, m_TransmittanceMaterial;
491-
private SerializedProperty m_LenVolMeanFreePath, m_ScatteringDistance, m_SurfaceAlbedo, m_VolumeAlbedo, m_SurfaceShapeParam, m_VolumeShapeParam,
493+
private SerializedProperty m_LenVolMeanFreePath, m_KernelSize, m_ScatteringDistance, m_VolumeAlbedo, m_SurfaceShapeParam, m_VolumeShapeParam,
492494
m_TexturingMode, m_TransmissionMode, m_ThicknessRemap, m_WorldScale;
493495

494496
void OnEnable()
495497
{
496-
m_SurfaceAlbedo = serializedObject.FindProperty("surfaceAlbedo");
498+
m_ScatteringDistance = serializedObject.FindProperty("scatteringDistance");
497499
m_VolumeAlbedo = serializedObject.FindProperty("volumeAlbedo");
498500
m_LenVolMeanFreePath = serializedObject.FindProperty("lenVolMeanFreePath");
499-
m_ScatteringDistance = serializedObject.FindProperty("m_ScatteringDistance");
501+
m_KernelSize = serializedObject.FindProperty("m_KernelSize");
500502
m_SurfaceShapeParam = serializedObject.FindProperty("m_SurfaceShapeParam");
501503
m_VolumeShapeParam = serializedObject.FindProperty("m_VolumeShapeParam");
502504
m_TexturingMode = serializedObject.FindProperty("texturingMode");
@@ -518,22 +520,27 @@ public override void OnInspectorGUI()
518520

519521
EditorGUI.BeginChangeCheck();
520522
{
521-
EditorGUILayout.PropertyField(m_SurfaceAlbedo, styles.sssProfileSurfaceAlbedo);
522-
m_LenVolMeanFreePath.floatValue = EditorGUILayout.Slider(styles.sssProfileLenVolMeanFreePath, m_LenVolMeanFreePath.floatValue, 0.01f, 1.0f);
523-
523+
GUILayout.Label(styles.SSSText, EditorStyles.boldLabel);
524+
EditorGUI.indentLevel++;
525+
EditorGUILayout.PropertyField(m_ScatteringDistance, styles.sssProfileScatteringDistance);
524526
GUI.enabled = false;
525-
EditorGUILayout.PropertyField(m_ScatteringDistance, styles.sssProfileScatteringDistance);
527+
EditorGUILayout.PropertyField(m_KernelSize, styles.sssProfileKernelSize);
526528
GUI.enabled = true;
529+
m_TexturingMode.intValue = EditorGUILayout.Popup(styles.sssTexturingMode, m_TexturingMode.intValue, styles.sssTexturingModeOptions);
530+
EditorGUI.indentLevel--;
527531

528-
m_TexturingMode.intValue = EditorGUILayout.Popup(styles.sssTexturingMode, m_TexturingMode.intValue, styles.sssTexturingModeOptions);
532+
GUILayout.Label(styles.transmissionText, EditorStyles.boldLabel);
533+
EditorGUI.indentLevel++;
529534
m_TransmissionMode.intValue = EditorGUILayout.Popup(styles.sssProfileTransmissionMode, m_TransmissionMode.intValue, styles.sssTransmissionModeOptions);
530535

531536
EditorGUILayout.PropertyField(m_VolumeAlbedo, styles.sssProfileVolumeAlbedo);
537+
m_LenVolMeanFreePath.floatValue = EditorGUILayout.Slider(styles.sssProfileLenVolMeanFreePath, m_LenVolMeanFreePath.floatValue, 0.01f, 1.0f);
532538
EditorGUILayout.PropertyField(m_ThicknessRemap, styles.sssProfileMinMaxThickness);
533539
Vector2 thicknessRemap = m_ThicknessRemap.vector2Value;
534540
EditorGUILayout.MinMaxSlider(styles.sssProfileThicknessRemap, ref thicknessRemap.x, ref thicknessRemap.y, 0.0f, 50.0f);
535541
m_ThicknessRemap.vector2Value = thicknessRemap;
536542
EditorGUILayout.PropertyField(m_WorldScale, styles.sssProfileWorldScale);
543+
EditorGUI.indentLevel--;
537544

538545
EditorGUILayout.Space();
539546
EditorGUILayout.LabelField(styles.sssProfilePreview0, styles.centeredMiniBoldLabel);
@@ -543,18 +550,16 @@ public override void OnInspectorGUI()
543550
EditorGUILayout.Space();
544551
}
545552

546-
float d = m_ScatteringDistance.floatValue;
547-
Vector4 aS = m_SurfaceAlbedo.colorValue;
553+
float d = m_KernelSize.floatValue;
548554
Vector4 aV = m_VolumeAlbedo.colorValue;
549-
Vector3 sS = m_SurfaceShapeParam.vector3Value;
555+
Vector3 sD = m_SurfaceShapeParam.vector3Value;
550556
Vector3 sV = m_VolumeShapeParam.vector3Value;
551557
Vector2 R = m_ThicknessRemap.vector2Value;
552558
bool transmissionEnabled = m_TransmissionMode.intValue != (int)SubsurfaceScatteringProfile.TransmissionMode.None;
553559

554560
// Draw the profile.
555-
m_ProfileMaterial.SetFloat("_ScatteringDistance", d);
556-
m_ProfileMaterial.SetVector("_SurfaceAlbedo", aS);
557-
m_ProfileMaterial.SetVector("_SurfaceShapeParam", sS);
561+
m_ProfileMaterial.SetFloat("_KernelSize", d);
562+
m_ProfileMaterial.SetVector("_SurfaceShapeParam", sD);
558563
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(256, 256), m_ProfileImage, m_ProfileMaterial, ScaleMode.ScaleToFit, 1.0f);
559564

560565
EditorGUILayout.Space();
@@ -564,7 +569,7 @@ public override void OnInspectorGUI()
564569
EditorGUILayout.Space();
565570

566571
// Draw the transmittance graph.
567-
m_TransmittanceMaterial.SetFloat("_ScatteringDistance", d);
572+
m_TransmittanceMaterial.SetFloat("_KernelSize", d);
568573
m_TransmittanceMaterial.SetVector("_VolumeAlbedo", transmissionEnabled ? aV : Vector4.zero);
569574
m_TransmittanceMaterial.SetVector("_VolumeShapeParam", sV);
570575
m_TransmittanceMaterial.SetVector("_ThicknessRemap", R);

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ Shader "Hidden/HDRenderPipeline/DrawSssProfile"
2727
// Inputs & outputs
2828
//-------------------------------------------------------------------------------------
2929

30-
float4 _SurfaceAlbedo, _SurfaceShapeParam;
31-
float _ScatteringDistance; // See 'SubsurfaceScatteringProfile'
30+
float4 _SurfaceShapeParam;
31+
float _KernelSize; // See 'SubsurfaceScatteringProfile'
3232

3333
//-------------------------------------------------------------------------------------
3434
// Implementation
@@ -56,13 +56,13 @@ Shader "Hidden/HDRenderPipeline/DrawSssProfile"
5656

5757
float4 Frag(Varyings input) : SV_Target
5858
{
59-
float r = (2 * length(input.texcoord - 0.5)) * _ScatteringDistance;
59+
float r = (2 * length(input.texcoord - 0.5)) * _KernelSize;
6060
float3 S = _SurfaceShapeParam.rgb;
6161
float3 M = S * (exp(-r * S) + exp(-r * S * (1.0 / 3.0))) / (8 * PI * r);
6262

6363
// N.b.: we multiply by the surface albedo of the actual geometry during shading.
6464
// Apply gamma for visualization only. Do not apply gamma to the color.
65-
return float4(pow(M, 1.0 / 3.0) * _SurfaceAlbedo.rgb, 1);
65+
return float4(pow(M, 1.0 / 3.0), 1);
6666
}
6767
ENDHLSL
6868
}

0 commit comments

Comments
 (0)