浏览代码

Merge pull request #637 from EvgeniiG/master

Add shadowing to the regular ("thick object") transmission mode
/main
GitHub 7 年前
当前提交
7a242318
共有 8 个文件被更改,包括 94 次插入83 次删除
  1. 5
      ScriptableRenderPipeline/Core/ShaderLibrary/Macros.hlsl
  2. 7
      ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs
  3. 2
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs
  4. 8
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl
  5. 143
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl
  6. 3
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/SubsurfaceScattering.compute
  7. 5
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/SubsurfaceScattering.shader
  8. 4
      ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringSettings.cs

5
ScriptableRenderPipeline/Core/ShaderLibrary/Macros.hlsl


#define LOG2_E 1.44269504088896340736
#define INFINITY asfloat(0x7F800000)
#define MILLIMETERS_PER_METER 1000
#define METERS_PER_MILLIMETER rcp(MILLIMETERS_PER_METER)
#define CENTIMETERS_PER_METER 100
#define METERS_PER_CENTIMETER rcp(CENTIMETERS_PER_METER)
#define FLT_EPS 5.960464478e-8 // 2^-24, machine epsilon: 1 + EPS = 1 (half of the ULP for 1)
#define FLT_MIN 1.175494351e-38 // Minimum representable positive floating-point number
#define FLT_MAX 3.402823466e+38 // Maximum representable floating-point number

7
ScriptableRenderPipeline/HDRenderPipeline/HDRenderPipeline.cs


cmd.SetGlobalVectorArray(HDShaderIDs._ShapeParams, sssParameters.shapeParams);
cmd.SetGlobalVectorArray(HDShaderIDs._HalfRcpVariancesAndWeights, sssParameters.halfRcpVariancesAndWeights);
cmd.SetGlobalVectorArray(HDShaderIDs._TransmissionTints, sssParameters.transmissionTints);
cmd.SetGlobalVectorArray(HDShaderIDs._WorldScales, sssParameters.worldScales);
}
}

cmd.SetComputeFloatParam(m_SubsurfaceScatteringCS, HDShaderIDs._TexturingModeFlags, *(float*)&texturingModeFlags);
}
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._WorldScales, sssParameters.worldScales);
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._FilterKernels, sssParameters.filterKernels);
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._ShapeParams, sssParameters.shapeParams);
cmd.SetComputeVectorArrayParam(m_SubsurfaceScatteringCS, HDShaderIDs._FilterKernels, sssParameters.filterKernels);
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._GBufferTexture0, m_GbufferManager.GetGBuffers()[0]);
cmd.SetComputeTextureParam(m_SubsurfaceScatteringCS, m_SubsurfaceScatteringKernel, HDShaderIDs._GBufferTexture1, m_GbufferManager.GetGBuffers()[1]);

