浏览代码

Add the old SSS model back

/RenderPassXR_Sandbox
Evgenii Golubev 7 年前
当前提交
d238793c
共有 9 个文件被更改,包括 598 次插入50 次删除
  1. 9
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Editor/HDRenderPipelineInspector.cs
  2. 49
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  3. 1
      Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipelineAsset.asset
  4. 115
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/CombineSubsurfaceScattering.shader
  5. 128
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SSSProfile/SkinSSSProfile.asset
  6. 311
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs
  7. 2
      Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringProfile.cs.hlsl
  8. 25
      Assets/ScriptableRenderPipeline/HDRenderPipeline/SceneSettings/Resources/DrawSssProfile.shader
  9. 8
      Assets/TestScenes/HDTest/GraphicTest/SSS/Materials/SSSHead.mat

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


SerializedProperty m_RenderingUseDepthPrepass = null;
// Subsurface Scattering Settings
// Old SSS Model >>>
SerializedProperty m_UseDisneySSS = null;
// <<< Old SSS Model
SerializedProperty m_Profiles = null;
SerializedProperty m_NumProfiles = null;

m_RenderingUseDepthPrepass = FindProperty(x => x.renderingSettings.useDepthPrepass);
// Subsurface Scattering Settings
// Old SSS Model >>>
m_UseDisneySSS = FindProperty(x => x.sssSettings.useDisneySSS);
// <<< Old SSS Model
m_Profiles = FindProperty(x => x.sssSettings.profiles);
m_NumProfiles = m_Profiles.FindPropertyRelative("Array.size");
}

EditorGUI.BeginChangeCheck();
// Old SSS Model >>>
EditorGUILayout.PropertyField(m_UseDisneySSS);
// <<< Old SSS Model
EditorGUILayout.PropertyField(m_NumProfiles, styles.sssNumProfiles);
for (int i = 0, n = m_Profiles.arraySize; i < n; i++)

49
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


// Various set of material use in render loop
readonly Material m_FilterAndCombineSubsurfaceScattering;
// Old SSS Model >>>
readonly Material m_FilterSubsurfaceScattering;
// <<< Old SSS Model
Material m_DebugViewMaterialGBuffer;
Material m_DebugDisplayLatlong;

// It is stored within 'm_CameraSubsurfaceBufferRT'.
readonly RenderTargetIdentifier m_CameraColorBufferRT;
readonly RenderTargetIdentifier m_CameraSubsurfaceBufferRT;
// Old SSS Model >>>
readonly RenderTargetIdentifier m_CameraFilteringBufferRT;
// <<< Old SSS Model
readonly RenderTargetIdentifier m_VelocityBufferRT;
readonly RenderTargetIdentifier m_DistortionBufferRT;

m_CameraSubsurfaceBufferRT = new RenderTargetIdentifier(m_CameraSubsurfaceBuffer);
m_FilterAndCombineSubsurfaceScattering = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/CombineSubsurfaceScattering");
// Old SSS Model >>>
m_CameraFilteringBufferRT = new RenderTargetIdentifier(m_CameraFilteringBuffer);
m_FilterSubsurfaceScattering = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/CombineSubsurfaceScattering");
m_FilterSubsurfaceScattering.DisableKeyword("SSS_FILTER_HORIZONTAL_AND_COMBINE");
m_FilterSubsurfaceScattering.SetFloat("_DstBlend", (float)BlendMode.Zero);
m_FilterAndCombineSubsurfaceScattering.EnableKeyword("SSS_FILTER_HORIZONTAL_AND_COMBINE");
m_FilterAndCombineSubsurfaceScattering.SetFloat("_DstBlend", (float)BlendMode.One);
// <<< Old SSS Model
InitializeDebugMaterials();

