浏览代码

Implement SSS transmittance for punctual and directional lights

/Branch_Batching2
Evgenii Golubev 7 年前
当前提交
02b8a18b
共有 5 个文件被更改,包括 132 次插入38 次删除
  1. 8
      Assets/ScriptableRenderLoop/HDRenderPipeline/HDRenderPipeline.cs
  2. 12
      Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl
  3. 8
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.cs
  4. 8
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.cs.hlsl
  5. 134
      Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.hlsl

8
Assets/ScriptableRenderLoop/HDRenderPipeline/HDRenderPipeline.cs


}
}
public void PushGlobalParams(HDCamera hdCamera, ScriptableRenderContext renderContext)
public void PushGlobalParams(HDCamera hdCamera, ScriptableRenderContext renderContext, SubsurfaceScatteringParameters sssParameters)
{
if (m_SkyManager.IsSkyValid())
{

{
Shader.SetGlobalInt("_EnvLightSkyEnabled", 0);
}
// Broadcast SSS parameters to all shaders.
Shader.SetGlobalInt("_TransmittanceFlags", sssParameters.transmittanceFlags);
Shader.SetGlobalVectorArray("_HalfRcpVariancesAndLerpWeights", sssParameters.halfRcpVariancesAndLerpWeights);
var cmd = new CommandBuffer {name = "Push Global Parameters"};

}
}
PushGlobalParams(hdCamera, renderContext);
PushGlobalParams(hdCamera, renderContext, m_Owner.sssParameters);
// Caution: We require sun light here as some sky use the sun light to render, mean UpdateSkyEnvironment
// must be call after BuildGPULightLists.

12
Assets/ScriptableRenderLoop/HDRenderPipeline/Lighting/TilePass/TilePass.hlsl


// Shadow sampling function
// ----------------------------------------------------------------------------
float GetPunctualShadowAttenuation(LightLoopContext lightLoopContext, uint lightType, float3 positionWS, int index, float3 L, float2 unPositionSS)
float GetPunctualShadowAttenuation(LightLoopContext lightLoopContext, uint lightType, float3 positionWS, int index, float3 L, float2 unPositionSS, float bias)
{
int faceIndex = 0;
if (lightType == GPULIGHTTYPE_POINT)

// Note: scale and bias of shadow atlas are included in ShadowTransform but could be apply here.
float4 positionTXS = mul(float4(positionWS, 1.0), shadowData.worldToShadow);
positionTXS.xyz /= positionTXS.w;
// positionTXS.z -= shadowData.bias; // Apply a linear bias
positionTXS.z -= 0.001;
// positionTXS.z -= shadowData.bias;
positionTXS.z -= (bias + 0.001); // Apply a linear bias
#if UNITY_REVERSED_Z
positionTXS.z = 1.0 - positionTXS.z;

return int(4.0 - dot(weights, float4(4.0, 3.0, 2.0, 1.0)));
}
float GetDirectionalShadowAttenuation(LightLoopContext lightLoopContext, float3 positionWS, int index, float3 L, float2 unPositionSS)
float GetDirectionalShadowAttenuation(LightLoopContext lightLoopContext, float3 positionWS, int index, float3 L, float2 unPositionSS, float bias)
{
// Note Index is 0 for now, but else we need to provide the correct index in _DirShadowSplitSpheres and _ShadowDatas
int shadowSplitIndex = GetSplitSphereIndexForDirshadows(positionWS, _DirShadowSplitSpheres);

// Note: scale and bias of shadow atlas are included in ShadowTransform but could be apply here.
float4 positionTXS = mul(float4(positionWS, 1.0), shadowData.worldToShadow);
positionTXS.xyz /= positionTXS.w;
// positionTXS.z -= shadowData.bias; // Apply a linear bias
positionTXS.z -= 0.003;
// positionTXS.z -= shadowData.bias;
positionTXS.z -= (bias + 0.003); // Apply a linear bias
#if UNITY_REVERSED_Z
positionTXS.z = 1.0 - positionTXS.z;

8
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.cs


// fold into fresnel0
// SSS
public float subsurfaceRadius;
public float thickness;
public int subsurfaceProfile;
public float subsurfaceRadius;
public float thickness;
public int subsurfaceProfile;
public bool enableTransmittance;
public Vector3 transmittance;
// Clearcoat
public Vector3 coatNormalWS;

8
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.cs.hlsl


#define DEBUGVIEW_LIT_BSDFDATA_SUBSURFACE_RADIUS (1042)
#define DEBUGVIEW_LIT_BSDFDATA_THICKNESS (1043)
#define DEBUGVIEW_LIT_BSDFDATA_SUBSURFACE_PROFILE (1044)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_NORMAL_WS (1045)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_ROUGHNESS (1046)
#define DEBUGVIEW_LIT_BSDFDATA_ENABLE_TRANSMITTANCE (1045)
#define DEBUGVIEW_LIT_BSDFDATA_TRANSMITTANCE (1046)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_NORMAL_WS (1047)
#define DEBUGVIEW_LIT_BSDFDATA_COAT_ROUGHNESS (1048)
//
// UnityEngine.Experimental.Rendering.HDPipeline.Lit.GBufferMaterial: static fields

float subsurfaceRadius;
float thickness;
int subsurfaceProfile;
bool enableTransmittance;
float3 transmittance;
float3 coatNormalWS;
float coatRoughness;
};

