浏览代码

Make the SSS texturing mode a profile-local property

/fptl_cleanup
Evgenii Golubev 8 年前
当前提交
ced19359
共有 7 个文件被更改,包括 87 次插入103 次删除
  1. 9
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs
  2. 19
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  3. 19
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  4. 15
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader
  5. 121
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs
  6. 5
      Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl
  7. 2
      ProjectSettings/ProjectVersion.txt

9
Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs


// Subsurface Scattering Settings
public readonly GUIContent[] sssProfiles = new GUIContent[SubsurfaceScatteringSettings.maxNumProfiles] { new GUIContent("Profile #0"), new GUIContent("Profile #1"), new GUIContent("Profile #2"), new GUIContent("Profile #3"), new GUIContent("Profile #4"), new GUIContent("Profile #5"), new GUIContent("Profile #6"), new GUIContent("Profile #7") };
public readonly GUIContent sssNumProfiles = new GUIContent("Number of profiles");
public readonly GUIContent sssTexturingMode = new GUIContent("Texturing mode", "Specifies when the diffuse texture should be applied.");
public readonly GUIContent[] sssTexturingModeOptions = new GUIContent[3] { new GUIContent("Pre-scatter", "Before the blurring pass. Effectively results in the diffuse texture getting blurred together with the lighting."), new GUIContent("Post-scatter", "After the blurring pass. Effectively preserves the sharpness of the diffuse texture."), new GUIContent("Pre- and post-scatter", "Both before and after the blurring pass.") };
// Tile pass Settings
public readonly GUIContent tileLightLoopSettings = new GUIContent("Tile Light Loop Settings");

SerializedProperty m_RenderingUseDepthPrepass = null;
// Subsurface Scattering Settings
SerializedProperty m_TexturingMode = null;
SerializedProperty m_Profiles = null;
SerializedProperty m_NumProfiles = null;

m_RenderingUseDepthPrepass = FindProperty(x => x.renderingSettings.useDepthPrepass);
// Subsurface Scattering Settings
m_TexturingMode = FindProperty(x => x.sssSettings.texturingMode);
m_Profiles = FindProperty(x => x.sssSettings.profiles);
m_NumProfiles = m_Profiles.FindPropertyRelative("Array.size");
m_Profiles = FindProperty(x => x.sssSettings.profiles);
m_NumProfiles = m_Profiles.FindPropertyRelative("Array.size");
}
SerializedProperty FindProperty<TValue>(Expression<Func<HDRenderPipeline, TValue>> expr)

EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_NumProfiles, styles.sssNumProfiles);
m_TexturingMode.intValue = EditorGUILayout.Popup(styles.sssTexturingMode, m_TexturingMode.intValue, styles.sssTexturingModeOptions, (GUILayoutOption[])null);
for (int i = 0, n = Math.Min(m_Profiles.arraySize, SubsurfaceScatteringSettings.maxNumProfiles); i < n; i++)
{

19
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


}
// Broadcast SSS parameters to all shaders.
Shader.SetGlobalInt("_TransmissionFlags", sssParameters.transmissionFlags);
Shader.SetGlobalInt("_TransmissionFlags", sssParameters.transmissionFlags);
Shader.SetGlobalInt("_TexturingModeFlags", sssParameters.texturingModeFlags);
switch (sssParameters.texturingMode)
{
case SubsurfaceScatteringSettings.TexturingMode.PreScatter:
cmd.EnableShaderKeyword("SSS_PRE_SCATTER_TEXTURING");
cmd.DisableShaderKeyword("SSS_POST_SCATTER_TEXTURING");
break;
case SubsurfaceScatteringSettings.TexturingMode.PostScatter:
cmd.DisableShaderKeyword("SSS_PRE_SCATTER_TEXTURING");
cmd.EnableShaderKeyword("SSS_POST_SCATTER_TEXTURING");
break;
case SubsurfaceScatteringSettings.TexturingMode.PreAndPostScatter:
cmd.DisableShaderKeyword("SSS_PRE_SCATTER_TEXTURING");
cmd.DisableShaderKeyword("SSS_POST_SCATTER_TEXTURING");
break;
}
if (globalDebugSettings.renderingDebugSettings.enableSSS)
{

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


// SSS parameters
#define SSS_N_PROFILES 8
#define SSS_UNIT_CONVERSION (1.0 / 300.0) // From meters to 1/3 centimeters
uint _TransmissionFlags; // One bit per profile; 1 = enabled
uint _TransmissionFlags; // 1 bit/profile; 0 = inf. thick, 1 = supports transmission
uint _TexturingModeFlags; // 1 bit/profile; 0 = PreAndPostScatter, 1 = PostScatter
float _ThicknessRemaps[SSS_N_PROFILES][2]; // Remap: 0 = start, 1 = end - start
float4 _HalfRcpVariancesAndLerpWeights[SSS_N_PROFILES][2]; // 2x Gaussians per color channel, A is the the associated interpolation weight

void ConfigureTexturingForSSS(inout BSDFData bsdfData)
{
#ifdef SSS_PRE_SCATTER_TEXTURING
bsdfData.diffuseColor = bsdfData.diffuseColor;
#elif SSS_POST_SCATTER_TEXTURING
bsdfData.diffuseColor = float3(1, 1, 1);
#else // combine pre-scatter and post-scatter texturing
bsdfData.diffuseColor = sqrt(bsdfData.diffuseColor);
#endif
bool performPostScatterTexturing = IsBitSet(_TexturingModeFlags, bsdfData.subsurfaceProfile);
// It's either post-scatter, or pre- and post-scatter texturing.
bsdfData.diffuseColor = performPostScatterTexturing ? float3(1, 1, 1)
: sqrt(bsdfData.diffuseColor);
}
// Evaluates transmittance for a linear combination of two normalized 2D Gaussians.

bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * surfaceData.subsurfaceRadius;
bsdfData.thickness = SSS_UNIT_CONVERSION * (_ThicknessRemaps[bsdfData.subsurfaceProfile][0] +
_ThicknessRemaps[bsdfData.subsurfaceProfile][1] * surfaceData.thickness);
bsdfData.enableTransmission = (1 << bsdfData.subsurfaceProfile) & _TransmissionFlags;
bsdfData.enableTransmission = IsBitSet(_TransmissionFlags, bsdfData.subsurfaceProfile);
if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance(_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].xyz,

bsdfData.subsurfaceRadius = SSS_UNIT_CONVERSION * inGBuffer2.r;
bsdfData.thickness = SSS_UNIT_CONVERSION * (_ThicknessRemaps[bsdfData.subsurfaceProfile][0] +
_ThicknessRemaps[bsdfData.subsurfaceProfile][1] * inGBuffer2.g);
bsdfData.enableTransmission = (1 << bsdfData.subsurfaceProfile) & _TransmissionFlags;
bsdfData.enableTransmission = IsBitSet(_TransmissionFlags, bsdfData.subsurfaceProfile);
if (bsdfData.enableTransmission)
{
bsdfData.transmittance = ComputeTransmittance(_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].xyz,

15
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader


totalWeight += sampleWeight;
}
#ifdef SSS_PRE_SCATTER_TEXTURING
float3 diffuseContrib = float3(1, 1, 1);
#elif SSS_POST_SCATTER_TEXTURING
float3 diffuseColor = DecodeGBuffer0(LOAD_TEXTURE2D(_GBufferTexture0, posInput.unPositionSS)).rgb;
float3 diffuseContrib = diffuseColor;
#else // combine pre-scatter and post-scatter texturing
float3 diffuseColor = DecodeGBuffer0(LOAD_TEXTURE2D(_GBufferTexture0, posInput.unPositionSS)).rgb;
float3 diffuseContrib = sqrt(diffuseColor);
#endif
#ifdef FILTER_HORIZONTAL_AND_COMBINE
bool performPostScatterTexturing = IsBitSet(_TexturingModeFlags, profileID);
#ifdef FILTER_HORIZONTAL_AND_COMBINE
// It's either post-scatter, or pre- and post-scatter texturing.
float3 diffuseContrib = performPostScatterTexturing ? bsdfData.diffuseColor
: sqrt(bsdfData.diffuseColor);
return float4(diffuseContrib * totalIrradiance / totalWeight, 1.0);
#else
return float4(totalIrradiance / totalWeight, 1.0);

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


[Serializable]
public class SubsurfaceScatteringProfile : ScriptableObject
{
public enum TexturingMode : int { PreAndPostScatter = 0, PostScatter = 1 };
[SerializeField, ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)]
public Color stdDev1;
[SerializeField, ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)]
public Color stdDev2;
[ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)]
public Color stdDev1;
[ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)]
public Color stdDev2;
public float lerpWeight;
public TexturingMode texturingMode;
public bool enableTransmission;
public Vector2 thicknessRemap;
[HideInInspector]
public int settingsIndex;
public float lerpWeight;
Vector4[] m_FilterKernel;
public bool enableTransmission;
Vector3[] m_HalfRcpVariances;
public Vector2 thicknessRemap;
[SerializeField] [HideInInspector]
public int settingsIndex;
[SerializeField] [HideInInspector]
Vector4[] m_FilterKernel;
[SerializeField] [HideInInspector]
Vector3[] m_HalfRcpVariances;
[SerializeField] [HideInInspector]
Vector4 m_HalfRcpWeightedVariances;
Vector4 m_HalfRcpWeightedVariances;
// --- Public Methods ---