var cmd = new CommandBuffer() { name = "Subsurface Scattering" };
cmd.SetGlobalTexture("_IrradianceSource", m_CameraSubsurfaceBufferRT); // Cannot set a RT on a material
m_FilterAndCombineSubsurfaceScattering.SetVectorArray("_SurfaceShapeParams", sssParameters.surfaceShapeParams);
m_FilterAndCombineSubsurfaceScattering.SetFloatArray("_WorldScales", sssParameters.worldScales);
m_FilterAndCombineSubsurfaceScattering.SetFloatArray("_FilterKernelsNearField", sssParameters.filterKernelsNearField);
m_FilterAndCombineSubsurfaceScattering.SetFloatArray("_FilterKernelsFarField", sssParameters.filterKernelsFarField);
if (sssSettings.useDisneySSS)
{
Utilities.SelectKeyword(m_FilterAndCombineSubsurfaceScattering, "SSS_MODEL_DISNEY", "SSS_MODEL_BASIC", true);
cmd.SetGlobalTexture("_IrradianceSource", m_CameraSubsurfaceBufferRT); // Cannot set a RT on a material
m_FilterAndCombineSubsurfaceScattering.SetVectorArray("_SurfaceShapeParams", sssParameters.surfaceShapeParams);
m_FilterAndCombineSubsurfaceScattering.SetFloatArray("_WorldScales", sssParameters.worldScales);
m_FilterAndCombineSubsurfaceScattering.SetFloatArray("_FilterKernelsNearField", sssParameters.filterKernelsNearField);
m_FilterAndCombineSubsurfaceScattering.SetFloatArray("_FilterKernelsFarField", sssParameters.filterKernelsFarField);
Utilities.DrawFullScreen(cmd, m_FilterAndCombineSubsurfaceScattering, hdCamera, m_CameraColorBufferRT, m_CameraDepthStencilBufferRT);
Utilities.DrawFullScreen(cmd, m_FilterAndCombineSubsurfaceScattering, hdCamera, m_CameraColorBufferRT, m_CameraDepthStencilBufferRT);
}
else
{
Utilities.SelectKeyword(m_FilterSubsurfaceScattering, "SSS_MODEL_DISNEY", "SSS_MODEL_BASIC", false);
Utilities.SelectKeyword(m_FilterAndCombineSubsurfaceScattering, "SSS_MODEL_DISNEY", "SSS_MODEL_BASIC", false);
// Perform the vertical SSS filtering pass.
m_FilterSubsurfaceScattering.SetVectorArray("_FilterKernelsBasic", sssParameters.filterKernelsBasic);
m_FilterSubsurfaceScattering.SetVectorArray("_HalfRcpWeightedVariances", sssParameters.halfRcpWeightedVariances);
cmd.SetGlobalTexture("_IrradianceSource", m_CameraSubsurfaceBufferRT);
Utilities.DrawFullScreen(cmd, m_FilterSubsurfaceScattering, hdCamera, m_CameraFilteringBufferRT, m_CameraDepthStencilBufferRT);
// Perform the horizontal SSS filtering pass, and combine diffuse and specular lighting.
m_FilterAndCombineSubsurfaceScattering.SetVectorArray("_FilterKernelsBasic", sssParameters.filterKernelsBasic);
m_FilterAndCombineSubsurfaceScattering.SetVectorArray("_HalfRcpWeightedVariances", sssParameters.halfRcpWeightedVariances);
cmd.SetGlobalTexture("_IrradianceSource", m_CameraFilteringBufferRT);
Utilities.DrawFullScreen(cmd, m_FilterAndCombineSubsurfaceScattering, hdCamera, m_CameraColorBufferRT, m_CameraDepthStencilBufferRT);
}
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();

1
Assets/ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipelineAsset.asset


- {fileID: 11400000, guid: d6ee4403015766f4093158d69216c0bf, type: 2}
- {fileID: 11400000, guid: 906339bac2066fc4aa22a3652e1283ef, type: 2}
- {fileID: 0}
useDisneySSS: 1
tileSettings:
enableTileAndCluster: 1
enableSplitLightEvaluation: 1

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