134
Assets/ScriptableRenderLoop/HDRenderPipeline/Material/Lit/Lit.hlsl


#define LTC_DISNEY_DIFFUSE_MATRIX_INDEX 1 // RGBA
#define LTC_MULTI_GGX_FRESNEL_DISNEY_DIFFUSE_INDEX 2 // RGB, A unused
// SSS parameters
#define N_PROFILES 8
uint _TransmittanceFlags; // One bit per profile; 1 = enabled
float4 _HalfRcpVariancesAndLerpWeights[N_PROFILES][2]; // 2x Gaussians per color channel, A is the the associated interpolation weight
//-----------------------------------------------------------------------------
// Helper functions/variable specific to this material
//-----------------------------------------------------------------------------

#endif
}
// Evaluates transmittance for a linear combination of two normalized 2D Gaussians.
// Computes results for each color channel separately.
// Ref: Real-Time Realistic Skin Translucency (2010), equation 9 (modified).
float3 ComputeTransmittance(float3 halfRcpVariance1, float lerpWeight1,
float3 halfRcpVariance2, float lerpWeight2,
float thickness, float radiusScale)
{
// To be consistent with SSS, we modify the thickness instead of scaling the radius of the profile.
thickness /= radiusScale;
float t2 = thickness * thickness;
// TODO: 6 exponentials is kind of expensive... Should we use a LUT instead?
// lerp(exp(-t2 * halfRcpVariance1), exp(-t2 * halfRcpVariance2), lerpWeight2)
return exp(-t2 * halfRcpVariance1) * lerpWeight1 + exp(-t2 * halfRcpVariance2) * lerpWeight2;
}
//-----------------------------------------------------------------------------
// conversion function for forward
//-----------------------------------------------------------------------------

{
bsdfData.diffuseColor = surfaceData.baseColor;
bsdfData.fresnel0 = 0.028; // TODO take from subsurfaceProfile
bsdfData.subsurfaceRadius = surfaceData.subsurfaceRadius;
bsdfData.thickness = surfaceData.thickness;
bsdfData.subsurfaceRadius = surfaceData.subsurfaceRadius * 0.01;
bsdfData.thickness = surfaceData.thickness * 0.01;
bsdfData.enableTransmittance = (1 << bsdfData.subsurfaceProfile) & _TransmittanceFlags;
if (bsdfData.enableTransmittance)
{
bsdfData.transmittance = ComputeTransmittance(_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].w,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].w,
bsdfData.thickness, bsdfData.subsurfaceRadius);
}
}
else if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{

{
bsdfData.diffuseColor = baseColor;
bsdfData.fresnel0 = 0.028; // TODO take from subsurfaceProfile
bsdfData.subsurfaceRadius = inGBuffer2.r;
bsdfData.thickness = inGBuffer2.g;
bsdfData.subsurfaceRadius = inGBuffer2.r * 0.01;
bsdfData.thickness = inGBuffer2.g * 0.01;
bsdfData.enableTransmittance = (1 << bsdfData.subsurfaceProfile) & _TransmittanceFlags;
if (bsdfData.enableTransmittance)
{
bsdfData.transmittance = ComputeTransmittance(_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][0].w,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].xyz,
_HalfRcpVariancesAndLerpWeights[bsdfData.subsurfaceProfile][1].w,
bsdfData.thickness, bsdfData.subsurfaceRadius);
}
}
else if (bsdfData.materialId == MATERIALID_LIT_CLEAR_COAT)
{

float3 L = -lightData.forward; // Lights are pointing backward in Unity
float illuminance = saturate(dot(bsdfData.normalWS, L));
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
float3 cookieColor = float3(1.0, 1.0, 1.0);
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
float4 cookie = float4(1.0, 1.0, 1.0, 1.0);
float shadowAttenuation = GetDirectionalShadowAttenuation(lightLoopContext, positionWS, lightData.shadowIndex, L, posInput.unPositionSS);
float shadow = GetDirectionalShadowAttenuation(lightLoopContext, positionWS, lightData.shadowIndex, L, posInput.unPositionSS, 0);
illuminance *= shadowAttenuation;
illuminance *= shadow;
}
[branch] if (lightData.cookieIndex >= 0 && illuminance > 0.0)