else
{
cmd.SetGlobalTexture(HDShaderIDs._IrradianceSource, m_CameraSssDiffuseLightingBufferRT); // Cannot set a RT on a material
m_SssVerticalFilterPass.SetVectorArray(HDShaderIDs._WorldScales, sssParameters.worldScales);
m_SssVerticalFilterPass.SetVectorArray(HDShaderIDs._FilterKernelsBasic, sssParameters.filterKernelsBasic);
m_SssVerticalFilterPass.SetVectorArray(HDShaderIDs._HalfRcpWeightedVariances, sssParameters.halfRcpWeightedVariances);
// Perform the vertical SSS filtering pass which fills 'm_CameraFilteringBufferRT'.

m_SssHorizontalFilterAndCombinePass.SetVectorArray(HDShaderIDs._WorldScales, sssParameters.worldScales);
m_SssHorizontalFilterAndCombinePass.SetVectorArray(HDShaderIDs._FilterKernelsBasic, sssParameters.filterKernelsBasic);
m_SssHorizontalFilterAndCombinePass.SetVectorArray(HDShaderIDs._HalfRcpWeightedVariances, sssParameters.halfRcpWeightedVariances);
// Perform the horizontal SSS filtering pass, and combine diffuse and specular lighting into 'm_CameraColorBufferRT'.

2
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs


public float thickness;
public int subsurfaceProfile;
public bool enableTransmission; // Read from the SSS profile
public bool useThinObjectMode; // Read from the SSS profile
public bool useThickObjectMode; // Read from the SSS profile
public Vector3 transmittance;
// SpecColor

8
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.cs.hlsl


#define DEBUGVIEW_LIT_BSDFDATA_THICKNESS (1042)
#define DEBUGVIEW_LIT_BSDFDATA_SUBSURFACE_PROFILE (1043)
#define DEBUGVIEW_LIT_BSDFDATA_ENABLE_TRANSMISSION (1044)
#define DEBUGVIEW_LIT_BSDFDATA_USE_THIN_OBJECT_MODE (1045)
#define DEBUGVIEW_LIT_BSDFDATA_USE_THICK_OBJECT_MODE (1045)
#define DEBUGVIEW_LIT_BSDFDATA_TRANSMITTANCE (1046)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_NORMAL_WS (1047)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_COVERAGE (1048)

float thickness;
int subsurfaceProfile;
bool enableTransmission;
bool useThinObjectMode;
bool useThickObjectMode;
float3 transmittance;
float3 coatNormalWS;
float coatCoverage;

case DEBUGVIEW_LIT_BSDFDATA_ENABLE_TRANSMISSION:
result = (bsdfdata.enableTransmission) ? float3(1.0, 1.0, 1.0) : float3(0.0, 0.0, 0.0);
break;
case DEBUGVIEW_LIT_BSDFDATA_USE_THIN_OBJECT_MODE:
result = (bsdfdata.useThinObjectMode) ? float3(1.0, 1.0, 1.0) : float3(0.0, 0.0, 0.0);
case DEBUGVIEW_LIT_BSDFDATA_USE_THICK_OBJECT_MODE:
result = (bsdfdata.useThickObjectMode) ? float3(1.0, 1.0, 1.0) : float3(0.0, 0.0, 0.0);
break;
case DEBUGVIEW_LIT_BSDFDATA_TRANSMITTANCE:
result = bsdfdata.transmittance;

143
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Lit.hlsl


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 _TransmissionTints[SSS_N_PROFILES]; // RGB = 1/4 * color, A = unused
float4 _WorldScales[SSS_N_PROFILES]; // X = meters per world unit; Y = world units per meter
CBUFFER_END
//-----------------------------------------------------------------------------

{
bsdfData.diffuseColor = baseColor;
bsdfData.fresnel0 = SKIN_SPECULAR_VALUE; // TODO take from subsurfaceProfile instead
bsdfData.subsurfaceProfile = subsurfaceProfile;
bsdfData.subsurfaceRadius = subsurfaceRadius;
bsdfData.thickness = _ThicknessRemaps[subsurfaceProfile].x + _ThicknessRemaps[subsurfaceProfile].y * thickness;
bsdfData.useThinObjectMode = true; // Do not displace the point of BSDF evaluation
bsdfData.useThinObjectMode = transmissionMode == SSS_TRSM_MODE_THIN;
bsdfData.subsurfaceProfile = subsurfaceProfile;
bsdfData.subsurfaceRadius = subsurfaceRadius;
bsdfData.useThickObjectMode = transmissionMode != SSS_TRSM_MODE_THIN;
bsdfData.thickness = _ThicknessRemaps[subsurfaceProfile].x + _ThicknessRemaps[subsurfaceProfile].y * thickness;
if (_UseDisneySSS != 0)
{

diffuseLighting = diffuseTerm;
}
// In the "thin object" mode (for cards), we assume that the geometry is very thin.
// We apply wrapped lighting to compensate for that, and do not modify the shading position.
// Otherwise, in the "thick object" mode, we can have EITHER reflected (front) lighting
// OR transmitted (back) lighting, never both at the same time. For transmitted lighting,
// we need to push the shading position back to avoid self-shadowing problems.
float3 ComputeThicknessDisplacement(BSDFData bsdfData, float3 L, float NdotL)
{
// Compute the thickness in world units along the normal.
float thicknessInMeters = bsdfData.thickness * METERS_PER_MILLIMETER;
float thicknessInUnits = thicknessInMeters * _WorldScales[bsdfData.subsurfaceProfile].y;
// Compute the thickness in world units along the light vector.
float unprojectedThickness = thicknessInUnits / -NdotL;
return unprojectedThickness * L;
}
// We assume that the back side of the object is a uniformly illuminated infinite plane
// with the reversed normal (and the view vector) of the current sample.
float3 EvaluateTransmission(BSDFData bsdfData, float intensity, float shadow)
// Transmitted lighting is computed as follows:
// - we assume that the object is a thick plane (slab);
// - we reverse the front-facing normal for the back of the object;
// - we assume that the incoming radiance is constant along the entire back surface;
// - we apply BSDF-specific diffuse transmission to transmit the light subsurface and back;
// - we integrate the diffuse reflectance profile w.r.t. the radius (while also accounting
// for the thickness) to compute the transmittance;
// - we multiply the transmitted radiance by the transmittance.
float3 EvaluateTransmission(BSDFData bsdfData, float NdotL, float NdotV, float attenuation)
// For low thickness, we can reuse the shadowing status for the back of the object.
shadow = bsdfData.useThinObjectMode ? shadow : 1.0;
float wrappedNdotL = ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
float negatedNdotL = saturate(-NdotL);
// Apply wrapped lighting to better handle thin objects (cards) at grazing angles.
float backNdotL = bsdfData.useThickObjectMode ? negatedNdotL : wrappedNdotL;
float backLight = intensity * shadow;
// Apply BSDF-specific diffuse transmission to attenuation. See also: [SSS-NOTE-TRSM]
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
attenuation *= Lambert();
#else
attenuation *= INV_PI * F_Transm_Schlick(0, 0.5, NdotV) * F_Transm_Schlick(0, 0.5, backNdotL);
#endif
return backLight * bsdfData.transmittance; // Premultiplied with the diffuse color
float intensity = attenuation * backNdotL;
return intensity * bsdfData.transmittance;
}
//-----------------------------------------------------------------------------

void EvaluateLight_Directional(LightLoopContext lightLoopContext, PositionInputs posInput,
DirectionalLightData lightData, BakeLightingData bakeLightingData,
float3 N, float3 L,
out float3 color, out float attenuation, out float shadow)
out float3 color, out float attenuation)
float shadow = 1.0;
shadow = 1.0;
#ifdef SHADOWS_SHADOWMASK
// shadowMaskSelector.x is -1 if there is no shadow mask