Shader "Hidden/HDRenderPipeline/CombineSubsurfaceScattering"
{
// Old SSS Model >>>
// <<< Old SSS Model
SubShader
{

Cull Off
ZTest Always
ZWrite Off
Blend One One
// Old SSS Model >>>
Blend One [_DstBlend]
// <<< Old SSS Model
HLSLPROGRAM
#pragma target 4.5

#pragma vertex Vert
#pragma fragment Frag
// Old SSS Model >>>
#pragma multi_compile SSS_MODEL_BASIC SSS_MODEL_DISNEY
#pragma multi_compile _ SSS_FILTER_HORIZONTAL_AND_COMBINE
// <<< Old SSS Model
#ifdef SSS_MODEL_BASIC
#define CENTIMETERS_PER_METER 100
#define RBG_BILATERAL_WEIGHTS 0
#endif
//-------------------------------------------------------------------------------------
// Include

// Inputs & outputs
//-------------------------------------------------------------------------------------
float4 _SurfaceShapeParams[SSS_N_PROFILES]; // RGB = S = 1 / D, A = filter radius
#ifdef SSS_MODEL_DISNEY
float4 _SurfaceShapeParams[SSS_N_PROFILES]; // RGB = S = 1 / D, A = filter radius
#else
float4 _FilterKernelsBasic[SSS_N_PROFILES][SSS_BASIC_N_SAMPLES]; // RGB = weights, A = radial distance
float4 _HalfRcpWeightedVariances[SSS_BASIC_N_SAMPLES]; // RGB for chromatic, A for achromatic
#endif
TEXTURE2D(_IrradianceSource); // Includes transmitted light
DECLARE_GBUFFER_TEXTURE(_GBufferTexture); // Contains the albedo and SSS parameters

int profileID = bsdfData.subsurfaceProfile;
float distScale = bsdfData.subsurfaceRadius;
#ifdef SSS_MODEL_DISNEY
#else
float maxDistance = _FilterKernelsBasic[profileID][SSS_BASIC_N_SAMPLES - 1].a;
#endif
// Reconstruct the view-space position.
float2 centerPosSS = posInput.positionSS;

// Compute the view-space dimensions of the pixel as a quad projected onto geometry.
float2 unitsPerPixel = 2 * (cornerPosVS.xy - centerPosVS.xy);
#ifdef SSS_MODEL_DISNEY
float metersPerUnit = _WorldScales[profileID];
float millimPerUnit = MILLIMETERS_PER_METER * metersPerUnit;
float2 scaledPixPerMm = distScale * rcp(millimPerUnit * unitsPerPixel);

// We perform point sampling. Therefore, we can avoid the cost
// of filtering if we stay within the bounds of the current pixel.
// We use the value of 1 instead of 0.5 as an optimization.
if (maxDistInPixels < 1)
if (distScale == 0 || maxDistInPixels < 1)
{
#if SSS_DEBUG
return float4(0, 0, 1, 1);

totalIrradiance, totalWeight)
#endif
}
#else
float metersPerUnit = _WorldScales[profileID] * SSS_BASIC_DISTANCE_SCALE;
float centimPerUnit = CENTIMETERS_PER_METER * metersPerUnit;
float2 scaledPixPerCm = distScale * rcp(centimPerUnit * unitsPerPixel);
float unitScale = centimPerUnit / distScale;
// Compute the filtering direction.
#ifdef SSS_FILTER_HORIZONTAL_AND_COMBINE
float scaledStepSize = scaledPixPerCm.x;
float2 unitDirection = float2(1, 0);
#else
float scaledStepSize = scaledPixPerCm.y;
float2 unitDirection = float2(0, 1);
#endif
float2 scaledDirection = scaledPixPerCm * unitDirection;
float phi = 0; // Random rotation; unused for now
float2x2 rotationMatrix = float2x2(cos(phi), -sin(phi), sin(phi), cos(phi));
float2 rotatedDirection = mul(rotationMatrix, scaledDirection);
// Load (1 / (2 * WeightedVariance)) for bilateral weighting.
#if (RBG_BILATERAL_WEIGHTS != 0)
float3 halfRcpVariance = _HalfRcpWeightedVariances[profileID].rgb;
#else
float halfRcpVariance = _HalfRcpWeightedVariances[profileID].a;
#endif
#ifndef SSS_FILTER_HORIZONTAL_AND_COMBINE
bsdfData.diffuseColor = float3(1, 1, 1);
#endif
// Take the first (central) sample.
float2 samplePosition = posInput.unPositionSS;
float3 sampleWeight = _FilterKernelsBasic[profileID][0].rgb;
float3 sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
// We perform point sampling. Therefore, we can avoid the cost
// of filtering if we stay within the bounds of the current pixel.
// We use the value of 1 instead of 0.5 as an optimization.
float maxDistInPixels = scaledStepSize * maxDistance;
[branch]
if (distScale == 0 || maxDistInPixels < 1)
{
return float4(bsdfData.diffuseColor * sampleIrradiance, 1);
}
// Accumulate filtered irradiance and bilateral weights (for renormalization).
float3 totalIrradiance = sampleWeight * sampleIrradiance;
float3 totalWeight = sampleWeight;
[unroll]
for (int i = 1; i < SSS_BASIC_N_SAMPLES; i++)
{
samplePosition = posInput.unPositionSS + rotatedDirection * _FilterKernelsBasic[profileID][i].a;
sampleWeight = _FilterKernelsBasic[profileID][i].rgb;
sampleIrradiance = LOAD_TEXTURE2D(_IrradianceSource, samplePosition).rgb;
[flatten]
if (any(sampleIrradiance))
{
// Apply bilateral weighting.
// Ref #1: Skin Rendering by Pseudo–Separable Cross Bilateral Filtering.
// Ref #2: Separable SSS, Supplementary Materials, Section E.
float rawDepth = LOAD_TEXTURE2D(_MainDepthTexture, samplePosition).r;
float sampleDepth = LinearEyeDepth(rawDepth, _ZBufferParams);
float zDistance = unitScale * sampleDepth - (unitScale * centerPosVS.z);
sampleWeight *= exp(-zDistance * zDistance * halfRcpVariance);
totalIrradiance += sampleWeight * sampleIrradiance;
totalWeight += sampleWeight;
}
else
{
// The irradiance is 0. This could happen for 3 reasons.
// Most likely, the surface fragment does not have an SSS material.
// Alternatively, our sample comes from a region without any geometry.
// Finally, the surface fragment could be completely shadowed.
// Our blur is energy-preserving, so 'centerWeight' should be set to 0.
// We do not terminate the loop since we want to gather the contribution
// of the remaining samples (e.g. in case of hair covering skin).
}
}
#endif
return float4(bsdfData.diffuseColor * totalIrradiance / totalWeight, 1);
}

128
Assets/ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SSSProfile/SkinSSSProfile.asset


