浏览代码

Rename SubsurfaceScattering Settings/Editor to DiffusionProfile + various file renaming/moving

/main
Sebastien Lagarde 7 年前
当前提交
a8ab890d
共有 52 个文件被更改,包括 742 次插入715 次删除
  1. 10
      SampleScenes/HDTest/GraphicTest/SSS/Materials/SSSHead.mat
  2. 10
      SampleScenes/HDTest/GraphicTest/Two Sided/Material/GroundLeaf_DoubleSidedFlipSSS.mat
  3. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDAssetFactory.cs
  4. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineInspector.Styles.cs
  5. 10
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineInspector.cs
  6. 52
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineMenuItems.cs
  7. 10
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Lit/LitUI.cs
  8. 14
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs
  9. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipelineAsset.asset
  10. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipelineAsset.cs
  11. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Deferred.shader
  12. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/Deferred.compute
  13. 21
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl
  14. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.compute
  15. 36
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl
  16. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.shader
  17. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringManager.cs
  18. 5
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/RenderPipelineResources.cs
  19. 2
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassForward.hlsl
  20. 3
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.Styles.cs
  21. 20
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs
  22. 18
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Default Diffusion Profile Settings.asset
  23. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawDiffusionProfile.shader
  24. 4
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawTransmittanceGraph.shader
  25. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile.meta
  26. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Default Diffusion Profile Settings.asset.meta
  27. 44
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfile.hlsl
  28. 513
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs
  29. 21
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.hlsl
  30. 8
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/SubsurfaceScattering.meta
  31. 61
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/CommonSubsurfaceScattering.hlsl
  32. 21
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs.hlsl
  33. 513
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs
  34. 9
      ScriptableRenderPipeline/HDRenderPipeline/HDRP/SceneSettings.meta
  35. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfile.hlsl.meta
  36. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.hlsl.meta
  37. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.meta
  38. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile.meta
  39. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.Styles.cs.meta
  40. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs.meta
  41. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.Styles.cs
  42. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs
  43. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Default Diffusion Profile Settings.asset
  44. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawDiffusionProfile.shader.meta
  45. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawTransmittanceGraph.shader.meta
  46. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawDiffusionProfile.shader
  47. 0
      /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawTransmittanceGraph.shader

10
SampleScenes/HDTest/GraphicTest/SSS/Materials/SSSHead.mat


m_PrefabInternal: {fileID: 0}
m_Name: SSSHead
m_Shader: {fileID: 4800000, guid: 6e4ae4064600d784cac1e41a9e6f2e59, type: 3}
m_ShaderKeywords: _BLENDMODE_PRESERVE_SPECULAR_LIGHTING _MATID_SSS _NORMALMAP _NORMALMAP_TANGENT_SPACE
_THICKNESSMAP
m_ShaderKeywords: _MATID_SSS _NORMALMAP _NORMALMAP_TANGENT_SPACE _THICKNESSMAP
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0

m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SubsurfaceMaskMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SubsurfaceRadiusMap:
m_Texture: {fileID: 2800000, guid: f40319fb453e7e04dbe1e64f7b81efd9, type: 3}
m_Scale: {x: 1, y: 1}

- _BumpScale: 1
- _CoatCoverage: 1
- _CoatIOR: 0.5
- _CoatMask: 1
- _CullMode: 2
- _CullModeForward: 2
- _Cutoff: 0.5

- _DetailNormalScale: 1
- _DetailSmoothnessScale: 1
- _DiffusionProfile: 1
- _DisplacementLockObjectScale: 1
- _DisplacementLockTilingScale: 1
- _DisplacementMode: 0

- _StencilWriteMask: 7
- _StencilWriteMaskMV: 128
- _Stiffness: 1
- _SubsurfaceMask: 1
- _SubsurfaceProfile: 1
- _SubsurfaceRadius: 1
- _SurfaceType: 0

10
SampleScenes/HDTest/GraphicTest/Two Sided/Material/GroundLeaf_DoubleSidedFlipSSS.mat


m_PrefabInternal: {fileID: 0}
m_Name: GroundLeaf_DoubleSidedFlipSSS
m_Shader: {fileID: 4800000, guid: 6e4ae4064600d784cac1e41a9e6f2e59, type: 3}
m_ShaderKeywords: _ALPHATEST_ON _BLENDMODE_PRESERVE_SPECULAR_LIGHTING _DOUBLESIDED_ON
_MASKMAP _MATID_SSS _NORMALMAP _NORMALMAP_TANGENT_SPACE
m_ShaderKeywords: _ALPHATEST_ON _DOUBLESIDED_ON _MASKMAP _MATID_SSS _NORMALMAP _NORMALMAP_TANGENT_SPACE
m_LightmapFlags: 1
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 1

m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SubsurfaceMaskMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SubsurfaceRadiusMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}

- _BumpScale: 1
- _CoatCoverage: 1
- _CoatIOR: 0.5
- _CoatMask: 1
- _CullMode: 0
- _CullModeForward: 0
- _Cutoff: 0.5

- _DetailNormalMapScale: 1
- _DetailNormalScale: 1
- _DetailSmoothnessScale: 1
- _DiffusionProfile: 2
- _DisplacementLockObjectScale: 1
- _DisplacementLockTilingScale: 1
- _DisplacementMode: 0

- _StencilWriteMask: 7
- _StencilWriteMaskMV: 128
- _Stiffness: 1
- _SubsurfaceMask: 1
- _SubsurfaceProfile: 2
- _SubsurfaceRadius: 1
- _SurfaceType: 0

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDAssetFactory.cs


newAsset.deferredDirectionalShadowComputeShader = Load<ComputeShader>(HDRenderPipelinePath + "Lighting/DeferredDirectionalShadow.compute");
// SubsurfaceScattering
// These shaders don't need to be reference by RenderPipelineResource as they are not use at runtime (only to draw in editor)
// instance.drawSssProfile = UnityEditor.AssetDatabase.LoadAssetAtPath<Shader>(HDRenderPipelinePath + "SceneSettings/DrawSssProfile.shader");
// instance.drawTransmittanceGraphShader = UnityEditor.AssetDatabase.LoadAssetAtPath<Shader>(HDRenderPipelinePath + "SceneSettings/DrawTransmittanceGraph.shader");
newAsset.subsurfaceScatteringCS = Load<ComputeShader>(HDRenderPipelinePath + "Material/SubsurfaceScattering/SubsurfaceScattering.compute");
newAsset.subsurfaceScattering = Load<Shader>(HDRenderPipelinePath + "Material/SubsurfaceScattering/SubsurfaceScattering.shader");
newAsset.combineLighting = Load<Shader>(HDRenderPipelinePath + "Material/SubsurfaceScattering/CombineLighting.shader");

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineInspector.Styles.cs


// Rendering Settings
public readonly GUIContent renderingSettingsLabel = new GUIContent("Rendering Settings");
public readonly GUIContent sssSettings = new GUIContent("Subsurface Scattering Settings");
public readonly GUIContent diffusionProfileSettings = new GUIContent("Diffusion Profile Settings");
}
static Styles s_Styles;

10
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineInspector.cs


SerializedProperty m_SkyReflectionSize;
SerializedProperty m_SkyLightingOverrideLayerMask;
// Subsurface Scattering Settings
SerializedProperty m_SubsurfaceScatteringSettings;
// Diffusion profile Settings
SerializedProperty m_DiffusionProfileSettings;
SerializedFrameSettings serializedFrameSettings = null;
FrameSettingsUI m_FrameSettingsUI = new FrameSettingsUI();

m_SkyReflectionSize = properties.Find(x => x.renderPipelineSettings.lightLoopSettings.skyReflectionSize);
m_SkyLightingOverrideLayerMask = properties.Find(x => x.renderPipelineSettings.lightLoopSettings.skyLightingOverrideLayerMask);
// Subsurface Scattering Settings
m_SubsurfaceScatteringSettings = properties.Find(x => x.sssSettings);
// Diffusion profile Settings
m_DiffusionProfileSettings = properties.Find(x => x.diffusionProfileSettings);
serializedFrameSettings = new SerializedFrameSettings(properties.Find(x => x.serializedFrameSettings));

EditorGUILayout.PropertyField(m_RenderPipelineResources, s_Styles.renderPipelineResources);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_SubsurfaceScatteringSettings, s_Styles.sssSettings);
EditorGUILayout.PropertyField(m_DiffusionProfileSettings, s_Styles.diffusionProfileSettings);
EditorGUILayout.Space();
SettingsUI(m_Target);

52
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/HDRenderPipelineMenuItems.cs


var sceneName = Path.GetFileNameWithoutExtension(scenePath);
var description = string.Format("{0} {1}/{2} - ", sceneName, i + 1, scenes.Length);
ResetAllLoadedMaterialKeywords(description, scale, scale * i);
}