#endif
}
attenuation *= shadow;
[branch] if (lightData.cookieIndex >= 0)
{
float3 lightToSample = positionWS - lightData.positionWS;

DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 positionWS = posInput.positionWS;
float3 color; float attenuation, shadow;
[flatten] if (bsdfData.useThickObjectMode && NdotL < 0)
{
posInput.positionWS += ComputeThicknessDisplacement(bsdfData, L, NdotL);
}
float3 color; float attenuation;
color, attenuation, shadow);
color, attenuation);
float intensity = shadow * attenuation * saturate(NdotL);
float intensity = attenuation * saturate(NdotL);
BSDF(V, L, positionWS, preLightData, bsdfData, lighting.diffuse, lighting.specular);
BSDF(V, L, posInput.positionWS, preLightData, bsdfData, lighting.diffuse, lighting.specular);
lighting.diffuse *= intensity * lightData.diffuseScale;
lighting.specular *= intensity * lightData.specularScale;

{
// Apply wrapped lighting to better handle thin objects (cards) at grazing angles.
float wrappedNdotL = ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
// Apply the BSDF to attenuation. See also: [SSS-NOTE-TRSM]
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
attenuation *= Lambert();
#else
float tNdotL = saturate(-NdotL);
float NdotV = preLightData.NdotV;
attenuation *= INV_PI * F_Transm_Schlick(0, 0.5, NdotV) * F_Transm_Schlick(0, 0.5, tNdotL);
#endif
// Shadowing is applied inside EvaluateTransmission().
intensity = attenuation * wrappedNdotL;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse += EvaluateTransmission(bsdfData, intensity * lightData.diffuseScale, shadow);
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, preLightData.NdotV, attenuation * lightData.diffuseScale);
}
// Save ALU by applying light and cookie colors only once.

void EvaluateLight_Punctual(LightLoopContext lightLoopContext, PositionInputs posInput,
LightData lightData, BakeLightingData bakeLightingData,
float3 N, float3 L, float distSq,
out float3 color, out float attenuation, out float shadow)
out float3 color, out float attenuation)
float shadow = 1.0;
shadow = 1.0;
#ifdef SHADOWS_SHADOWMASK
// shadowMaskSelector.x is -1 if there is no shadow mask