m_Script: {fileID: 11500000, guid: a6e7465350bf0d248b4799d98e18cd24, type: 3}
m_Name: SkinSSSProfile
m_EditorClassIdentifier:
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.6, g: 0.6, b: 0.6, a: 0}
lerpWeight: 0.5
texturingMode: 1
enableTransmission: 0
enableThinObject: 0
tintColor: {r: 1, g: 1, b: 1, a: 1}
thicknessRemap: {x: 0, y: 2.04}
surfaceAlbedo: {r: 0.9264706, g: 0.40873703, b: 0.40873703, a: 1}
volumeAlbedo: {r: 1, g: 1, b: 1, a: 1}
lenVolMeanFreePath: 0.5
texturingMode: 0
transmissionMode: 0
thicknessRemap: {x: 0, y: 12.031147}
worldScale: 1
m_FilterKernel:
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.00000001629312}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.034422863}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.07085508}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.112142384}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.16452742}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: -0.25364923}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.03442289}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.07085508}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.11214242}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.16452742}
- {x: 0.09090909, y: 0.09090909, z: 0.09090909, w: 0.2536493}
m_HalfRcpVariances:
- {x: 49.999992, y: 49.999992, z: 49.999992}
- {x: 12.499998, y: 12.499998, z: 12.499998}
m_HalfRcpWeightedVariances: {x: 22.222221, y: 22.222221, z: 22.222221, w: 22.222221}
m_SurfaceShapeParam: {x: 2.0590224, y: 4.054133, z: 4.054133}
m_VolumeShapeParam: {x: 2.08, y: 2.08, z: 2.08}
m_ScatteringDistance: 5.419821
m_FilterKernelNearField:
- {x: 0, y: 0.97133476}
- {x: 0.017877756, y: 0.9953917}
- {x: 0.036202505, y: 1.0205092}
- {x: 0.054994013, y: 1.0467529}
- {x: 0.07427349, y: 1.0741944}
- {x: 0.094063364, y: 1.1029103}
- {x: 0.11438756, y: 1.132984}
- {x: 0.13527156, y: 1.164506}
- {x: 0.15674259, y: 1.1975743}
- {x: 0.17882973, y: 1.2322955}
- {x: 0.20156404, y: 1.2687856}
- {x: 0.22497883, y: 1.3071716}
- {x: 0.24910988, y: 1.3475916}
- {x: 0.27399546, y: 1.3901969}
- {x: 0.29967672, y: 1.4351535}
- {x: 0.32619816, y: 1.482644}
- {x: 0.35360762, y: 1.5328683}
- {x: 0.3819568, y: 1.5860481}
- {x: 0.41130146, y: 1.6424277}
- {x: 0.4417024, y: 1.7022778}
- {x: 0.4732253, y: 1.7658993}
- {x: 0.5059418, y: 1.8336275}
- {x: 0.5399298, y: 1.9058359}
- {x: 0.5752746, y: 1.9829437}
- {x: 0.6120694, y: 2.065422}
- {x: 0.65041655, y: 2.1538014}
- {x: 0.6904289, y: 2.248684}
- {x: 0.7322304, y: 2.3507519}
- {x: 0.775959, y: 2.460786}
- {x: 0.82176715, y: 2.579681}
- {x: 0.8698255, y: 2.7084694}
- {x: 0.92032427, y: 2.8483486}
- {x: 0.9734774, y: 3.0007153}
- {x: 1.0295267, y: 3.1672118}
- {x: 1.0887463, y: 3.3497832}
- {x: 1.1514484, y: 3.5507479}
- {x: 1.2179924, y: 3.7729046}
- {x: 1.2887937, y: 4.0196543}
- {x: 1.3643361, y: 4.295185}
- {x: 1.445188, y: 4.6047096}
- {x: 1.5320255, y: 4.954817}
- {x: 1.6256601, y: 5.353957}
- {x: 1.7270783, y: 5.8131566}
- {x: 1.8374994, y: 6.3471036}
- {x: 1.9584543, y: 6.9758067}
- {x: 2.0919068, y: 7.7272725}
- {x: 2.2404315, y: 8.641929}
- {x: 2.4075086, y: 9.780431}
- {x: 2.5980062, y: 11.2381115}
- {x: 2.819041, y: 13.173864}
- {x: 3.0816343, y: 15.873777}
- {x: 3.4042366, y: 19.91012}
- {x: 3.8214154, y: 26.618317}
- {x: 4.41076, y: 40.00495}
- {x: 5.419821, y: 80.10354}
m_FilterKernelFarField:
- {x: 0, y: 0.97133476}
- {x: 0.047778983, y: 1.0366181}
- {x: 0.098853074, y: 1.1099442}
- {x: 0.15363829, y: 1.1927516}
- {x: 0.21262695, y: 1.28682}
- {x: 0.27640635, y: 1.3943745}
- {x: 0.34568286, y: 1.518227}
- {x: 0.42131463, y: 1.6619779}
- {x: 0.5043557, y: 1.8303038}
- {x: 0.59611636, y: 2.0293841}
- {x: 0.69824916, y: 2.267549}
- {x: 0.8128741, y: 2.556306}
- {x: 0.9427658, y: 2.9120302}
- {x: 1.0916504, y: 3.3589153}
- {x: 1.2646923, y: 3.9344332}
- {x: 1.4693556, y: 4.7002707}
- {x: 1.7170528, y: 5.7664676}
- {x: 2.0266538, y: 7.3519235}
- {x: 2.4331524, y: 9.9663}
- {x: 3.0145338, y: 15.138358}
- {x: 4.018674, y: 30.515371}
scatterDistance1: {r: 0.3, g: 0.2, b: 0.2, a: 0}
scatterDistance2: {r: 0.6, g: 0.2, b: 0.2, a: 0}
lerpWeight: 0.5
m_HalfRcpWeightedVariances: {x: 2.4691355, y: 12.5, z: 12.5, w: 2.4691355}
m_FilterKernelBasic:
- {x: 0.09090909, y: 0.21162307, z: 0.21162307, w: -0.000000048879357}
- {x: 0.09090909, y: 0.18990478, z: 0.18990478, w: -0.11381993}
- {x: 0.09090909, y: 0.13233659, z: 0.13233659, w: -0.23580086}
- {x: 0.09090909, y: 0.061445467, z: 0.061445467, w: -0.37865555}
- {x: 0.09090909, y: 0.010501689, z: 0.010501689, w: -0.57677805}
- {x: 0.09090909, y: 2.9458339e-10, z: 2.9458339e-10, w: -1.3907351}
- {x: 0.09090909, y: 0.18990476, z: 0.18990476, w: 0.11382001}
- {x: 0.09090909, y: 0.13233659, z: 0.13233659, w: 0.23580086}
- {x: 0.09090909, y: 0.061445467, z: 0.061445467, w: 0.37865555}
- {x: 0.09090909, y: 0.010501689, z: 0.010501689, w: 0.57677805}
- {x: 0.09090909, y: 2.9456845e-10, z: 2.9456845e-10, w: 1.3907368}

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


using System;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor;
#endif
namespace UnityEngine.Experimental.Rendering.HDPipeline