if (mat.shader.name == "HDRenderPipeline/LitTessellation" ||
mat.shader.name == "HDRenderPipeline/Lit")
{
float fvalue = mat.GetFloat("_MaterialID");
if (fvalue == 0.0) // SSS
if (mat.HasProperty("_SubsurfaceProfile"))
int ivalue = mat.GetInt("_DiffusionProfile");
if (ivalue == 15)
{
mat.SetInt("_DiffusionProfile", 0);
}
else
{
mat.SetInt("_DiffusionProfile", ivalue + 1);
}
float value = mat.GetInt("_DiffusionProfile");
mat.SetInt("_DiffusionProfile", 0);
EditorUtility.SetDirty(mat);
}

{
float fvalue = mat.GetFloat("_MaterialID");
if (fvalue == 0.0) // SSS
bool hasSubsurfaceProfile = false;
int numLayer = (int)mat.GetFloat("_LayerCount");
for (int x = 0; x < numLayer; ++x)
{
if (mat.HasProperty("_SubsurfaceProfile" + x))
{
hasSubsurfaceProfile = true;
}
}
if (hasSubsurfaceProfile)
int numLayer = (int)mat.GetFloat("_LayerCount");
int ivalue = mat.GetInt("_DiffusionProfile" + x);
if (ivalue == 15)
if (mat.HasProperty("_SubsurfaceProfile" + x))
CheckOutFile(VSCEnabled, mat);
float value = mat.GetInt("_DiffusionProfile" + x);
}
else
{
mat.SetInt("_DiffusionProfile" + x, ivalue + 1);
EditorUtility.SetDirty(mat);
EditorUtility.SetDirty(mat);
}
}

}
}
class DoCreateNewAssetSubsurfaceScatteringSettings : DoCreateNewAsset<SubsurfaceScatteringSettings> {}
class DoCreateNewAssetDiffusionProfileSettings : DoCreateNewAsset<DiffusionProfileSettings> {}
[MenuItem("Assets/Create/Render Pipeline/High Definition/Subsurface Scattering Settings", priority = CoreUtils.assetCreateMenuPriority2)]
static void MenuCreateSubsurfaceScatteringProfile()
[MenuItem("Assets/Create/Render Pipeline/High Definition/Diffusion profile Settings", priority = CoreUtils.assetCreateMenuPriority2)]
static void MenuCreateDiffusionProfile()
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<DoCreateNewAssetSubsurfaceScatteringSettings>(), "New SSS Settings.asset", icon, null);
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<DoCreateNewAssetDiffusionProfileSettings>(), "New Diffusion Profile Settings.asset", icon, null);
}
static void ResetAllMaterialAssetsKeywords(float progressScale, float progressOffset)

10
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/Lit/LitUI.cs


protected void ShaderSSSInputGUI(Material material, int layerIndex)
{
var hdPipeline = RenderPipelineManager.currentPipeline as HDRenderPipeline;
var sssSettings = hdPipeline.sssSettings;
var diffusionProfileSettings = hdPipeline.diffusionProfileSettings;
if (sssSettings == null)
if (diffusionProfileSettings == null)
{
EditorGUILayout.HelpBox("No Subsurface Scattering Settings have been assigned to the render pipeline asset.", MessageType.Warning);
return;

var profiles = sssSettings.profiles;
var profiles = diffusionProfileSettings.profiles;
values[0] = SssConstants.SSS_NEUTRAL_PROFILE_ID;
values[0] = DiffusionProfileConstants.DIFFUSION_NEUTRAL_PROFILE_ID;
for (int i = 0; i < profiles.Length; i++)
{

profileID = EditorGUILayout.IntPopup(profileID, names, values);
if (GUILayout.Button("Goto", EditorStyles.miniButton, GUILayout.Width(50f)))
Selection.activeObject = sssSettings;
Selection.activeObject = diffusionProfileSettings;
}
}

14
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipeline.cs


readonly HDRenderPipelineAsset m_Asset;
SubsurfaceScatteringSettings m_InternalSSSAsset;
public SubsurfaceScatteringSettings sssSettings
DiffusionProfileSettings m_InternalSSSAsset;
public DiffusionProfileSettings diffusionProfileSettings
var asset = m_Asset.sssSettings;
var asset = m_Asset.diffusionProfileSettings;
m_InternalSSSAsset = ScriptableObject.CreateInstance<SubsurfaceScatteringSettings>();
m_InternalSSSAsset = ScriptableObject.CreateInstance<DiffusionProfileSettings>();
asset = m_InternalSSSAsset;
}