stdDev2 = new Color(0.6f, 0.6f, 0.6f, 0.0f);
lerpWeight = 0.5f;
texturingMode = TexturingMode.PreAndPostScatter;
enableTransmission = false;
thicknessRemap = new Vector2(0, 1);
settingsIndex = SubsurfaceScatteringSettings.neutralProfileID; // Updated by SubsurfaceScatteringSettings.OnValidate() once assigned

[Serializable]
public class SubsurfaceScatteringSettings
{
public enum TexturingMode : int { PreScatter = 0, PostScatter = 1, PreAndPostScatter = 2, MaxValue = 2 };
public TexturingMode texturingMode;
public int transmissionFlags;
[NonSerialized] public int texturingModeFlags; // 0 = PreAndPostScatter, 1 = PostScatter
[NonSerialized] public int transmissionFlags; // 0 = inf. thick, 1 = supports transmission
[NonSerialized] public float[] thicknessRemaps;
[NonSerialized] public Vector4[] halfRcpVariancesAndLerpWeights;
[NonSerialized] public Vector4[] halfRcpWeightedVariances;

numProfiles = 1;
profiles = new SubsurfaceScatteringProfile[numProfiles];
profiles[0] = null;
texturingMode = TexturingMode.PreScatter;
texturingModeFlags = 0;
transmissionFlags = 0;
thicknessRemaps = null;
halfRcpVariancesAndLerpWeights = null;
halfRcpWeightedVariances = null;

}
}
texturingMode = (TexturingMode)Math.Max(0, Math.Min((int)texturingMode, (int)TexturingMode.MaxValue));
if (thicknessRemaps == null || thicknessRemaps.Length != (maxNumProfiles * 2))
{
thicknessRemaps = new float[maxNumProfiles * 2];

filterKernels = new Vector4[maxNumProfiles * SubsurfaceScatteringProfile.numSamples];
}
transmissionFlags = 0;
Color c = new Color();
for (int i = 0; i < numProfiles; i++)

transmissionFlags |= (profiles[i].enableTransmission ? 1 : 0) << i;
c.r = Mathf.Clamp(profiles[i].stdDev1.r, 0.05f, 2.0f);
c.g = Mathf.Clamp(profiles[i].stdDev1.g, 0.05f, 2.0f);
c.b = Mathf.Clamp(profiles[i].stdDev1.b, 0.05f, 2.0f);

profiles[i].UpdateKernelAndVarianceData();
}
texturingModeFlags = 0;
transmissionFlags = 0;
texturingModeFlags |= ((int)profiles[i].texturingMode) << i;
transmissionFlags |= (profiles[i].enableTransmission ? 1 : 0) << i;
thicknessRemaps[2 * i] = profiles[i].thicknessRemap.x;
thicknessRemaps[2 * i + 1] = profiles[i].thicknessRemap.y - profiles[i].thicknessRemap.x;