public const int SSS_LOD_THRESHOLD = 4; // The LoD threshold of the near-field kernel (in pixels)
public const int SSS_TRSM_MODE_NONE = 0;
public const int SSS_TRSM_MODE_THIN = 1;
// Old SSS Model >>>
public const int SSS_BASIC_N_SAMPLES = 11; // Must be an odd number
public const int SSS_BASIC_DISTANCE_SCALE = 3; // SSS distance units per centimeter
// <<< Old SSS Model
}
[Serializable]

Vector2[] m_FilterKernelNearField; // X = radius, Y = reciprocal of the PDF
[SerializeField]
Vector2[] m_FilterKernelFarField; // X = radius, Y = reciprocal of the PDF
// Old SSS Model >>>
[ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)]
public Color scatterDistance1;
[ColorUsage(false, true, 0.05f, 2.0f, 1.0f, 1.0f)]
public Color scatterDistance2;
public float lerpWeight;
[SerializeField]
Vector4 m_HalfRcpWeightedVariances;
[SerializeField]
Vector4[] m_FilterKernelBasic;
// <<< Old SSS Model
// --- Public Methods ---

thicknessRemap = new Vector2(0.0f, 5.0f);
worldScale = 1.0f;
settingsIndex = SssConstants.SSS_NEUTRAL_PROFILE_ID; // Updated by SubsurfaceScatteringSettings.OnValidate() once assigned
// Old SSS Model >>>
scatterDistance1 = new Color(0.3f, 0.3f, 0.3f, 0.0f);
scatterDistance2 = new Color(0.5f, 0.5f, 0.5f, 0.0f);
lerpWeight = 1.0f;
// <<< Old SSS Model
BuildKernel();
}

// PDF(r, s) = s * (Exp[-r * s] + Exp[-r * s / 3]) / 4
// CDF(r, s) = 1 - 1/4 * Exp[-r * s] - 3/4 * Exp[-r * s / 3]
// ------------------------------------------------------------------------------------
// N.b.: computation of normalized weights, and multiplication by the surface albedo
// of the actual geometry is performed at runtime (in the shader).
m_FilterKernelNearField[i].x = r;

m_FilterKernelFarField[i].x = r;
m_FilterKernelFarField[i].y = 1.0f / KernelPdf(r, s);
}
// Old SSS Model >>>
UpdateKernelAndVarianceData();
// <<< Old SSS Model
// Old SSS Model >>>
public void UpdateKernelAndVarianceData()
{
const int numSamples = SssConstants.SSS_BASIC_N_SAMPLES;
const int distanceScale = SssConstants.SSS_BASIC_DISTANCE_SCALE;
if (m_FilterKernelBasic == null || m_FilterKernelBasic.Length != numSamples)
{
m_FilterKernelBasic = new Vector4[numSamples];
}
// Apply the three-sigma rule, and rescale.
Color stdDev1 = ((1.0f / 3.0f) * distanceScale) * scatterDistance1;
Color stdDev2 = ((1.0f / 3.0f) * distanceScale) * scatterDistance2;
// Our goal is to blur the image using a filter which is represented
// as a product of a linear combination of two normalized 1D Gaussians
// as suggested by Jimenez et al. in "Separable Subsurface Scattering".
// A normalized (i.e. energy-preserving) 1D Gaussian with the mean of 0
// is defined as follows: G1(x, v) = exp(-x * x / (2 * v)) / sqrt(2 * Pi * v),
// where 'v' is variance and 'x' is the radial distance from the origin.
// Using the weight 'w', our 1D and the resulting 2D filters are given as:
// A1(v1, v2, w, x) = G1(x, v1) * (1 - w) + G1(r, v2) * w,
// A2(v1, v2, w, x, y) = A1(v1, v2, w, x) * A1(v1, v2, w, y).
// The resulting filter function is a non-Gaussian PDF.
// It is separable by design, but generally not radially symmetric.
// N.b.: our scattering distance is rather limited. Therefore, in order to allow
// for a greater range of standard deviation values for flatter profiles,
// we rescale the world using 'distanceScale', effectively reducing the SSS
// distance units from centimeters to (1 / distanceScale).
// Find the widest Gaussian across 3 color channels.
float maxStdDev1 = Mathf.Max(stdDev1.r, stdDev1.g, stdDev1.b);
float maxStdDev2 = Mathf.Max(stdDev2.r, stdDev2.g, stdDev2.b);
Vector3 weightSum = new Vector3(0, 0, 0);
float step = 1.0f / (numSamples - 1);
// Importance sample the linear combination of two Gaussians.
for (int i = 0; i < numSamples; i++)
{
// Generate 'u' on (0, 0.5] and (0.5, 1).
float u = (i <= numSamples / 2) ? 0.5f - i * step // The center and to the left
: i * step; // From the center to the right
u = Mathf.Clamp(u, 0.001f, 0.999f);
float pos = GaussianCombinationCdfInverse(u, maxStdDev1, maxStdDev2, lerpWeight);
float pdf = GaussianCombination(pos, maxStdDev1, maxStdDev2, lerpWeight);
Vector3 val;
val.x = GaussianCombination(pos, stdDev1.r, stdDev2.r, lerpWeight);
val.y = GaussianCombination(pos, stdDev1.g, stdDev2.g, lerpWeight);
val.z = GaussianCombination(pos, stdDev1.b, stdDev2.b, lerpWeight);
// We do not divide by 'numSamples' since we will renormalize, anyway.
m_FilterKernelBasic[i].x = val.x * (1 / pdf);
m_FilterKernelBasic[i].y = val.y * (1 / pdf);
m_FilterKernelBasic[i].z = val.z * (1 / pdf);
m_FilterKernelBasic[i].w = pos;
weightSum.x += m_FilterKernelBasic[i].x;
weightSum.y += m_FilterKernelBasic[i].y;
weightSum.z += m_FilterKernelBasic[i].z;
}
// Renormalize the weights to conserve energy.
for (int i = 0; i < numSamples; i++)
{
m_FilterKernelBasic[i].x *= 1 / weightSum.x;
m_FilterKernelBasic[i].y *= 1 / weightSum.y;
m_FilterKernelBasic[i].z *= 1 / weightSum.z;
}
Vector4 weightedStdDev;
weightedStdDev.x = Mathf.Lerp(stdDev1.r, stdDev2.r, lerpWeight);
weightedStdDev.y = Mathf.Lerp(stdDev1.g, stdDev2.g, lerpWeight);
weightedStdDev.z = Mathf.Lerp(stdDev1.b, stdDev2.b, lerpWeight);
weightedStdDev.w = Mathf.Lerp(maxStdDev1, maxStdDev2, lerpWeight);
// Store (1 / (2 * WeightedVariance)) per color channel.
m_HalfRcpWeightedVariances.x = 0.5f / (weightedStdDev.x * weightedStdDev.x);
m_HalfRcpWeightedVariances.y = 0.5f / (weightedStdDev.y * weightedStdDev.y);
m_HalfRcpWeightedVariances.z = 0.5f / (weightedStdDev.z * weightedStdDev.z);
m_HalfRcpWeightedVariances.w = 0.5f / (weightedStdDev.w * weightedStdDev.w);
}
// <<< Old SSS Model
public Vector3 surfaceShapeParameter
{
// Set in BuildKernel().

// Set in BuildKernel().
get { return m_FilterKernelNearField; }
}
// Old SSS Model >>>
public Vector4[] filterKernelBasic
{
// Set via UpdateKernelAndVarianceData().
get { return m_FilterKernelBasic; }
}
public Vector4 halfRcpWeightedVariances
{
// Set via UpdateKernelAndVarianceData().
get { return m_HalfRcpWeightedVariances; }
}
// <<< Old SSS Model
// --- Private Methods ---