m_CurrentHeight = texHeight;
}
public void PushGlobalParams(HDCamera hdCamera, CommandBuffer cmd, SubsurfaceScatteringSettings sssParameters)
public void PushGlobalParams(HDCamera hdCamera, CommandBuffer cmd, DiffusionProfileSettings sssParameters)
{
using (new ProfilingSample(cmd, "Push Global Parameters", GetSampler(CustomSamplerId.PushGlobalParameters)))
{

renderContext.SetupCameraProperties(camera);
PushGlobalParams(hdCamera, cmd, sssSettings);
PushGlobalParams(hdCamera, cmd, diffusionProfileSettings);
// TODO: Find a correct place to bind these material textures
// We have to bind the material specific global parameters in this mode

RenderForwardError(m_CullResults, camera, renderContext, cmd, ForwardPass.Opaque);
// SSS pass here handle both SSS material from deferred and forward
m_SSSBufferManager.SubsurfaceScatteringPass(hdCamera, cmd, sssSettings, m_FrameSettings,
m_SSSBufferManager.SubsurfaceScatteringPass(hdCamera, cmd, diffusionProfileSettings, m_FrameSettings,
m_CameraColorBufferRT, m_CameraSssDiffuseLightingBufferRT, m_CameraDepthStencilBufferRT, GetDepthTexture());
RenderSky(hdCamera, cmd);

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipelineAsset.asset


shadowInitParams:
shadowAtlasWidth: 4096
shadowAtlasHeight: 4096
sssSettings: {fileID: 11400000, guid: c4d57f106d34d0046a33b3e66da29a72, type: 2}
diffusionProfileSettings: {fileID: 11400000, guid: 404820c4cf36ad944862fa59c56064f0,
type: 2}

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/HDRenderPipelineAsset.cs


}
[SerializeField]
public SubsurfaceScatteringSettings sssSettings;
public DiffusionProfileSettings diffusionProfileSettings;
public override Shader GetDefaultShader()
{

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/Deferred.shader


Outputs outputs;
#ifdef OUTPUT_SPLIT_LIGHTING
if (_EnableSSSAndTransmission != 0 && bsdfData.materialId == MATERIALID_LIT_SSS)
if (_EnableSSSAndTransmission != 0 && HaveSubsurfaceScattering(bsdfData))
{
outputs.specularLighting = float4(specularLighting, 1.0);
outputs.diffuseLighting = TagLightingForSSS(diffuseLighting);

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Lighting/LightLoop/Deferred.compute


float3 specularLighting;
LightLoop(V, posInput, preLightData, bsdfData, bakeLightingData, featureFlags, diffuseLighting, specularLighting);
if (_EnableSSSAndTransmission != 0 && bsdfData.materialId == MATERIALID_LIT_SSS && HasMaterialFeatureFlag(MATERIALFEATUREFLAGS_LIT_SSS))
if (_EnableSSSAndTransmission != 0 && HaveSubsurfaceScattering(bsdfData))
{
specularLightingUAV[pixelCoord] = float4(specularLighting, 1.0);
diffuseLightingUAV[pixelCoord] = TagLightingForSSS(diffuseLighting);

21
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/Lit/Lit.hlsl


bsdfData.subsurfaceMask = radius;
bsdfData.enableTransmission = _EnableSSSAndTransmission != 0;
if (bsdfData.enableTransmission && transmissionMode != SSS_TRSM_MODE_NONE)
if (bsdfData.enableTransmission && transmissionMode != TRANSMISSION_MODE_NONE)
bsdfData.useThickObjectMode = transmissionMode != SSS_TRSM_MODE_THIN;
bsdfData.useThickObjectMode = transmissionMode != TRANSMISSION_MODE_THIN;
#if SHADEROPTIONS_USE_DISNEY_SSS
bsdfData.transmittance = ComputeTransmittanceDisney(_ShapeParams[diffusionProfile].rgb,

if (HasMaterialFeatureFlag(MATERIALFEATUREFLAGS_LIT_SSS))
{
int diffusionProfile = SSS_NEUTRAL_PROFILE_ID;
uint transmissionMode = SSS_TRSM_MODE_NONE;
int diffusionProfile = DIFFUSION_NEUTRAL_PROFILE_ID;
uint transmissionMode = TRANSMISSION_MODE_NONE;
float radius = 0;
float thickness = 0;

{
if (bsdfData.materialId == MATERIALID_LIT_SSS)
{
bsdfData.diffuseColor = ApplyDiffuseTexturingMode(bsdfData.diffuseColor, bsdfData.diffusionProfile);
bsdfData.diffuseColor = ApplySubsurfaceScatteringTexturingMode(bsdfData.diffuseColor, bsdfData.diffusionProfile);
}
// Premultiply bake diffuse lighting information with DisneyDiffuse pre-integration

lightTransportData.emissiveColor = builtinData.emissiveColor;
return lightTransportData;
}
//-----------------------------------------------------------------------------
// Subsurface Scattering functions
//-----------------------------------------------------------------------------
bool HaveSubsurfaceScattering(BSDFData bsdfData)
{
return bsdfData.materialId == MATERIALID_LIT_SSS && HasMaterialFeatureFlag(MATERIALFEATUREFLAGS_LIT_SSS);
}
//-----------------------------------------------------------------------------

float3 modifiedDiffuseColor;
if (bsdfData.materialId == MATERIALID_LIT_SSS)
modifiedDiffuseColor = ApplyDiffuseTexturingMode(bsdfData.diffuseColor, bsdfData.diffusionProfile);
modifiedDiffuseColor = ApplySubsurfaceScatteringTexturingMode(bsdfData.diffuseColor, bsdfData.diffusionProfile);
else
modifiedDiffuseColor = bsdfData.diffuseColor;

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.compute


// Inputs & outputs
//--------------------------------------------------------------------------------------------------
float4 _FilterKernels[SSS_N_PROFILES][SSS_N_SAMPLES_NEAR_FIELD]; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
float4 _FilterKernels[DIFFUSION_N_PROFILES][SSS_N_SAMPLES_NEAR_FIELD]; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
TEXTURE2D(_DepthTexture); // Z-buffer
TEXTURE2D(_SSSHTile); // DXGI_FORMAT_R8_UINT is not supported by Unity

// divergence of execution across the warp.
float maxDistInPixels = maxDistance * max(pixelsPerMm.x, pixelsPerMm.y);
float3 albedo = ApplyDiffuseTexturingMode(sssData.diffuseColor, profileID);
float3 albedo = ApplySubsurfaceScatteringTexturingMode(sssData.diffuseColor, profileID);
[branch] if (distScale == 0 || maxDistInPixels < 1)
{

36
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.hlsl


#include "SubsurfaceScatteringSettings.cs.hlsl"
#include "CommonSubsurfaceScattering.hlsl"
#include "../DiffusionProfile/DiffusionProfileSettings.cs.hlsl"
#include "../DiffusionProfile/DiffusionProfile.hlsl"
CBUFFER_START(UnitySSSParameters)
CBUFFER_START(UnitySSSAndTransmissionParameters)
// Warning: Unity is not able to losslessly transfer integers larger than 2^24 to the shader system.
// Therefore, we bitcast uint to float in C#, and bitcast back to uint in the shader.
uint _EnableSSSAndTransmission; // Globally toggles subsurface and transmission scattering on/off

float4 _HalfRcpVariancesAndWeights[SSS_N_PROFILES][2]; // 2x Gaussians in RGB, A is interpolation weights
float4 _HalfRcpVariancesAndWeights[DIFFUSION_N_PROFILES][2]; // 2x Gaussians in RGB, A is interpolation weights
float4 _ThicknessRemaps[SSS_N_PROFILES]; // R: start, G = end - start, BA unused
float4 _ShapeParams[SSS_N_PROFILES]; // RGB = S = 1 / D, A = filter radius
float4 _TransmissionTintsAndFresnel0[SSS_N_PROFILES]; // RGB = 1/4 * color, A = fresnel0
float4 _WorldScales[SSS_N_PROFILES]; // X = meters per world unit; Y = world units per meter
float4 _ThicknessRemaps[DIFFUSION_N_PROFILES]; // R: start, G = end - start, BA unused
float4 _ShapeParams[DIFFUSION_N_PROFILES]; // RGB = S = 1 / D, A = filter radius
float4 _TransmissionTintsAndFresnel0[DIFFUSION_N_PROFILES]; // RGB = 1/4 * color, A = fresnel0
float4 _WorldScales[DIFFUSION_N_PROFILES]; // X = meters per world unit; Y = world units per meter
CBUFFER_END
// ----------------------------------------------------------------------------

// Returns the modified albedo (diffuse color) for materials with subsurface scattering.
// Ref: Advanced Techniques for Realistic Real-Time Skin Rendering.
float3 ApplyDiffuseTexturingMode(float3 color, int diffusionProfile)
float3 ApplySubsurfaceScatteringTexturingMode(float3 color, int diffusionProfile)
{
#if defined(SHADERPASS) && (SHADERPASS == SHADERPASS_SUBSURFACE_SCATTERING)
// If the SSS pass is executed, we know we have SSS enabled.

#define ENCODE_INTO_SSSBUFFER(SURFACE_DATA, UNPOSITIONSS, NAME) EncodeIntoSSSBuffer(ConvertSurfaceDataToSSSData(SURFACE_DATA), UNPOSITIONSS, MERGE_NAME(NAME, 0))
#define DECODE_FROM_SSSBUFFER(UNPOSITIONSS, SSS_DATA) DecodeFromSSSBuffer(UNPOSITIONSS, SSS_DATA)
// In order to support subsurface scattering, we need to know which pixels have an SSS material.
// It can be accomplished by reading the stencil buffer.
// A faster solution (which avoids an extra texture fetch) is to simply make sure that
// all pixels which belong to an SSS material are not black (those that don't always are).
// We choose the blue color channel since it's perceptually the least noticeable.
float3 TagLightingForSSS(float3 subsurfaceLighting)
{
subsurfaceLighting.b = max(subsurfaceLighting.b, HALF_MIN);
return subsurfaceLighting;
}
// See TagLightingForSSS() for details.
bool TestLightingForSSS(float3 subsurfaceLighting)
{
return subsurfaceLighting.b > 0;
}

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScattering.shader


// Inputs & outputs
//-------------------------------------------------------------------------------------
float4 _FilterKernelsBasic[SSS_N_PROFILES][SSS_BASIC_N_SAMPLES]; // RGB = weights, A = radial distance
float4 _FilterKernelsBasic[DIFFUSION_N_PROFILES][SSS_BASIC_N_SAMPLES]; // RGB = weights, A = radial distance
float4 _HalfRcpWeightedVariances[SSS_BASIC_N_SAMPLES]; // RGB for chromatic, A for achromatic
TEXTURE2D(_IrradianceSource); // Includes transmitted light

float halfRcpVariance = _HalfRcpWeightedVariances[profileID].a;
#endif
float3 albedo = ApplyDiffuseTexturingMode(sssData.diffuseColor, profileID);
float3 albedo = ApplySubsurfaceScatteringTexturingMode(sssData.diffuseColor, profileID);
#ifndef SSS_FILTER_HORIZONTAL_AND_COMBINE
albedo = float3(1, 1, 1);

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringManager.cs


m_HTileRT = new RenderTargetIdentifier(m_HTile);
}
public void PushGlobalParams(CommandBuffer cmd, SubsurfaceScatteringSettings sssParameters, FrameSettings frameSettings)
public void PushGlobalParams(CommandBuffer cmd, DiffusionProfileSettings sssParameters, FrameSettings frameSettings)
{
// Broadcast SSS parameters to all shaders.
cmd.SetGlobalInt(HDShaderIDs._EnableSSSAndTransmission, frameSettings.enableSSSAndTransmission ? 1 : 0);

}
// Combines specular lighting and diffuse lighting with subsurface scattering.
public void SubsurfaceScatteringPass(HDCamera hdCamera, CommandBuffer cmd, SubsurfaceScatteringSettings sssParameters, FrameSettings frameSettings,
public void SubsurfaceScatteringPass(HDCamera hdCamera, CommandBuffer cmd, DiffusionProfileSettings sssParameters, FrameSettings frameSettings,
RenderTargetIdentifier colorBufferRT, RenderTargetIdentifier diffuseBufferRT, RenderTargetIdentifier depthStencilBufferRT, RenderTargetIdentifier depthTextureRT)
{
if (sssParameters == null || !frameSettings.enableSSSAndTransmission)

5
ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/RenderPipelineResources.cs


public ComputeShader deferredComputeShader;
public ComputeShader deferredDirectionalShadowComputeShader;
// Subsurface scattering
// These shaders don't need to be reference by RenderPipelineResource as they are not use at runtime (only to draw in editor)
// public Shader drawSssProfile;
// public Shader drawTransmittanceGraphShader;
public ComputeShader subsurfaceScatteringCS; // Disney SSS
public Shader subsurfaceScattering; // Jimenez SSS
public Shader combineLighting;

2
ScriptableRenderPipeline/HDRenderPipeline/HDRP/ShaderPass/ShaderPassForward.hlsl


LightLoop(V, posInput, preLightData, bsdfData, bakeLightingData, featureFlags, diffuseLighting, specularLighting);
#ifdef OUTPUT_SPLIT_LIGHTING
if (_EnableSSSAndTransmission != 0)
if (_EnableSSSAndTransmission != 0 && HaveSubsurfaceScattering(bsdfData))
{
outColor = float4(specularLighting, 1.0);
outDiffuseLighting = float4(TagLightingForSSS(diffuseLighting), 1.0);

3
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.Styles.cs


namespace UnityEditor.Experimental.Rendering.HDPipeline
{
public sealed partial class SubsurfaceScatteringSettingsEditor
public sealed partial class DiffusionProfileSettingsEditor
// TODO: missing tooltips
sealed class Styles
{
public readonly GUIContent profilePreview0 = new GUIContent("Profile Preview");

20
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs


namespace UnityEditor.Experimental.Rendering.HDPipeline
{
[CustomEditor(typeof(SubsurfaceScatteringSettings))]
public sealed partial class SubsurfaceScatteringSettingsEditor : HDBaseEditor<SubsurfaceScatteringSettings>
[CustomEditor(typeof(DiffusionProfileSettings))]
public sealed partial class DiffusionProfileSettingsEditor : HDBaseEditor<DiffusionProfileSettings>
internal SubsurfaceScatteringProfile objReference;
internal DiffusionProfile objReference;
internal SerializedProperty name;

base.OnEnable();
// These shaders don't need to be reference by RenderPipelineResource as they are not use at runtime
m_ProfileMaterial = CoreUtils.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawSssProfile");
m_ProfileMaterial = CoreUtils.CreateEngineMaterial("Hidden/HDRenderPipeline/DrawDiffusionProfile");
int count = SssConstants.SSS_N_PROFILES - 1;
int count = DiffusionProfileConstants.DIFFUSION_N_PROFILES - 1;
m_Profiles = new List<Profile>();
var serializedProfiles = properties.Find(x => x.profiles);

var serializedProfile = serializedProfiles.GetArrayElementAtIndex(i);
var rp = new RelativePropertyFetcher<SubsurfaceScatteringProfile>(serializedProfile);
var rp = new RelativePropertyFetcher<DiffusionProfile>(serializedProfile);
var profile = new Profile
{

CheckStyles();
// Display a warning if this settings asset is not currently in use
if (m_HDPipeline == null || m_HDPipeline.sssSettings != m_Target)
if (m_HDPipeline == null || m_HDPipeline.diffusionProfileSettings != m_Target)
EditorGUILayout.HelpBox("These profiles aren't currently in use, assign this asset to the HD render pipeline asset to use them.", MessageType.Warning);
serializedObject.Update();

var S = obj.shapeParam;
var T = (Vector4)profile.transmissionTint.colorValue;
var R = profile.thicknessRemap.vector2Value;
bool transmissionEnabled = profile.transmissionMode.intValue != (int)SubsurfaceScatteringProfile.TransmissionMode.None;
bool transmissionEnabled = profile.transmissionMode.intValue != (int)DiffusionProfile.TransmissionMode.None;
m_ProfileMaterial.SetFloat(HDShaderIDs._MaxRadius, r);
m_ProfileMaterial.SetVector(HDShaderIDs._ShapeParam, S);

// Apply the three-sigma rule, and rescale.
float s = (1f / 3f) * SssConstants.SSS_BASIC_DISTANCE_SCALE;
float s = (1f / 3f) * DiffusionProfileConstants.SSS_BASIC_DISTANCE_SCALE;
var scatterDist1 = profile.scatterDistance1.colorValue;
var scatterDist2 = profile.scatterDistance2.colorValue;
float rMax = Mathf.Max(scatterDist1.r, scatterDist1.g, scatterDist1.b,

// 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;
float a = 0.1f * DiffusionProfileConstants.SSS_BASIC_DISTANCE_SCALE;
var 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), 4f * (1f - profile.lerpWeight.floatValue));
var 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), 4f * profile.lerpWeight.floatValue);
m_TransmittanceMaterial.SetVector(HDShaderIDs._HalfRcpVarianceAndWeight1, halfRcpVarianceAndWeight1);

18
ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Default Diffusion Profile Settings.asset


m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b2686e09ec7aef44bad2843e4416f057, type: 3}
m_Name: SSS Settings
m_Name: Default Diffusion Profile Settings
useDisneySSS: 1
profiles:
- name: Skin
scatteringDistance: {r: 0.7568628, g: 0.32156864, b: 0.20000002, a: 1}

thicknessRemap: {x: 0, y: 8.152544}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3019608, g: 0.20000002, b: 0.20000002, a: 0}
scatterDistance2: {r: 0.6, g: 0.20000002, b: 0.20000002, a: 0}
lerpWeight: 0.5

transmissionMode: 1
thicknessRemap: {x: 0, y: 0.2873168}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 0.5

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

transmissionMode: 0
thicknessRemap: {x: 0, y: 5}
worldScale: 1
fresnel0: 0
scatterDistance1: {r: 0.3, g: 0.3, b: 0.3, a: 0}
scatterDistance2: {r: 0.5, g: 0.5, b: 0.5, a: 0}
lerpWeight: 1

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawDiffusionProfile.shader


Shader "Hidden/HDRenderPipeline/DrawSssProfile"
Shader "Hidden/HDRenderPipeline/DrawDiffusionProfile"
{
SubShader
{

#include "CoreRP/ShaderLibrary/Common.hlsl"
#define USE_LEGACY_UNITY_MATRIX_VARIABLES
#include "../../ShaderVariables.hlsl"
#include "HDRP/ShaderVariables.hlsl"
#include "../../Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs.hlsl"
#include "HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.hlsl"
#endif
//-------------------------------------------------------------------------------------

#ifdef SSS_MODEL_DISNEY
float4 _ShapeParam; float _MaxRadius; // See 'SubsurfaceScatteringProfile'
float4 _ShapeParam; float _MaxRadius; // See 'DiffusionProfile'
#else
float4 _StdDev1, _StdDev2;
float _LerpWeight, _MaxRadius; // See 'SubsurfaceScatteringParameters'

4
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawTransmittanceGraph.shader


#include "CoreRP/ShaderLibrary/Common.hlsl"
#include "CoreRP/ShaderLibrary/CommonMaterial.hlsl"
#define USE_LEGACY_UNITY_MATRIX_VARIABLES
#include "../../ShaderVariables.hlsl"
#include "../../Material/SubsurfaceScattering/CommonSubsurfaceScattering.hlsl"
#include "HDRP/ShaderVariables.hlsl"
#include "HDRP/Material/DiffusionProfile/DiffusionProfile.hlsl"
//-------------------------------------------------------------------------------------
// Inputs & outputs

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile.meta


fileFormatVersion: 2
guid: 2f0a1a902f8504048ad14c07d71182ff
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Default Diffusion Profile Settings.asset.meta


fileFormatVersion: 2
guid: 404820c4cf36ad944862fa59c56064f0
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

44
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfile.hlsl


// ----------------------------------------------------------------------------
// SSS/Transmittance helper
// ----------------------------------------------------------------------------
// 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 ComputeTransmittanceDisney(float3 S, 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;
#if 0
float3 expOneThird = exp(((-1.0 / 3.0) * thickness) * S);
#else
// Help the compiler.
float k = (-1.0 / 3.0) * LOG2_E;
float3 p = (k * thickness) * S;
float3 expOneThird = exp2(p);
#endif
// 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 * DiffusionProfileConstants.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);
}

513
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs


using System;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
[GenerateHLSL]
public class DiffusionProfileConstants
{
public const int DIFFUSION_N_PROFILES = 16; // Max. number of profiles, including the slot taken by the neutral profile
public const int DIFFUSION_NEUTRAL_PROFILE_ID = 0; // Does not result in blurring
public const int SSS_N_SAMPLES_NEAR_FIELD = 55; // Used for extreme close ups; must be a Fibonacci number
public const int SSS_N_SAMPLES_FAR_FIELD = 21; // Used at a regular distance; must be a Fibonacci number
public const int SSS_LOD_THRESHOLD = 4; // The LoD threshold of the near-field kernel (in pixels)
public const int TRANSMISSION_MODE_NONE = 0;
public const int TRANSMISSION_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]
public sealed class DiffusionProfile
{
public enum TexturingMode : uint
{
PreAndPostScatter = 0,
PostScatter = 1
}
public enum TransmissionMode : uint
{
None = DiffusionProfileConstants.TRANSMISSION_MODE_NONE,
ThinObject = DiffusionProfileConstants.TRANSMISSION_MODE_THIN,
Regular
}
public string name;
[ColorUsage(false, true)]
public Color scatteringDistance; // Per color channel (no meaningful units)
[ColorUsage(false)]
public Color transmissionTint; // Color, 0 to 1
public TexturingMode texturingMode;
public TransmissionMode transmissionMode;
public Vector2 thicknessRemap; // X = min, Y = max (in millimeters)
public float worldScale; // Size of the world unit in meters
public float fresnel0; // Fresnel0, 0.028 for skin
// Old SSS Model >>>
[ColorUsage(false, true)]
public Color scatterDistance1;
[ColorUsage(false, true)]
public Color scatterDistance2;
[Range(0f, 1f)]
public float lerpWeight;
// <<< Old SSS Model
public Vector3 shapeParam { get; private set; } // RGB = shape parameter: S = 1 / D
public float maxRadius { get; private set; } // In millimeters
public Vector2[] filterKernelNearField { get; private set; } // X = radius, Y = reciprocal of the PDF
public Vector2[] filterKernelFarField { get; private set; } // X = radius, Y = reciprocal of the PDF
public Vector4 halfRcpWeightedVariances { get; private set; }
public Vector4[] filterKernelBasic { get; private set; }
public DiffusionProfile(string name)
{
this.name = name;
scatteringDistance = Color.grey;
transmissionTint = Color.white;
texturingMode = TexturingMode.PreAndPostScatter;
transmissionMode = TransmissionMode.None;
thicknessRemap = new Vector2(0f, 5f);
worldScale = 1f;
fresnel0 = 0.028f; // TYpical value for skin specular reflectance
// Old SSS Model >>>
scatterDistance1 = new Color(0.3f, 0.3f, 0.3f, 0f);
scatterDistance2 = new Color(0.5f, 0.5f, 0.5f, 0f);
lerpWeight = 1f;
// <<< Old SSS Model
}
public void Validate()
{
thicknessRemap.y = Mathf.Max(thicknessRemap.y, 0f);
thicknessRemap.x = Mathf.Clamp(thicknessRemap.x, 0f, thicknessRemap.y);
worldScale = Mathf.Max(worldScale, 0.001f);
fresnel0 = Mathf.Clamp(fresnel0, 0.0f, 0.1f);
// Old SSS Model >>>
scatterDistance1 = new Color
{
r = Mathf.Max(0.05f, scatterDistance1.r),
g = Mathf.Max(0.05f, scatterDistance1.g),
b = Mathf.Max(0.05f, scatterDistance1.b),
a = 0.0f
};
scatterDistance2 = new Color
{
r = Mathf.Max(0.05f, scatterDistance2.r),
g = Mathf.Max(0.05f, scatterDistance2.g),
b = Mathf.Max(0.05f, scatterDistance2.b),
a = 0f
};
// <<< Old SSS Model
UpdateKernel();
}
// Ref: Approximate Reflectance Profiles for Efficient Subsurface Scattering by Pixar.
public void UpdateKernel()
{
if (filterKernelNearField == null || filterKernelNearField.Length != DiffusionProfileConstants.SSS_N_SAMPLES_NEAR_FIELD)
filterKernelNearField = new Vector2[DiffusionProfileConstants.SSS_N_SAMPLES_NEAR_FIELD];
if (filterKernelFarField == null || filterKernelFarField.Length != DiffusionProfileConstants.SSS_N_SAMPLES_FAR_FIELD)
filterKernelFarField = new Vector2[DiffusionProfileConstants.SSS_N_SAMPLES_FAR_FIELD];
// Clamp to avoid artifacts.
shapeParam = new Vector3(
1f / Mathf.Max(0.001f, scatteringDistance.r),
1f / Mathf.Max(0.001f, scatteringDistance.g),
1f / Mathf.Max(0.001f, scatteringDistance.b)
);
// We importance sample the color channel with the widest scattering distance.
float s = Mathf.Min(shapeParam.x, shapeParam.y, shapeParam.z);
// Importance sample the normalized diffuse reflectance profile for the computed value of 's'.
// ------------------------------------------------------------------------------------
// R[r, phi, s] = s * (Exp[-r * s] + Exp[-r * s / 3]) / (8 * Pi * r)
// PDF[r, phi, s] = r * R[r, phi, s]
// CDF[r, s] = 1 - 1/4 * Exp[-r * s] - 3/4 * Exp[-r * s / 3]
// ------------------------------------------------------------------------------------
// Importance sample the near field kernel.
for (int i = 0, n = DiffusionProfileConstants.SSS_N_SAMPLES_NEAR_FIELD; i < n; i++)
{
float p = (i + 0.5f) * (1f / n);
float r = DisneyProfileCdfInverse(p, s);
// N.b.: computation of normalized weights, and multiplication by the surface albedo
// of the actual geometry is performed at runtime (in the shader).
filterKernelNearField[i].x = r;
filterKernelNearField[i].y = 1f / DisneyProfilePdf(r, s);
}
// Importance sample the far field kernel.
for (int i = 0, n = DiffusionProfileConstants.SSS_N_SAMPLES_FAR_FIELD; i < n; i++)
{
float p = (i + 0.5f) * (1f / n);
float r = DisneyProfileCdfInverse(p, s);
// N.b.: computation of normalized weights, and multiplication by the surface albedo
// of the actual geometry is performed at runtime (in the shader).
filterKernelFarField[i].x = r;
filterKernelFarField[i].y = 1f / DisneyProfilePdf(r, s);
}
maxRadius = filterKernelFarField[DiffusionProfileConstants.SSS_N_SAMPLES_FAR_FIELD - 1].x;
// Old SSS Model >>>
UpdateKernelAndVarianceData();
// <<< Old SSS Model
}
// Old SSS Model >>>
public void UpdateKernelAndVarianceData()
{
const int kNumSamples = DiffusionProfileConstants.SSS_BASIC_N_SAMPLES;
const int kDistanceScale = DiffusionProfileConstants.SSS_BASIC_DISTANCE_SCALE;
if (filterKernelBasic == null || filterKernelBasic.Length != kNumSamples)
filterKernelBasic = new Vector4[kNumSamples];
// Apply the three-sigma rule, and rescale.
var stdDev1 = ((1f / 3f) * kDistanceScale) * scatterDistance1;
var stdDev2 = ((1f / 3f) * kDistanceScale) * 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);
var weightSum = Vector3.zero;
float step = 1f / (kNumSamples - 1);
// Importance sample the linear combination of two Gaussians.
for (int i = 0; i < kNumSamples; i++)
{
// Generate 'u' on (0, 0.5] and (0.5, 1).
float u = (i <= kNumSamples / 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.
filterKernelBasic[i].x = val.x * (1 / pdf);
filterKernelBasic[i].y = val.y * (1 / pdf);
filterKernelBasic[i].z = val.z * (1 / pdf);
filterKernelBasic[i].w = pos;
weightSum.x += filterKernelBasic[i].x;
weightSum.y += filterKernelBasic[i].y;
weightSum.z += filterKernelBasic[i].z;
}
// Renormalize the weights to conserve energy.
for (int i = 0; i < kNumSamples; i++)
{
filterKernelBasic[i].x *= 1 / weightSum.x;
filterKernelBasic[i].y *= 1 / weightSum.y;
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.
// Warning: do not use halfRcpWeightedVariances.Set(). It will not work.
halfRcpWeightedVariances = new Vector4(0.5f / (weightedStdDev.x * weightedStdDev.x),
0.5f / (weightedStdDev.y * weightedStdDev.y),
0.5f / (weightedStdDev.z * weightedStdDev.z),
0.5f / (weightedStdDev.w * weightedStdDev.w));
}
// <<< Old SSS Model
static float DisneyProfile(float r, float s)
{
return s * (Mathf.Exp(-r * s) + Mathf.Exp(-r * s * (1.0f / 3.0f))) / (8.0f * Mathf.PI * r);
}
static float DisneyProfilePdf(float r, float s)
{
return r * DisneyProfile(r, s);
}
static float DisneyProfileCdf(float r, float s)
{
return 1.0f - 0.25f * Mathf.Exp(-r * s) - 0.75f * Mathf.Exp(-r * s * (1.0f / 3.0f));
}
static float DisneyProfileCdfDerivative1(float r, float s)
{
return 0.25f * s * Mathf.Exp(-r * s) * (1.0f + Mathf.Exp(r * s * (2.0f / 3.0f)));
}
static float DisneyProfileCdfDerivative2(float r, float s)
{
return (-1.0f / 12.0f) * s * s * Mathf.Exp(-r * s) * (3.0f + Mathf.Exp(r * s * (2.0f / 3.0f)));
}
// The CDF is not analytically invertible, so we use Halley's Method of root finding.
// { f(r, s, p) = CDF(r, s) - p = 0 } with the initial guess { r = (10^p - 1) / s }.
static float DisneyProfileCdfInverse(float p, float s)
{
// Supply the initial guess.
float r = (Mathf.Pow(10f, p) - 1f) / s;
float t = float.MaxValue;
while (true)
{
float f0 = DisneyProfileCdf(r, s) - p;
float f1 = DisneyProfileCdfDerivative1(r, s);
float f2 = DisneyProfileCdfDerivative2(r, s);
float dr = f0 / (f1 * (1f - f0 * f2 / (2f * f1 * f1)));
if (Mathf.Abs(dr) < t)
{
r = r - dr;
t = Mathf.Abs(dr);
}
else
{
// Converged to the best result.
break;
}
}
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(-2f * Mathf.Log(p)));
}
else
{
// F^-1(p) = G^-1(1-p)
x = RationalApproximation(Mathf.Sqrt(-2f * Mathf.Log(1f - 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
}
public sealed class DiffusionProfileSettings : ScriptableObject
{
public DiffusionProfile[] profiles;
[NonSerialized] public uint texturingModeFlags; // 1 bit/profile; 0 = PreAndPostScatter, 1 = PostScatter
[NonSerialized] public uint 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; // X = meters per world unit; Y = world units per meter
[NonSerialized] public Vector4[] shapeParams; // RGB = S = 1 / D, A = filter radius
[NonSerialized] public Vector4[] transmissionTintsAndFresnel0; // RGB = color, A = fresnel0
[NonSerialized] public Vector4[] filterKernels; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
// Old SSS Model >>>
[NonSerialized] public Vector4[] halfRcpWeightedVariances;
[NonSerialized] public Vector4[] halfRcpVariancesAndWeights;
[NonSerialized] public Vector4[] filterKernelsBasic;
// <<< Old SSS Model
public DiffusionProfile this[int index]
{
get
{
if (index >= DiffusionProfileConstants.DIFFUSION_N_PROFILES - 1)
throw new IndexOutOfRangeException("index");
return profiles[index];
}
}
void OnEnable()
{
// The neutral profile is not a part of the array.
int profileArraySize = DiffusionProfileConstants.DIFFUSION_N_PROFILES - 1;
if (profiles != null && profiles.Length != profileArraySize)
Array.Resize(ref profiles, profileArraySize);
if (profiles == null)
profiles = new DiffusionProfile[profileArraySize];
for (int i = 0; i < profileArraySize; i++)
{
if (profiles[i] == null)
profiles[i] = new DiffusionProfile("Profile " + (i + 1));
profiles[i].Validate();
}
ValidateArray(ref thicknessRemaps, DiffusionProfileConstants.DIFFUSION_N_PROFILES);
ValidateArray(ref worldScales, DiffusionProfileConstants.DIFFUSION_N_PROFILES);
ValidateArray(ref shapeParams, DiffusionProfileConstants.DIFFUSION_N_PROFILES);
ValidateArray(ref transmissionTintsAndFresnel0, DiffusionProfileConstants.DIFFUSION_N_PROFILES);
ValidateArray(ref filterKernels, DiffusionProfileConstants.DIFFUSION_N_PROFILES * DiffusionProfileConstants.SSS_N_SAMPLES_NEAR_FIELD);
// Old SSS Model >>>
ValidateArray(ref halfRcpWeightedVariances, DiffusionProfileConstants.DIFFUSION_N_PROFILES);
ValidateArray(ref halfRcpVariancesAndWeights, DiffusionProfileConstants.DIFFUSION_N_PROFILES * 2);
ValidateArray(ref filterKernelsBasic, DiffusionProfileConstants.DIFFUSION_N_PROFILES * DiffusionProfileConstants.SSS_BASIC_N_SAMPLES);
Debug.Assert(DiffusionProfileConstants.DIFFUSION_NEUTRAL_PROFILE_ID < 16, "Transmission flags (32-bit integer) cannot support more than 16 profiles (2 bits per profile).");
UpdateCache();
}
static void ValidateArray<T>(ref T[] array, int len)
{
if (array == null || array.Length != len)
array = new T[len];
}
public void UpdateCache()
{
for (int i = 0; i < DiffusionProfileConstants.DIFFUSION_N_PROFILES - 1; i++)
{
UpdateCache(i);
}
// Fill the neutral profile.
int neutralId = DiffusionProfileConstants.DIFFUSION_NEUTRAL_PROFILE_ID;
worldScales[neutralId] = Vector4.one;
shapeParams[neutralId] = Vector4.zero;
for (int j = 0, n = DiffusionProfileConstants.SSS_N_SAMPLES_NEAR_FIELD; j < n; j++)
{
filterKernels[n * neutralId + j].x = 0f;
filterKernels[n * neutralId + j].y = 1f;
filterKernels[n * neutralId + j].z = 0f;
filterKernels[n * neutralId + j].w = 1f;
}
// Old SSS Model >>>
halfRcpWeightedVariances[neutralId] = Vector4.one;
for (int j = 0, n = DiffusionProfileConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{
filterKernelsBasic[n * neutralId + j] = Vector4.one;
filterKernelsBasic[n * neutralId + j].w = 0f;
}
// <<< Old SSS Model
}
public void UpdateCache(int p)
{
// 'p' is the profile array index. 'i' is the index in the shader (accounting for the neutral profile).
int i = p + 1;
// Erase previous value (This need to be done here individually as in the SSS editor we edit individual component)
uint mask = 1u << i;
texturingModeFlags &= ~mask;
mask = 3u << i * 2;
transmissionFlags &= ~mask;
texturingModeFlags |= (uint)profiles[p].texturingMode << i;
transmissionFlags |= (uint)profiles[p].transmissionMode << i * 2;
thicknessRemaps[i] = new Vector4(profiles[p].thicknessRemap.x, profiles[p].thicknessRemap.y - profiles[p].thicknessRemap.x, 0f, 0f);
worldScales[i] = new Vector4(profiles[p].worldScale, 1.0f / profiles[p].worldScale, 0f, 0f);
shapeParams[i] = profiles[p].shapeParam;
shapeParams[i].w = profiles[p].maxRadius;
transmissionTintsAndFresnel0[i] = new Vector4(profiles[p].transmissionTint.r * 0.25f, profiles[p].transmissionTint.g * 0.25f, profiles[p].transmissionTint.b * 0.25f, profiles[p].fresnel0); // Premultiplied
for (int j = 0, n = DiffusionProfileConstants.SSS_N_SAMPLES_NEAR_FIELD; j < n; j++)
{
filterKernels[n * i + j].x = profiles[p].filterKernelNearField[j].x;
filterKernels[n * i + j].y = profiles[p].filterKernelNearField[j].y;
if (j < DiffusionProfileConstants.SSS_N_SAMPLES_FAR_FIELD)
{
filterKernels[n * i + j].z = profiles[p].filterKernelFarField[j].x;
filterKernels[n * i + j].w = profiles[p].filterKernelFarField[j].y;
}
}
// Old SSS Model >>>
halfRcpWeightedVariances[i] = profiles[p].halfRcpWeightedVariances;
var stdDev1 = ((1f / 3f) * DiffusionProfileConstants.SSS_BASIC_DISTANCE_SCALE) * (Vector4)profiles[p].scatterDistance1;
var stdDev2 = ((1f / 3f) * DiffusionProfileConstants.SSS_BASIC_DISTANCE_SCALE) * (Vector4)profiles[p].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 * DiffusionProfileConstants.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), 4f * (1f - profiles[p].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), 4f * profiles[p].lerpWeight);
for (int j = 0, n = DiffusionProfileConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{
filterKernelsBasic[n * i + j] = profiles[p].filterKernelBasic[j];
}
// <<< Old SSS Model
}
}
}

21
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.hlsl


//
// This file was automatically generated. Please don't edit by hand.
//
#ifndef SUBSURFACESCATTERINGSETTINGS_CS_HLSL
#define SUBSURFACESCATTERINGSETTINGS_CS_HLSL
//
// UnityEngine.Experimental.Rendering.HDPipeline.DiffusionProfileConstants: static fields
//
#define DIFFUSION_N_PROFILES (16)
#define DIFFUSION_NEUTRAL_PROFILE_ID (0)
#define SSS_N_SAMPLES_NEAR_FIELD (55)
#define SSS_N_SAMPLES_FAR_FIELD (21)
#define SSS_LOD_THRESHOLD (4)
#define TRANSMISSION_MODE_NONE (0)
#define TRANSMISSION_MODE_THIN (1)
#define SSS_BASIC_N_SAMPLES (11)
#define SSS_BASIC_DISTANCE_SCALE (3)
#endif

8
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/SubsurfaceScattering.meta


fileFormatVersion: 2
guid: fb3f658c087068440b2c5063fc3abaed
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

61
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/CommonSubsurfaceScattering.hlsl


// ----------------------------------------------------------------------------
// SSS/Transmittance helper
// ----------------------------------------------------------------------------
// 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 ComputeTransmittanceDisney(float3 S, 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;
#if 0
float3 expOneThird = exp(((-1.0 / 3.0) * thickness) * S);
#else
// Help the compiler.
float k = (-1.0 / 3.0) * LOG2_E;
float3 p = (k * thickness) * S;
float3 expOneThird = exp2(p);
#endif
// 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);
}
// In order to support subsurface scattering, we need to know which pixels have an SSS material.
// It can be accomplished by reading the stencil buffer.
// A faster solution (which avoids an extra texture fetch) is to simply make sure that
// all pixels which belong to an SSS material are not black (those that don't always are).
// We choose the blue color channel since it's perceptually the least noticeable.
float3 TagLightingForSSS(float3 subsurfaceLighting)
{
subsurfaceLighting.b = max(subsurfaceLighting.b, HALF_MIN);
return subsurfaceLighting;
}
// See TagLightingForSSS() for details.
bool TestLightingForSSS(float3 subsurfaceLighting)
{
return subsurfaceLighting.b > 0;
}

21
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs.hlsl


//
// This file was automatically generated. Please don't edit by hand.
//
#ifndef SUBSURFACESCATTERINGSETTINGS_CS_HLSL
#define SUBSURFACESCATTERINGSETTINGS_CS_HLSL
//
// UnityEngine.Experimental.Rendering.HDPipeline.SssConstants: static fields
//
#define SSS_N_PROFILES (16)
#define SSS_NEUTRAL_PROFILE_ID (0)
#define SSS_N_SAMPLES_NEAR_FIELD (55)
#define SSS_N_SAMPLES_FAR_FIELD (21)
#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

513
ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs


using System;
namespace UnityEngine.Experimental.Rendering.HDPipeline
{
[GenerateHLSL]
public class SssConstants
{
public const int SSS_N_PROFILES = 16; // Max. number of profiles, including the slot taken by the neutral profile
public const int SSS_NEUTRAL_PROFILE_ID = 0; // Does not result in blurring
public const int SSS_N_SAMPLES_NEAR_FIELD = 55; // Used for extreme close ups; must be a Fibonacci number
public const int SSS_N_SAMPLES_FAR_FIELD = 21; // Used at a regular distance; must be a Fibonacci number
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]
public sealed class SubsurfaceScatteringProfile
{
public enum TexturingMode : uint
{
PreAndPostScatter = 0,
PostScatter = 1
}
public enum TransmissionMode : uint
{
None = SssConstants.SSS_TRSM_MODE_NONE,
ThinObject = SssConstants.SSS_TRSM_MODE_THIN,
Regular
}
public string name;
[ColorUsage(false, true)]
public Color scatteringDistance; // Per color channel (no meaningful units)
[ColorUsage(false)]
public Color transmissionTint; // Color, 0 to 1
public TexturingMode texturingMode;
public TransmissionMode transmissionMode;
public Vector2 thicknessRemap; // X = min, Y = max (in millimeters)
public float worldScale; // Size of the world unit in meters
public float fresnel0; // Fresnel0, 0.028 for skin
// Old SSS Model >>>
[ColorUsage(false, true)]
public Color scatterDistance1;
[ColorUsage(false, true)]
public Color scatterDistance2;
[Range(0f, 1f)]
public float lerpWeight;
// <<< Old SSS Model
public Vector3 shapeParam { get; private set; } // RGB = shape parameter: S = 1 / D
public float maxRadius { get; private set; } // In millimeters
public Vector2[] filterKernelNearField { get; private set; } // X = radius, Y = reciprocal of the PDF
public Vector2[] filterKernelFarField { get; private set; } // X = radius, Y = reciprocal of the PDF
public Vector4 halfRcpWeightedVariances { get; private set; }
public Vector4[] filterKernelBasic { get; private set; }
public SubsurfaceScatteringProfile(string name)
{
this.name = name;
scatteringDistance = Color.grey;
transmissionTint = Color.white;
texturingMode = TexturingMode.PreAndPostScatter;
transmissionMode = TransmissionMode.None;
thicknessRemap = new Vector2(0f, 5f);
worldScale = 1f;
fresnel0 = 0.028f; // TYpical value for skin specular reflectance
// Old SSS Model >>>
scatterDistance1 = new Color(0.3f, 0.3f, 0.3f, 0f);
scatterDistance2 = new Color(0.5f, 0.5f, 0.5f, 0f);
lerpWeight = 1f;
// <<< Old SSS Model
}
public void Validate()
{
thicknessRemap.y = Mathf.Max(thicknessRemap.y, 0f);
thicknessRemap.x = Mathf.Clamp(thicknessRemap.x, 0f, thicknessRemap.y);
worldScale = Mathf.Max(worldScale, 0.001f);
fresnel0 = Mathf.Clamp(fresnel0, 0.0f, 0.1f);
// Old SSS Model >>>
scatterDistance1 = new Color
{
r = Mathf.Max(0.05f, scatterDistance1.r),
g = Mathf.Max(0.05f, scatterDistance1.g),
b = Mathf.Max(0.05f, scatterDistance1.b),
a = 0.0f
};
scatterDistance2 = new Color
{
r = Mathf.Max(0.05f, scatterDistance2.r),
g = Mathf.Max(0.05f, scatterDistance2.g),
b = Mathf.Max(0.05f, scatterDistance2.b),
a = 0f
};
// <<< Old SSS Model
UpdateKernel();
}
// Ref: Approximate Reflectance Profiles for Efficient Subsurface Scattering by Pixar.
public void UpdateKernel()
{
if (filterKernelNearField == null || filterKernelNearField.Length != SssConstants.SSS_N_SAMPLES_NEAR_FIELD)
filterKernelNearField = new Vector2[SssConstants.SSS_N_SAMPLES_NEAR_FIELD];
if (filterKernelFarField == null || filterKernelFarField.Length != SssConstants.SSS_N_SAMPLES_FAR_FIELD)
filterKernelFarField = new Vector2[SssConstants.SSS_N_SAMPLES_FAR_FIELD];
// Clamp to avoid artifacts.
shapeParam = new Vector3(
1f / Mathf.Max(0.001f, scatteringDistance.r),
1f / Mathf.Max(0.001f, scatteringDistance.g),
1f / Mathf.Max(0.001f, scatteringDistance.b)
);
// We importance sample the color channel with the widest scattering distance.
float s = Mathf.Min(shapeParam.x, shapeParam.y, shapeParam.z);
// Importance sample the normalized diffuse reflectance profile for the computed value of 's'.
// ------------------------------------------------------------------------------------
// R[r, phi, s] = s * (Exp[-r * s] + Exp[-r * s / 3]) / (8 * Pi * r)
// PDF[r, phi, s] = r * R[r, phi, s]
// CDF[r, s] = 1 - 1/4 * Exp[-r * s] - 3/4 * Exp[-r * s / 3]
// ------------------------------------------------------------------------------------
// Importance sample the near field kernel.
for (int i = 0, n = SssConstants.SSS_N_SAMPLES_NEAR_FIELD; i < n; i++)
{
float p = (i + 0.5f) * (1f / n);
float r = DisneyProfileCdfInverse(p, s);
// N.b.: computation of normalized weights, and multiplication by the surface albedo
// of the actual geometry is performed at runtime (in the shader).
filterKernelNearField[i].x = r;
filterKernelNearField[i].y = 1f / DisneyProfilePdf(r, s);
}
// Importance sample the far field kernel.
for (int i = 0, n = SssConstants.SSS_N_SAMPLES_FAR_FIELD; i < n; i++)
{
float p = (i + 0.5f) * (1f / n);
float r = DisneyProfileCdfInverse(p, s);
// N.b.: computation of normalized weights, and multiplication by the surface albedo
// of the actual geometry is performed at runtime (in the shader).
filterKernelFarField[i].x = r;
filterKernelFarField[i].y = 1f / DisneyProfilePdf(r, s);
}
maxRadius = filterKernelFarField[SssConstants.SSS_N_SAMPLES_FAR_FIELD - 1].x;
// Old SSS Model >>>
UpdateKernelAndVarianceData();
// <<< Old SSS Model
}
// Old SSS Model >>>
public void UpdateKernelAndVarianceData()
{
const int kNumSamples = SssConstants.SSS_BASIC_N_SAMPLES;
const int kDistanceScale = SssConstants.SSS_BASIC_DISTANCE_SCALE;
if (filterKernelBasic == null || filterKernelBasic.Length != kNumSamples)
filterKernelBasic = new Vector4[kNumSamples];
// Apply the three-sigma rule, and rescale.
var stdDev1 = ((1f / 3f) * kDistanceScale) * scatterDistance1;
var stdDev2 = ((1f / 3f) * kDistanceScale) * 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);
var weightSum = Vector3.zero;
float step = 1f / (kNumSamples - 1);
// Importance sample the linear combination of two Gaussians.
for (int i = 0; i < kNumSamples; i++)
{
// Generate 'u' on (0, 0.5] and (0.5, 1).
float u = (i <= kNumSamples / 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.
filterKernelBasic[i].x = val.x * (1 / pdf);
filterKernelBasic[i].y = val.y * (1 / pdf);
filterKernelBasic[i].z = val.z * (1 / pdf);
filterKernelBasic[i].w = pos;
weightSum.x += filterKernelBasic[i].x;
weightSum.y += filterKernelBasic[i].y;
weightSum.z += filterKernelBasic[i].z;
}
// Renormalize the weights to conserve energy.
for (int i = 0; i < kNumSamples; i++)
{
filterKernelBasic[i].x *= 1 / weightSum.x;
filterKernelBasic[i].y *= 1 / weightSum.y;
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.
// Warning: do not use halfRcpWeightedVariances.Set(). It will not work.
halfRcpWeightedVariances = new Vector4(0.5f / (weightedStdDev.x * weightedStdDev.x),
0.5f / (weightedStdDev.y * weightedStdDev.y),
0.5f / (weightedStdDev.z * weightedStdDev.z),
0.5f / (weightedStdDev.w * weightedStdDev.w));
}
// <<< Old SSS Model
static float DisneyProfile(float r, float s)
{
return s * (Mathf.Exp(-r * s) + Mathf.Exp(-r * s * (1.0f / 3.0f))) / (8.0f * Mathf.PI * r);
}
static float DisneyProfilePdf(float r, float s)
{
return r * DisneyProfile(r, s);
}
static float DisneyProfileCdf(float r, float s)
{
return 1.0f - 0.25f * Mathf.Exp(-r * s) - 0.75f * Mathf.Exp(-r * s * (1.0f / 3.0f));
}
static float DisneyProfileCdfDerivative1(float r, float s)
{
return 0.25f * s * Mathf.Exp(-r * s) * (1.0f + Mathf.Exp(r * s * (2.0f / 3.0f)));
}
static float DisneyProfileCdfDerivative2(float r, float s)
{
return (-1.0f / 12.0f) * s * s * Mathf.Exp(-r * s) * (3.0f + Mathf.Exp(r * s * (2.0f / 3.0f)));
}
// The CDF is not analytically invertible, so we use Halley's Method of root finding.
// { f(r, s, p) = CDF(r, s) - p = 0 } with the initial guess { r = (10^p - 1) / s }.
static float DisneyProfileCdfInverse(float p, float s)
{
// Supply the initial guess.
float r = (Mathf.Pow(10f, p) - 1f) / s;
float t = float.MaxValue;
while (true)
{
float f0 = DisneyProfileCdf(r, s) - p;
float f1 = DisneyProfileCdfDerivative1(r, s);
float f2 = DisneyProfileCdfDerivative2(r, s);
float dr = f0 / (f1 * (1f - f0 * f2 / (2f * f1 * f1)));
if (Mathf.Abs(dr) < t)
{
r = r - dr;
t = Mathf.Abs(dr);
}
else
{
// Converged to the best result.
break;
}
}
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(-2f * Mathf.Log(p)));
}
else
{
// F^-1(p) = G^-1(1-p)
x = RationalApproximation(Mathf.Sqrt(-2f * Mathf.Log(1f - 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
}
public sealed class SubsurfaceScatteringSettings : ScriptableObject
{
public SubsurfaceScatteringProfile[] profiles;
[NonSerialized] public uint texturingModeFlags; // 1 bit/profile; 0 = PreAndPostScatter, 1 = PostScatter
[NonSerialized] public uint 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; // X = meters per world unit; Y = world units per meter
[NonSerialized] public Vector4[] shapeParams; // RGB = S = 1 / D, A = filter radius
[NonSerialized] public Vector4[] transmissionTintsAndFresnel0; // RGB = color, A = fresnel0
[NonSerialized] public Vector4[] filterKernels; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
// Old SSS Model >>>
[NonSerialized] public Vector4[] halfRcpWeightedVariances;
[NonSerialized] public Vector4[] halfRcpVariancesAndWeights;
[NonSerialized] public Vector4[] filterKernelsBasic;
// <<< Old SSS Model
public SubsurfaceScatteringProfile this[int index]
{
get
{
if (index >= SssConstants.SSS_N_PROFILES - 1)
throw new IndexOutOfRangeException("index");
return profiles[index];
}
}
void OnEnable()
{
// The neutral profile is not a part of the array.
int profileArraySize = SssConstants.SSS_N_PROFILES - 1;
if (profiles != null && profiles.Length != profileArraySize)
Array.Resize(ref profiles, profileArraySize);
if (profiles == null)
profiles = new SubsurfaceScatteringProfile[profileArraySize];
for (int i = 0; i < profileArraySize; i++)
{
if (profiles[i] == null)
profiles[i] = new SubsurfaceScatteringProfile("Profile " + (i + 1));
profiles[i].Validate();
}
ValidateArray(ref thicknessRemaps, SssConstants.SSS_N_PROFILES);
ValidateArray(ref worldScales, SssConstants.SSS_N_PROFILES);
ValidateArray(ref shapeParams, SssConstants.SSS_N_PROFILES);
ValidateArray(ref transmissionTintsAndFresnel0, SssConstants.SSS_N_PROFILES);
ValidateArray(ref filterKernels, SssConstants.SSS_N_PROFILES * SssConstants.SSS_N_SAMPLES_NEAR_FIELD);
// Old SSS Model >>>
ValidateArray(ref halfRcpWeightedVariances, SssConstants.SSS_N_PROFILES);
ValidateArray(ref halfRcpVariancesAndWeights, SssConstants.SSS_N_PROFILES * 2);
ValidateArray(ref filterKernelsBasic, SssConstants.SSS_N_PROFILES * SssConstants.SSS_BASIC_N_SAMPLES);
Debug.Assert(SssConstants.SSS_NEUTRAL_PROFILE_ID < 16, "Transmission flags (32-bit integer) cannot support more than 16 profiles (2 bits per profile).");
UpdateCache();
}
static void ValidateArray<T>(ref T[] array, int len)
{
if (array == null || array.Length != len)
array = new T[len];
}
public void UpdateCache()
{
for (int i = 0; i < SssConstants.SSS_N_PROFILES - 1; i++)
{
UpdateCache(i);
}
// Fill the neutral profile.
int neutralId = SssConstants.SSS_NEUTRAL_PROFILE_ID;
worldScales[neutralId] = Vector4.one;
shapeParams[neutralId] = Vector4.zero;
for (int j = 0, n = SssConstants.SSS_N_SAMPLES_NEAR_FIELD; j < n; j++)
{
filterKernels[n * neutralId + j].x = 0f;
filterKernels[n * neutralId + j].y = 1f;
filterKernels[n * neutralId + j].z = 0f;
filterKernels[n * neutralId + j].w = 1f;
}
// Old SSS Model >>>
halfRcpWeightedVariances[neutralId] = Vector4.one;
for (int j = 0, n = SssConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{
filterKernelsBasic[n * neutralId + j] = Vector4.one;
filterKernelsBasic[n * neutralId + j].w = 0f;
}
// <<< Old SSS Model
}
public void UpdateCache(int p)
{
// 'p' is the profile array index. 'i' is the index in the shader (accounting for the neutral profile).
int i = p + 1;
// Erase previous value (This need to be done here individually as in the SSS editor we edit individual component)
uint mask = 1u << i;
texturingModeFlags &= ~mask;
mask = 3u << i * 2;
transmissionFlags &= ~mask;
texturingModeFlags |= (uint)profiles[p].texturingMode << i;
transmissionFlags |= (uint)profiles[p].transmissionMode << i * 2;
thicknessRemaps[i] = new Vector4(profiles[p].thicknessRemap.x, profiles[p].thicknessRemap.y - profiles[p].thicknessRemap.x, 0f, 0f);
worldScales[i] = new Vector4(profiles[p].worldScale, 1.0f / profiles[p].worldScale, 0f, 0f);
shapeParams[i] = profiles[p].shapeParam;
shapeParams[i].w = profiles[p].maxRadius;
transmissionTintsAndFresnel0[i] = new Vector4(profiles[p].transmissionTint.r * 0.25f, profiles[p].transmissionTint.g * 0.25f, profiles[p].transmissionTint.b * 0.25f, profiles[p].fresnel0); // Premultiplied
for (int j = 0, n = SssConstants.SSS_N_SAMPLES_NEAR_FIELD; j < n; j++)
{
filterKernels[n * i + j].x = profiles[p].filterKernelNearField[j].x;
filterKernels[n * i + j].y = profiles[p].filterKernelNearField[j].y;
if (j < SssConstants.SSS_N_SAMPLES_FAR_FIELD)
{
filterKernels[n * i + j].z = profiles[p].filterKernelFarField[j].x;
filterKernels[n * i + j].w = profiles[p].filterKernelFarField[j].y;
}
}
// Old SSS Model >>>
halfRcpWeightedVariances[i] = profiles[p].halfRcpWeightedVariances;
var stdDev1 = ((1f / 3f) * SssConstants.SSS_BASIC_DISTANCE_SCALE) * (Vector4)profiles[p].scatterDistance1;
var stdDev2 = ((1f / 3f) * SssConstants.SSS_BASIC_DISTANCE_SCALE) * (Vector4)profiles[p].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), 4f * (1f - profiles[p].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), 4f * profiles[p].lerpWeight);
for (int j = 0, n = SssConstants.SSS_BASIC_N_SAMPLES; j < n; j++)
{
filterKernelsBasic[n * i + j] = profiles[p].filterKernelBasic[j];
}
// <<< Old SSS Model
}
}
}

9
ScriptableRenderPipeline/HDRenderPipeline/HDRP/SceneSettings.meta


fileFormatVersion: 2
guid: 1b5e87e98ef1994498478f60a6dcdd65
folderAsset: yes
timeCreated: 1481725797
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/CommonSubsurfaceScattering.hlsl.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfile.hlsl.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs.hlsl.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.hlsl.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SubsurfaceScatteringSettings.cs.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile/DiffusionProfileSettings.cs.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SSSProfile.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/DiffusionProfile.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/SubsurfaceScattering/SubsurfaceScatteringSettingsEditor.Styles.cs.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.Styles.cs.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/SubsurfaceScattering/SubsurfaceScatteringSettingsEditor.cs.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/SubsurfaceScattering/SubsurfaceScatteringSettingsEditor.Styles.cs → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.Styles.cs

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/SubsurfaceScattering/SubsurfaceScatteringSettingsEditor.cs → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DiffusionProfileSettingsEditor.cs

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/Material/SubsurfaceScattering/SSSProfile/SSS Settings.asset → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/RenderPipelineResources/Default Diffusion Profile Settings.asset

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/SceneSettings/Resources/DrawSssProfile.shader.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawDiffusionProfile.shader.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/SceneSettings/Resources/DrawTransmittanceGraph.shader.meta → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawTransmittanceGraph.shader.meta

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/SceneSettings/Resources/DrawSssProfile.shader → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawDiffusionProfile.shader

/ScriptableRenderPipeline/HDRenderPipeline/HDRP/SceneSettings/Resources/DrawTransmittanceGraph.shader → /ScriptableRenderPipeline/HDRenderPipeline/HDRP/Editor/Material/DiffusionProfile/DrawTransmittanceGraph.shader

正在加载...
取消
保存