coord = coord * 0.5 + 0.5;
// Tile the texture if the 'repeat' wrap mode is enabled.
if (lightData.tileCookie)
if (lightData.tileCookie)
float4 cookie = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
cookie = SampleCookie2D(lightLoopContext, coord, lightData.cookieIndex);
cookieColor = cookie.rgb;
illuminance *= cookie.a;
}

diffuseLighting *= (cookieColor * lightData.color) * (illuminance * lightData.diffuseScale);
specularLighting *= (cookieColor * lightData.color) * (illuminance * lightData.specularScale);
diffuseLighting *= (cookie.rgb * lightData.color) * (illuminance * lightData.diffuseScale);
specularLighting *= (cookie.rgb * lightData.color) * (illuminance * lightData.specularScale);
}
[branch] if (bsdfData.enableTransmittance)
{
// Reverse the normal.
illuminance = saturate(dot(-bsdfData.normalWS, L));
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0)
{
float shadow = GetDirectionalShadowAttenuation(lightLoopContext, positionWS, lightData.shadowIndex, L, posInput.unPositionSS, bsdfData.thickness);
illuminance *= shadow;
}
illuminance *= cookie.a;
// The difference between the Disney Diffuse and the Lambertian BRDF for transmittance is negligible.
float3 backLight = (cookie.rgb * lightData.color) * (illuminance * lightData.diffuseScale * Lambert());
// TODO: multiplication by 'diffuseColor' and 'transmittance' is the same for each light.
float3 transmittedLight = backLight * bsdfData.diffuseColor * bsdfData.transmittance;
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
diffuseLighting += transmittedLight;
}
}

attenuation *= GetAngleAttenuation(L, -lightData.forward, lightData.angleScale, lightData.angleOffset);
float illuminance = saturate(dot(bsdfData.normalWS, L)) * attenuation;
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
float3 cookieColor = float3(1.0, 1.0, 1.0);
diffuseLighting = float3(0.0, 0.0, 0.0);
specularLighting = float3(0.0, 0.0, 0.0);
float4 cookie = float4(1.0, 1.0, 1.0, 1.0);
// TODO: measure impact of having all these dynamic branch here and the gain (or not) of testing illuminace > 0

[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0)
{
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float shadowAttenuation = GetPunctualShadowAttenuation(lightLoopContext, lightData.lightType, positionWS + offset, lightData.shadowIndex, L, posInput.unPositionSS);
shadowAttenuation = lerp(1.0, shadowAttenuation, lightData.shadowDimmer);
float shadow = GetPunctualShadowAttenuation(lightLoopContext, lightData.lightType, positionWS + offset, lightData.shadowIndex, L, posInput.unPositionSS, 0);
shadow = lerp(1.0, shadow, lightData.shadowDimmer);
illuminance *= shadowAttenuation;
illuminance *= shadow;
}
[branch] if (lightData.cookieIndex >= 0 && illuminance > 0.0)

// Rotate 'L' into the light space.
// We perform the negation because lights are oriented backwards (-Z).
float3 coord = mul(-L, transpose(lightToWorld));
float4 cookie;
[branch] if (lightData.lightType == GPULIGHTTYPE_SPOT)
{

cookie = SampleCookieCube(lightLoopContext, coord, lightData.cookieIndex);
}
cookieColor = cookie.rgb;
illuminance *= cookie.a;
}

diffuseLighting *= (cookieColor * lightData.color) * (illuminance * lightData.diffuseScale);
specularLighting *= (cookieColor * lightData.color) * (illuminance * lightData.specularScale);
diffuseLighting *= (cookie.rgb * lightData.color) * (illuminance * lightData.diffuseScale);
specularLighting *= (cookie.rgb * lightData.color) * (illuminance * lightData.specularScale);
}
[branch] if (bsdfData.enableTransmittance)
{
// Reverse the normal.
illuminance = saturate(dot(-bsdfData.normalWS, L)) * attenuation;
[branch] if (lightData.shadowIndex >= 0 && illuminance > 0.0)
{
float3 offset = float3(0.0, 0.0, 0.0); // GetShadowPosOffset(nDotL, normal);
float shadow = GetPunctualShadowAttenuation(lightLoopContext, lightData.lightType, positionWS + offset, lightData.shadowIndex, L, posInput.unPositionSS, bsdfData.thickness);
shadow = lerp(1.0, shadow, lightData.shadowDimmer);
illuminance *= shadow;
}
illuminance *= cookie.a;
// The difference between the Disney Diffuse and the Lambertian BRDF for transmittance is negligible.
float3 backLight = (cookie.rgb * lightData.color) * (illuminance * lightData.diffuseScale * Lambert());
// TODO: multiplication by 'diffuseColor' and 'transmittance' is the same for each light.
float3 transmittedLight = backLight * bsdfData.diffuseColor * bsdfData.transmittance;
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
diffuseLighting += transmittedLight;
}
}

正在加载...
取消
保存