return r;
}
// Old SSS Model >>>
static float Gaussian(float x, float stdDev)
{
float variance = stdDev * stdDev;
return Mathf.Exp(-x * x / (2 * variance)) / Mathf.Sqrt(2 * Mathf.PI * variance);
}
static float GaussianCombination(float x, float stdDev1, float stdDev2, float lerpWeight)
{
return Mathf.Lerp(Gaussian(x, stdDev1), Gaussian(x, stdDev2), lerpWeight);
}
static float RationalApproximation(float t)
{
// Abramowitz and Stegun formula 26.2.23.
// The absolute value of the error should be less than 4.5 e-4.
float[] c = {2.515517f, 0.802853f, 0.010328f};
float[] d = {1.432788f, 0.189269f, 0.001308f};
return t - ((c[2] * t + c[1]) * t + c[0]) / (((d[2] * t + d[1]) * t + d[0]) * t + 1.0f);
}
// Ref: https://www.johndcook.com/blog/csharp_phi_inverse/
static float NormalCdfInverse(float p, float stdDev)
{
float x;
if (p < 0.5)
{
// F^-1(p) = - G^-1(p)
x = -RationalApproximation(Mathf.Sqrt(-2.0f * Mathf.Log(p)));
}
else
{
// F^-1(p) = G^-1(1-p)
x = RationalApproximation(Mathf.Sqrt(-2.0f * Mathf.Log(1.0f - p)));
}
return x * stdDev;
}
static float GaussianCombinationCdfInverse(float p, float stdDev1, float stdDev2, float lerpWeight)
{
return Mathf.Lerp(NormalCdfInverse(p, stdDev1), NormalCdfInverse(p, stdDev2), lerpWeight);
}
// <<< Old SSS Model
}
[Serializable]

[NonSerialized] public float[] worldScales; // Size of the world unit in meters
[NonSerialized] public float[] filterKernelsNearField; // 0 = radius, 1 = reciprocal of the PDF
[NonSerialized] public float[] filterKernelsFarField; // 0 = radius, 1 = reciprocal of the PDF
// Old SSS Model >>>
public bool useDisneySSS;
[NonSerialized] public Vector4[] halfRcpWeightedVariances;
[NonSerialized] public Vector4[] filterKernelsBasic;
// <<< Old SSS Model
// --- Public Methods ---

volumeShapeParams = null;
filterKernelsNearField = null;
filterKernelsFarField = null;
// Old SSS Model >>>
useDisneySSS = true;
halfRcpWeightedVariances = null;
filterKernelsBasic = null;
// <<< Old SSS Model
UpdateCache();
}