public class SubsurfaceScatteringProfileEditor : Editor {
private class Styles
{
public readonly GUIContent sssProfilePreview0 = new GUIContent("Profile preview");
public readonly GUIContent sssProfilePreview1 = new GUIContent("Shows the fraction of light scattered from the source as radius increases to 1.");
public readonly GUIContent sssProfilePreview2 = new GUIContent("Note that the intensity of the region in the center may be clamped.");
public readonly GUIContent sssTransmittancePreview0 = new GUIContent("Transmittance preview");
public readonly GUIContent sssTransmittancePreview1 = new GUIContent("Shows the fraction of light passing through the object as thickness increases to 1.");
public readonly GUIContent sssProfileStdDev1 = new GUIContent("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.");
public readonly GUIContent sssProfileStdDev2 = new GUIContent("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.");
public readonly GUIContent sssProfileLerpWeight = new GUIContent("Filter interpolation", "Controls linear interpolation between the two Gaussian filters.");
public readonly GUIContent sssProfileTransmission = new GUIContent("Enable transmission", "Toggles simulation of light passing through thin objects. Depends on the thickness of the material.");
public readonly GUIContent sssProfileThicknessRemap = new GUIContent("Thickness remap", "Remaps the thickness parameter from [0, 1] to the desired range.");
public readonly GUIContent sssProfilePreview0 = new GUIContent("Profile preview");
public readonly GUIContent sssProfilePreview1 = new GUIContent("Shows the fraction of light scattered from the source as radius increases to 1.");
public readonly GUIContent sssProfilePreview2 = new GUIContent("Note that the intensity of the region in the center may be clamped.");
public readonly GUIContent sssTransmittancePreview0 = new GUIContent("Transmittance preview");
public readonly GUIContent sssTransmittancePreview1 = new GUIContent("Shows the fraction of light passing through the object as thickness increases to 1.");
public readonly GUIContent sssProfileStdDev1 = new GUIContent("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.");
public readonly GUIContent sssProfileStdDev2 = new GUIContent("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.");
public readonly GUIContent sssProfileLerpWeight = new GUIContent("Filter interpolation", "Controls linear interpolation between the two Gaussian filters.");
public readonly GUIContent sssTexturingMode = new GUIContent("Texturing mode", "Specifies when the diffuse texture should be applied.");
public readonly GUIContent[] sssTexturingModeOptions = new GUIContent[2] { new GUIContent("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."),
new GUIContent("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).") };
public readonly GUIContent sssProfileTransmission = new GUIContent("Enable transmission", "Toggles simulation of light passing through thin objects. Depends on the thickness of the material.");
public readonly GUIContent sssProfileThicknessRemap = new GUIContent("Thickness remap", "Remaps the thickness parameter from [0, 1] to the desired range.");
public readonly GUIStyle centeredMiniBoldLabel = new GUIStyle(GUI.skin.label);
public readonly GUIStyle centeredMiniBoldLabel = new GUIStyle(GUI.skin.label);
public Styles()
{

private static Styles s_Styles = null;
private RenderTexture m_ProfileImage, m_TransmittanceImage;
private RenderTexture m_ProfileImage, m_TransmittanceImage;
private SerializedProperty m_ProfileStdDev1, m_ProfileStdDev2,
m_ProfileLerpWeight, m_ProfileTransmission,
m_ProfileThicknessRemap;
private SerializedProperty m_StdDev1, m_StdDev2, m_LerpWeight,
m_TexturingMode, m_Transmission, m_ThicknessRemap;
m_ProfileStdDev1 = serializedObject.FindProperty("stdDev1");
m_ProfileStdDev2 = serializedObject.FindProperty("stdDev2");
m_ProfileLerpWeight = serializedObject.FindProperty("lerpWeight");
m_ProfileTransmission = serializedObject.FindProperty("enableTransmission");
m_ProfileThicknessRemap = serializedObject.FindProperty("thicknessRemap");
m_StdDev1 = serializedObject.FindProperty("stdDev1");
m_StdDev2 = serializedObject.FindProperty("stdDev2");
m_LerpWeight = serializedObject.FindProperty("lerpWeight");
m_TexturingMode = serializedObject.FindProperty("texturingMode");
m_Transmission = serializedObject.FindProperty("enableTransmission");
m_ThicknessRemap = serializedObject.FindProperty("thicknessRemap");
m_ProfileMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawGaussianProfile");
m_TransmittanceMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawTransmittanceGraph");

EditorGUI.BeginChangeCheck();
{
EditorGUILayout.PropertyField(m_ProfileStdDev1, styles.sssProfileStdDev1);
EditorGUILayout.PropertyField(m_ProfileStdDev2, styles.sssProfileStdDev2);
EditorGUILayout.PropertyField(m_ProfileLerpWeight, styles.sssProfileLerpWeight);
EditorGUILayout.PropertyField(m_ProfileTransmission, styles.sssProfileTransmission);
EditorGUILayout.PropertyField(m_StdDev1, styles.sssProfileStdDev1);
EditorGUILayout.PropertyField(m_StdDev2, styles.sssProfileStdDev2);
EditorGUILayout.PropertyField(m_LerpWeight, styles.sssProfileLerpWeight);
m_TexturingMode.intValue = EditorGUILayout.Popup(styles.sssTexturingMode, m_TexturingMode.intValue, styles.sssTexturingModeOptions);
EditorGUILayout.PropertyField(m_Transmission, styles.sssProfileTransmission);
Vector2 thicknessRemap = m_ProfileThicknessRemap.vector2Value;
Vector2 thicknessRemap = m_ThicknessRemap.vector2Value;
m_ProfileThicknessRemap.vector2Value = thicknessRemap;
m_ThicknessRemap.vector2Value = thicknessRemap;
EditorGUILayout.Space();
EditorGUILayout.LabelField(styles.sssProfilePreview0, styles.centeredMiniBoldLabel);

}
// Draw the profile.
m_ProfileMaterial.SetColor("_StdDev1", m_ProfileStdDev1.colorValue);
m_ProfileMaterial.SetColor("_StdDev2", m_ProfileStdDev2.colorValue);
m_ProfileMaterial.SetFloat("_LerpWeight", m_ProfileLerpWeight.floatValue);
m_ProfileMaterial.SetColor("_StdDev1", m_StdDev1.colorValue);
m_ProfileMaterial.SetColor("_StdDev2", m_StdDev2.colorValue);
m_ProfileMaterial.SetFloat("_LerpWeight", m_LerpWeight.floatValue);
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(256, 256), m_ProfileImage, m_ProfileMaterial, ScaleMode.ScaleToFit, 1.0f);
EditorGUILayout.Space();

// Draw the transmittance graph.
m_TransmittanceMaterial.SetColor("_StdDev1", m_ProfileStdDev1.colorValue);
m_TransmittanceMaterial.SetColor("_StdDev2", m_ProfileStdDev2.colorValue);
m_TransmittanceMaterial.SetFloat("_LerpWeight", m_ProfileLerpWeight.floatValue);
m_TransmittanceMaterial.SetVector("_ThicknessRemap", m_ProfileThicknessRemap.vector2Value);
m_TransmittanceMaterial.SetColor("_StdDev1", m_StdDev1.colorValue);
m_TransmittanceMaterial.SetColor("_StdDev2", m_StdDev2.colorValue);
m_TransmittanceMaterial.SetFloat("_LerpWeight", m_LerpWeight.floatValue);
m_TransmittanceMaterial.SetVector("_ThicknessRemap", m_ThicknessRemap.vector2Value);
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(16, 16), m_TransmittanceImage, m_TransmittanceMaterial, ScaleMode.ScaleToFit, 16.0f);
serializedObject.ApplyModifiedProperties();

5
Assets/ScriptableRenderPipeline/ShaderLibrary/Common.hlsl


}
#endif // INTRINSIC_BITFIELD_EXTRACT
bool IsBitSet(uint number, uint bitPos)
{
return ((number >> bitPos) & 1) != 0;
}
#ifndef INTRINSIC_CLAMP
// TODO: should we force all clamp to be intrinsic by default ?
// Some platform have one instruction clamp

2
ProjectSettings/ProjectVersion.txt


m_EditorVersion: 2017.1.0a5
m_EditorVersion: 2017.1.0a6
正在加载...
取消
保存