#endif
}
attenuation *= shadow;
// Projector lights always have cookies, so we can perform clipping inside the if().
[branch] if (lightData.cookieIndex >= 0)
{

DirectLighting lighting;
ZERO_INITIALIZE(DirectLighting, lighting);
float3 positionWS = posInput.positionWS;
float3 lightToSample = positionWS - lightData.positionWS;
float3 lightToSample = posInput.positionWS - lightData.positionWS;
int lightType = lightData.lightType;
float3 unL = (lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? -lightToSample : -lightData.forward;

float NdotL = dot(N, L);
float3 color; float attenuation, shadow;
[flatten] if (bsdfData.useThickObjectMode && NdotL < 0)
{
posInput.positionWS += ComputeThicknessDisplacement(bsdfData, L, NdotL);
}
float3 color; float attenuation;
color, attenuation, shadow);
color, attenuation);
float intensity = shadow * attenuation * saturate(NdotL);
float intensity = attenuation * saturate(NdotL);
[branch] if (intensity > 0.0)
{

BSDF(V, L, positionWS, preLightData, bsdfData, lighting.diffuse, lighting.specular);
BSDF(V, L, posInput.positionWS, preLightData, bsdfData, lighting.diffuse, lighting.specular);
lighting.diffuse *= intensity * lightData.diffuseScale;
lighting.specular *= intensity * lightData.specularScale;

{
// Apply wrapped lighting to better handle thin objects (cards) at grazing angles.
float wrappedNdotL = ComputeWrappedDiffuseLighting(-NdotL, SSS_WRAP_LIGHT);
// Apply the BSDF to attenuation. See also: [SSS-NOTE-TRSM]
#ifdef LIT_DIFFUSE_LAMBERT_BRDF
attenuation *= Lambert();
#else
float tNdotL = saturate(-NdotL);
float NdotV = preLightData.NdotV;
attenuation *= INV_PI * F_Transm_Schlick(0, 0.5, NdotV) * F_Transm_Schlick(0, 0.5, tNdotL);
#endif
// Shadowing is applied inside EvaluateTransmission().
intensity = attenuation * wrappedNdotL;
// We don't multiply by 'bsdfData.diffuseColor' here. It's done only once in PostEvaluateBSDF().
lighting.diffuse += EvaluateTransmission(bsdfData, intensity * lightData.diffuseScale, shadow);
lighting.diffuse += EvaluateTransmission(bsdfData, NdotL, preLightData.NdotV, attenuation * lightData.diffuseScale);
}
// Save ALU by applying light and cookie colors only once.

// Use the Lambertian approximation for performance reasons.
// The matrix multiplication should not generate any extra ALU on GCN.
// TODO: double evaluation is very inefficient! This is a temporary solution.
lighting.diffuse += EvaluateTransmission(bsdfData, ltcValue, 1);
lighting.diffuse += bsdfData.transmittance * ltcValue;
}
// Evaluate the coat part

float3x3 ltcTransform = mul(flipMatrix, k_identity3x3);
// Polygon irradiance in the transformed configuration.
// TODO: double evaluation is very inefficient! This is a temporary solution.
lighting.diffuse += EvaluateTransmission(bsdfData, ltcValue, 1);
lighting.diffuse += bsdfData.transmittance * ltcValue;
}
// Evaluate the coat part

3
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/SubsurfaceScattering.compute


// Do not modify these.
#include "../../../ShaderPass/ShaderPass.cs.hlsl"
#define SHADERPASS SHADERPASS_SUBSURFACE_SCATTERING
#define MILLIMETERS_PER_METER 1000
#define CENTIMETERS_PER_METER 100
#define GROUP_SIZE_1D 16
#define GROUP_SIZE_2D (GROUP_SIZE_1D * GROUP_SIZE_1D)
#define TEXTURE_CACHE_BORDER 2

// Inputs & outputs
//--------------------------------------------------------------------------------------------------
float4 _WorldScales[SSS_N_PROFILES]; // Size of the world unit in meters (only the X component is used)
float4 _FilterKernels[SSS_N_PROFILES][SSS_N_SAMPLES_NEAR_FIELD]; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF
TEXTURE2D(_DepthTexture); // Z-buffer

5
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/Resources/SubsurfaceScattering.shader


// Do not modify these.
#include "../../../ShaderPass/ShaderPass.cs.hlsl"
#define SHADERPASS SHADERPASS_SUBSURFACE_SCATTERING
#define MILLIMETERS_PER_METER 1000
#define CENTIMETERS_PER_METER 100
#define SHADERPASS SHADERPASS_SUBSURFACE_SCATTERING
//-------------------------------------------------------------------------------------
// Include

// Inputs & outputs
//-------------------------------------------------------------------------------------
float4 _WorldScales[SSS_N_PROFILES]; // Size of the world unit in meters (only the X component is used)
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

4
ScriptableRenderPipeline/HDRenderPipeline/Material/Lit/SubsurfaceScatteringSettings.cs


[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; // Size of the world unit in meters (only the X component is used)
[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[] transmissionTints; // RGB = color, A = unused
[NonSerialized] public Vector4[] filterKernels; // XY = near field, ZW = far field; 0 = radius, 1 = reciprocal of the PDF

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, 0f, 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;
transmissionTints[i] = profiles[p].transmissionTint * 0.25f; // Premultiplied

正在加载...
取消
保存