profiles[i].thicknessRemap.x = Mathf.Clamp(profiles[i].thicknessRemap.x, 0, profiles[i].thicknessRemap.y);
profiles[i].worldScale = Mathf.Max(profiles[i].worldScale, 0.001f);
// Old SSS Model >>>
Color c = new Color();
c.r = Mathf.Clamp(profiles[i].scatterDistance1.r, 0.05f, 2.0f);
c.g = Mathf.Clamp(profiles[i].scatterDistance1.g, 0.05f, 2.0f);
c.b = Mathf.Clamp(profiles[i].scatterDistance1.b, 0.05f, 2.0f);
c.a = 0.0f;
profiles[i].scatterDistance1 = c;
c.r = Mathf.Clamp(profiles[i].scatterDistance2.r, 0.05f, 2.0f);
c.g = Mathf.Clamp(profiles[i].scatterDistance2.g, 0.05f, 2.0f);
c.b = Mathf.Clamp(profiles[i].scatterDistance2.b, 0.05f, 2.0f);
c.a = 0.0f;
profiles[i].scatterDistance2 = c;
profiles[i].lerpWeight = Mathf.Clamp01(profiles[i].lerpWeight);
// <<< Old SSS Model
profiles[i].BuildKernel();
}

filterKernelsFarField = new float[filterKernelsFarFieldLen];
}
// Old SSS Model >>>
if (halfRcpWeightedVariances == null || halfRcpWeightedVariances.Length != SssConstants.SSS_N_PROFILES)
{
halfRcpWeightedVariances = new Vector4[SssConstants.SSS_N_PROFILES];
}
const int filterKernelsLen = SssConstants.SSS_N_PROFILES * SssConstants.SSS_BASIC_N_SAMPLES;
if (filterKernelsBasic == null || filterKernelsBasic.Length != filterKernelsLen)
{
filterKernelsBasic = new Vector4[filterKernelsLen];
}
// <<< Old SSS Model
for (int i = 0; i < numProfiles; i++)
{
// Skip unassigned profiles.

filterKernelsFarField[2 * (n * i + j) + 0] = profiles[i].filterKernelFarField[j].x;
filterKernelsFarField[2 * (n * i + j) + 1] = profiles[i].filterKernelFarField[j].y;
}
// Old SSS Model >>>
halfRcpWeightedVariances[i] = profiles[i].halfRcpWeightedVariances;
for (int j = 0, n = SssConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{
filterKernelsBasic[n * i + j] = profiles[i].filterKernelBasic[j];
}
// <<< Old SSS Model
}
// Fill the neutral profile.

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

public readonly GUIContent sssProfileMinMaxThickness = new GUIContent("Min-Max Thickness", "Shows the values of the thickness remap below (in millimeters).");
public readonly GUIContent sssProfileThicknessRemap = new GUIContent("Thickness Remap", "Remaps the thickness parameter from [0, 1] to the desired range (in millimeters).");
public readonly GUIContent sssProfileWorldScale = new GUIContent("World Scale", "Size of the world unit in meters.");
// Old SSS Model >>>
public readonly GUIContent sssProfileScatterDistance1 = new GUIContent("Scattering 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.");
public readonly GUIContent sssProfileScatterDistance2 = new GUIContent("Scattering 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.");
public readonly GUIContent sssProfileLerpWeight = new GUIContent("Filter Interpolation", "Controls linear interpolation between the two Gaussian filters.");
// <<< Old SSS Model
public readonly GUIStyle centeredMiniBoldLabel = new GUIStyle(GUI.skin.label);
public Styles()

private Material m_ProfileMaterial, m_TransmittanceMaterial;
private SerializedProperty m_LenVolMeanFreePath, m_ScatteringDistance, m_SurfaceAlbedo, m_VolumeAlbedo, m_SurfaceShapeParam, m_VolumeShapeParam,
m_TexturingMode, m_TransmissionMode, m_ThicknessRemap, m_WorldScale;
// Old SSS Model >>>
private SerializedProperty m_ScatterDistance1, m_ScatterDistance2, m_LerpWeight;
// <<< Old SSS Model
void OnEnable()
{

m_TransmissionMode = serializedObject.FindProperty("transmissionMode");
m_ThicknessRemap = serializedObject.FindProperty("thicknessRemap");
m_WorldScale = serializedObject.FindProperty("worldScale");
// Old SSS Model >>>
m_ScatterDistance1 = serializedObject.FindProperty("scatterDistance1");
m_ScatterDistance2 = serializedObject.FindProperty("scatterDistance2");
m_LerpWeight = serializedObject.FindProperty("lerpWeight");
// <<< Old SSS Model
// These shaders don't need to be reference by RenderPipelineResource as they are not use at runtime
m_ProfileMaterial = Utilities.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawSssProfile");

{
serializedObject.Update();
// Old SSS Model >>>
bool useDisneySSS;
{
HDRenderPipeline hdPipeline = RenderPipelineManager.currentPipeline as HDRenderPipeline;
useDisneySSS = hdPipeline.sssSettings.useDisneySSS;
}
// <<< Old SSS Model
EditorGUILayout.PropertyField(m_SurfaceAlbedo, styles.sssProfileSurfaceAlbedo);
m_LenVolMeanFreePath.floatValue = EditorGUILayout.Slider(styles.sssProfileLenVolMeanFreePath, m_LenVolMeanFreePath.floatValue, 0.01f, 1.0f);
GUI.enabled = false;
EditorGUILayout.PropertyField(m_ScatteringDistance, styles.sssProfileScatteringDistance);
GUI.enabled = true;
if (useDisneySSS)
{
EditorGUILayout.PropertyField(m_SurfaceAlbedo, styles.sssProfileSurfaceAlbedo);
m_LenVolMeanFreePath.floatValue = EditorGUILayout.Slider(styles.sssProfileLenVolMeanFreePath, m_LenVolMeanFreePath.floatValue, 0.01f, 1.0f);
GUI.enabled = false;
EditorGUILayout.PropertyField(m_ScatteringDistance, styles.sssProfileScatteringDistance);
GUI.enabled = true;
}
else
{
EditorGUILayout.PropertyField(m_ScatterDistance1, styles.sssProfileScatterDistance1);
EditorGUILayout.PropertyField(m_ScatterDistance2, styles.sssProfileScatterDistance2);
EditorGUILayout.PropertyField(m_LerpWeight, styles.sssProfileLerpWeight);
}
m_TexturingMode.intValue = EditorGUILayout.Popup(styles.sssTexturingMode, m_TexturingMode.intValue, styles.sssTexturingModeOptions);
m_TransmissionMode.intValue = EditorGUILayout.Popup(styles.sssProfileTransmissionMode, m_TransmissionMode.intValue, styles.sssTransmissionModeOptions);

m_ProfileMaterial.SetFloat("_ScatteringDistance", d);
m_ProfileMaterial.SetVector("_SurfaceAlbedo", aS);
m_ProfileMaterial.SetVector("_SurfaceShapeParam", sS);
// Old SSS Model >>>
Utilities.SelectKeyword(m_ProfileMaterial, "SSS_MODEL_DISNEY", "SSS_MODEL_BASIC", useDisneySSS);
// Apply the three-sigma rule, and rescale.
float s = (1.0f / 3.0f) * SssConstants.SSS_BASIC_DISTANCE_SCALE;
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);
m_ProfileMaterial.SetVector("_StdDev1", stdDev1);
m_ProfileMaterial.SetVector("_StdDev2", stdDev2);
m_ProfileMaterial.SetFloat("_LerpWeight", m_LerpWeight.floatValue);
m_ProfileMaterial.SetFloat("_MaxRadius", rMax);
// <<< Old SSS Model
EditorGUILayout.Space();
EditorGUILayout.LabelField(styles.sssTransmittancePreview0, styles.centeredMiniBoldLabel);
EditorGUILayout.LabelField(styles.sssTransmittancePreview1, EditorStyles.centeredGreyMiniLabel);

// Draw the transmittance graph.
m_TransmittanceMaterial.SetFloat("_ScatteringDistance", d);
m_TransmittanceMaterial.SetVector("_VolumeAlbedo", transmissionEnabled ? aV : Vector4.zero);
m_TransmittanceMaterial.SetVector("_VolumeShapeParam", sV);
m_TransmittanceMaterial.SetVector("_ThicknessRemap", R);
m_TransmittanceMaterial.SetVector("_VolumeAlbedo", transmissionEnabled ? aV : Vector4.zero);
m_TransmittanceMaterial.SetVector("_VolumeShapeParam", sV);
m_TransmittanceMaterial.SetVector("_ThicknessRemap", R);
EditorGUI.DrawPreviewTexture(GUILayoutUtility.GetRect(16, 16), m_TransmittanceImage, m_TransmittanceMaterial, ScaleMode.ScaleToFit, 16.0f);
serializedObject.ApplyModifiedProperties();

// Validate each individual asset and update caches.
// Validate each individual asset and update caches.
hdPipeline.sssSettings.OnValidate();
}
}

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


#define SSS_LOD_THRESHOLD (4)
#define SSS_TRSM_MODE_NONE (0)
#define SSS_TRSM_MODE_THIN (1)
#define SSS_BASIC_N_SAMPLES (11)
#define SSS_BASIC_DISTANCE_SCALE (3)
#endif

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


#pragma vertex Vert
#pragma fragment Frag
#pragma multi_compile SSS_MODEL_BASIC SSS_MODEL_DISNEY
//-------------------------------------------------------------------------------------
// Include
//-------------------------------------------------------------------------------------

#ifdef SSS_MODEL_BASIC
#include "../../Material/Lit/SubsurfaceScatteringProfile.cs.hlsl"
#endif
#ifdef SSS_MODEL_DISNEY
#else
float4 _StdDev1, _StdDev2;
float _LerpWeight, _MaxRadius; // See 'SubsurfaceScatteringParameters'
#endif
//-------------------------------------------------------------------------------------
// Implementation

float4 Frag(Varyings input) : SV_Target
{
#ifdef SSS_MODEL_DISNEY
float r = (2 * length(input.texcoord - 0.5)) * _ScatteringDistance;
float3 S = _SurfaceShapeParam.rgb;
float3 M = S * (exp(-r * S) + exp(-r * S * (1.0 / 3.0))) / (8 * PI * r);

return float4(pow(M, 1.0 / 3.0) * _SurfaceAlbedo.rgb, 1);
#else
float r = (2 * length(input.texcoord - 0.5)) * _MaxRadius * SSS_BASIC_DISTANCE_SCALE;
float3 var1 = _StdDev1.rgb * _StdDev1.rgb;
float3 var2 = _StdDev2.rgb * _StdDev2.rgb;
// Evaluate the linear combination of two 2D Gaussians instead of
// product of the linear combination of two normalized 1D Gaussians
// since we do not want to bother artists with the lack of radial symmetry.
float3 magnitude = lerp(exp(-r * r / (2 * var1)) / (TWO_PI * var1),
exp(-r * r / (2 * var2)) / (TWO_PI * var2), _LerpWeight);
return float4(magnitude, 1);
#endif
}
ENDHLSL
}

8
Assets/TestScenes/HDTest/GraphicTest/SSS/Materials/SSSHead.mat


m_Texture: {fileID: 2800000, guid: 5ec067c14feff4144aa09544a2326b58, type: 3}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _NormalMapOS:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}

m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _TangentMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _TangentMapOS:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}

正在加载...
取消
保存