浏览代码

Merge pull request #1556 from Unity-Technologies/ContactShadowWithLightTransmisison-add

Fix contact shadow with light transmission
/main
GitHub 7 年前
当前提交
bf9b149a
共有 7 个文件被更改,包括 104 次插入63 次删除
  1. 3
      com.unity.render-pipelines.high-definition/CHANGELOG.md
  2. 27
      com.unity.render-pipelines.high-definition/HDRP/Lighting/LightEvaluation.hlsl
  3. 3
      com.unity.render-pipelines.high-definition/HDRP/Lighting/LightLoop/LightLoop.hlsl
  4. 19
      com.unity.render-pipelines.high-definition/HDRP/Lighting/LightLoop/LightLoopDef.hlsl
  5. 16
      com.unity.render-pipelines.high-definition/HDRP/Lighting/Volumetrics/VolumetricLighting.compute
  6. 44
      com.unity.render-pipelines.high-definition/HDRP/Material/Lit/Lit.hlsl
  7. 55
      com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.hlsl

3
com.unity.render-pipelines.high-definition/CHANGELOG.md


### Changed
- Re-enable shadow mask mode in debug view
### Fixed
- Fix contact shadows applied on transmission
## [2.0.4-preview]
### Fixed

27
com.unity.render-pipelines.high-definition/HDRP/Lighting/LightEvaluation.hlsl


}
// None of the outputs are premultiplied.
// Note: When doing transmission we always have only one shadow sample to do: Either front or back. We use NdotL to know on which side we are
void EvaluateLight_Directional(LightLoopContext lightLoopContext, PositionInputs posInput,
DirectionalLightData lightData, BakeLightingData bakeLightingData,
float3 N, float3 L,

float shadow = 1.0;
float shadowMask = 1.0;
float4 shadowData = float4(1, 1, 1, 1);
color = lightData.color;
attenuation = 1.0; // Note: no volumetric attenuation along shadow rays for directional lights

shadow = shadowMask = (lightData.shadowMaskSelector.x >= 0.0) ? dot(bakeLightingData.bakeShadowMask, lightData.shadowMaskSelector) : 1.0;
#endif
UNITY_BRANCH if (lightData.shadowIndex >= 0)
// We test NdotL >= 0.0 to not sample the shadow map if it is not required.
UNITY_BRANCH if (lightData.shadowIndex >= 0 && (dot(N, L) >= 0.0))
{
#ifdef USE_DEFERRED_DIRECTIONAL_SHADOWS
shadow = LOAD_TEXTURE2D(_DeferredShadowTexture, posInput.positionSS).x;

float contactShadow = GetContactShadow(lightLoopContext, lightData.contactShadowIndex);
shadow = min(shadow, contactShadow);
#ifdef SHADOWS_SHADOWMASK
// TODO: Optimize this code! Currently it is a bit like brute force to get the last transistion and fade to shadow mask, but there is

shadow = lightData.nonLightmappedOnly ? min(shadowMask, shadow) : shadow;
// Note: There is no shadowDimmer when there is no shadow mask
#endif
// Transparent have no contact shadow information
#ifndef _SURFACE_TYPE_TRANSPARENT
shadow = min(shadow, GetContactShadow(lightLoopContext, lightData.contactShadowIndex));
#endif
}

// None of the outputs are premultiplied.
// distances = {d, d^2, 1/d, d_proj}, where d_proj = dot(lightToSample, lightData.forward).
// Note: When doing transmission we always have only one shadow sample to do: Either front or back. We use NdotL to know on which side we are
void EvaluateLight_Punctual(LightLoopContext lightLoopContext, PositionInputs posInput,
LightData lightData, BakeLightingData bakeLightingData,
float3 N, float3 L, float3 lightToSample, float4 distances,

float shadow = 1.0;
float shadowMask = 1.0;
float contactShadow = 1.0;
color = lightData.color;
attenuation = SmoothPunctualLightAttenuation(distances, lightData.invSqrAttenuationRadius,

shadow = shadowMask = (lightData.shadowMaskSelector.x >= 0.0) ? dot(bakeLightingData.bakeShadowMask, lightData.shadowMaskSelector) : 1.0;
#endif
UNITY_BRANCH if (lightData.shadowIndex >= 0)
// We test NdotL >= 0.0 to not sample the shadow map if it is not required.
UNITY_BRANCH if (lightData.shadowIndex >= 0 && (dot(N, L) >= 0.0))
// Note:the case of NdotL < 0 can appear with isThinModeTransmission, in this case we need to flip the shadow bias
contactShadow = GetContactShadow(lightLoopContext, lightData.contactShadowIndex);
shadow = min(shadow, contactShadow);
#ifdef SHADOWS_SHADOWMASK
// Note: Legacy Unity have two shadow mask mode. ShadowMask (ShadowMask contain static objects shadow and ShadowMap contain only dynamic objects shadow, final result is the minimun of both value)

#else
shadow = lerp(1.0, shadow, lightData.shadowDimmer);
#endif
// Transparent have no contact shadow information
#ifndef _SURFACE_TYPE_TRANSPARENT
shadow = min(shadow, GetContactShadow(lightLoopContext, lightData.contactShadowIndex));
#endif
}
// Environment map share function

3
com.unity.render-pipelines.high-definition/HDRP/Lighting/LightLoop/LightLoop.hlsl


LightLoopContext context;
context.sampleReflection = 0;
context.shadowContext = InitShadowContext();
//We always fetch the screen space shadow texture, it is a 1x1 white texture if deferred directional shadow and/or contact shadow are disabled
context.contactShadow = LOAD_TEXTURE2D(_DeferredShadowTexture, posInput.positionSS).y; // Contactshadow is store in Green Channel of _DeferredShadowTexture
context.contactShadow = InitContactShadow(posInput);
// This struct is define in the material. the Lightloop must not access it
// PostEvaluateBSDF call at the end will convert Lighting to diffuse and specular lighting

19
com.unity.render-pipelines.high-definition/HDRP/Lighting/LightLoop/LightLoopDef.hlsl


return _EnvLightDatas[j];
}
float GetContactShadow(LightLoopContext lightLoopContact, int contactShadowIndex)
// We always fetch the screen space shadow texture to reduce the number of shader variant, overhead is negligible,
// it is a 1x1 white texture if deferred directional shadow and/or contact shadow are disabled
// We perform a single featch a the beginning of the lightloop
float InitContactShadow(PositionInputs posInput)
{
// For now we only support one contact shadow
// Contactshadow is store in Green Channel of _DeferredShadowTexture
return LOAD_TEXTURE2D(_DeferredShadowTexture, posInput.positionSS).y;
}
float GetContactShadow(LightLoopContext lightLoopContext, int contactShadowIndex)
// Here we take the contact shadow value using the contactShadowIndex of the light
// If the contact shadows are diasbled, it's value is -1 so this function will only
// return 1
// On the other hand, if the feature is active it's value is 0 so we can return
// the value fetched at the begining of LightLoop()
return max(lightLoopContact.contactShadow, abs(contactShadowIndex));
return contactShadowIndex >= 0 ? lightLoopContext.contactShadow : 1.0;
}

16
com.unity.render-pipelines.high-definition/HDRP/Lighting/Volumetrics/VolumetricLighting.compute


float3 L = -light.forward; // Lights point backwards in Unity
float3 color; float attenuation;
light.contactShadowIndex = -1; // Disable shadow contact if any
// Note: We provide a normal of 0 here that work with the NdotL >= 0 test inside the EvaluateLight_Punctual call
EvaluateLight_Directional(context, posInput, light, unused, 0, L,
color, attenuation);

float3 L = -lightToSample * distRcp;
float3 color; float attenuation;
light.contactShadowIndex = -1; // Disable shadow contact if any
// Note: We provide a normal of 0 here that work with the NdotL >= 0 test inside the EvaluateLight_Punctual call
0, L, lightToSample, distances, color, attenuation);
0, L, lightToSample, distances,
color, attenuation);
// Important:
// Ideally, all scattering calculations should use the jittered versions

float4 distances = float4(1, 1, 1, distProj);
float3 color; float attenuation;
EvaluateLight_Punctual(context, posInput, light, unused,
0, L, lightToSample, distances, color, attenuation);
light.contactShadowIndex = -1; // Disable shadow contact if any
// Note: We provide a normal of 0 here that work with the NdotL >= 0 test inside the EvaluateLight_Punctual call
EvaluateLight_Punctual( context, posInput, light, unused,
0, L, lightToSample, distances,
color, attenuation);
// Important:
// Ideally, all scattering calculations should use the jittered versions

// TODO
LightLoopContext context;
context.sampleReflection = 0;
context.contactShadow = 1.0;
uint featureFlags = 0xFFFFFFFF;
PositionInputs posInput = GetPositionInput(voxelCoord, _VBufferResolution.zw, tileCoord);

44
com.unity.render-pipelines.high-definition/HDRP/Material/Lit/Lit.hlsl


#define MATERIAL_FEATURE_FLAGS_SSS_OUTPUT_SPLIT_LIGHTING ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 0)
#define MATERIAL_FEATURE_FLAGS_SSS_TEXTURING_MODE_OFFSET FastLog2((MATERIAL_FEATURE_MASK_FLAGS + 1) << 1) // 2 bits
#define MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 3)
// Flags used as a shortcut to know if we have thin mode transmission
#define MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 4)
uint FeatureFlagsToTileVariant(uint featureFlags)
{

// the current object. That's not a problem, since large thickness will result in low intensity.
bool useThinObjectMode = IsBitSet(asuint(_TransmissionFlags), diffusionProfile);
bsdfData.materialFeatures |= useThinObjectMode ? 0 : MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS;
bsdfData.materialFeatures |= useThinObjectMode ? MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS : MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS;
// Compute transmittance using baked thickness here. It may be overridden for direct lighting
// in the auto-thickness mode (but is always be used for indirect lighting).

float3 color;
float attenuation;
// When using thin transmission mode we don't fetch shadow map for back face, we reuse front face shadow
// However we flip the normal for the bias (and the NdotL test) and disable contact shadow
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS) && NdotL < 0)
{
// Disable shadow contact in case of transmission and backface shadow
N = -N;
lightData.contactShadowIndex = -1; // This is only modify for the scope of this function
}
EvaluateLight_Directional(lightLoopContext, posInput, lightData, bakeLightingData, N, L, color, attenuation);
float intensity = max(0, attenuation * NdotL); // Warning: attenuation can be greater than 1 due to the inverse square attenuation (when position is close to light)

}
// The mixed thickness mode is not supported by directional lights due to poor quality and high performance impact.
bool mixedThicknessMode = HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS);
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION) && !mixedThicknessMode)
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS))
{
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
lighting.diffuse += EvaluateTransmission(bsdfData, bsdfData.transmittance, NdotL, NdotV, LdotV, attenuation * lightData.diffuseScale);

float NdotL = dot(N, L);
float LdotV = dot(L, V);
bool mixedThicknessMode = HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS)
&& NdotL < 0 && lightData.shadowIndex >= 0;
// Save the original version for the transmission code below.
int originalShadowIndex = lightData.shadowIndex;
float3 color;
float attenuation;
if (mixedThicknessMode)
// When using thin transmission mode we don't fetch shadow map for back face, we reuse front face shadow
// However we flip the normal for the bias (and the NdotL test) and disable contact shadow
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS) && NdotL < 0)
// Make sure we do not sample the shadow map twice.
lightData.shadowIndex = -1;
// Disable shadow contact in case of transmission and backface shadow
N = -N;
lightData.contactShadowIndex = -1; // This is only modify for the scope of this function
float3 color;
float attenuation;
// Restore the original shadow index.
lightData.shadowIndex = originalShadowIndex;
float intensity = max(0, attenuation * NdotL); // Warning: attenuation can be greater than 1 due to the inverse square attenuation (when position is close to light)

if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_LIT_TRANSMISSION))
{
float3 transmittance = bsdfData.transmittance;
// Note that if NdotL is positive, we have one fetch on front face done by EvaluateLight_Punctual, otherwise we have only one fetch
// done by transmission code here (EvaluateLight_Punctual discard the fetch if NdotL < 0)
bool mixedThicknessMode = HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS)
&& NdotL < 0 && lightData.shadowIndex >= 0;
if (mixedThicknessMode)
{

55
com.unity.render-pipelines.high-definition/HDRP/Material/StackLit/StackLit.hlsl


#define MATERIAL_FEATURE_FLAGS_SSS_OUTPUT_SPLIT_LIGHTING ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 0)
#define MATERIAL_FEATURE_FLAGS_SSS_TEXTURING_MODE_OFFSET FastLog2((MATERIAL_FEATURE_MASK_FLAGS + 1) << 1) // 2 bits
#define MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 3)
// Flags used as a shortcut to know if we have thin mode transmission
#define MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS ((MATERIAL_FEATURE_MASK_FLAGS + 1) << 4)
//
// Vertically Layered BSDF : "vlayering"

// the current object. That's not a problem, since large thickness will result in low intensity.
bool useThinObjectMode = IsBitSet(asuint(_TransmissionFlags), diffusionProfile);
bsdfData.materialFeatures |= useThinObjectMode ? 0 : MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS;
bsdfData.materialFeatures |= useThinObjectMode ? MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS : MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS;
_TransmissionTintsAndFresnel0[diffusionProfile].rgb,
bsdfData.thickness);
_TransmissionTintsAndFresnel0[diffusionProfile].rgb,
bsdfData.thickness);
_HalfRcpVariancesAndWeights[diffusionProfile][0].a,
_HalfRcpVariancesAndWeights[diffusionProfile][1].rgb,
_HalfRcpVariancesAndWeights[diffusionProfile][1].a,
_TransmissionTintsAndFresnel0[diffusionProfile].rgb,
bsdfData.thickness);
_HalfRcpVariancesAndWeights[diffusionProfile][0].a,
_HalfRcpVariancesAndWeights[diffusionProfile][1].rgb,
_HalfRcpVariancesAndWeights[diffusionProfile][1].a,
_TransmissionTintsAndFresnel0[diffusionProfile].rgb,
bsdfData.thickness);
#endif
}

float3 color;
float attenuation;
// When using thin transmission mode we don't fetch shadow map for back face, we reuse front face shadow
// However we flip the normal for the bias (and the NdotL test) and disable contact shadow
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS) && NdotL < 0)
{
// Disable shadow contact in case of transmission and backface shadow
N = -N;
lightData.contactShadowIndex = -1; // This is only modify for the scope of this function
}
// For shadow attenuation (ie receiver bias), always use the geometric normal:
EvaluateLight_Directional(lightLoopContext, posInput, lightData, bakeLightingData, bsdfData.geomNormalWS, L, color, attenuation);

}
// The mixed thickness mode is not supported by directional lights due to poor quality and high performance impact.
bool mixedThicknessMode = HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS);
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION) && !mixedThicknessMode)
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS))
{
// We use diffuse lighting for accumulation since it is going to be blurred during the SSS pass.
lighting.diffuse += EvaluateTransmission(bsdfData, bsdfData.transmittance, NdotL, NdotV, LdotV, attenuation * lightData.diffuseScale);

float NdotL = dot(N, L);
float LdotV = dot(L, V);
bool mixedThicknessMode = HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS)
&& NdotL < 0 && lightData.shadowIndex >= 0;
float3 color;
float attenuation;
// Save the original version for the transmission code below.
int originalShadowIndex = lightData.shadowIndex;
if (mixedThicknessMode)
// When using thin transmission mode we don't fetch shadow map for back face, we reuse front face shadow
// However we flip the normal for the bias (and the NdotL test) and disable contact shadow
if (HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_THIN_THICKNESS) && NdotL < 0)
// Make sure we do not sample the shadow map twice.
lightData.shadowIndex = -1;
// Disable shadow contact in case of transmission and backface shadow
N = -N;
lightData.contactShadowIndex = -1; // This is only modify for the scope of this function
float3 color;
float attenuation;
// Restore the original shadow index.
lightData.shadowIndex = originalShadowIndex;
float intensity = max(0, attenuation); // Warning: attenuation can be greater than 1 due to the inverse square attenuation (when position is close to light)

if (HasFeatureFlag(bsdfData.materialFeatures, MATERIALFEATUREFLAGS_STACK_LIT_TRANSMISSION))
{
float3 transmittance = bsdfData.transmittance;
bool mixedThicknessMode = HasFeatureFlag(bsdfData.materialFeatures, MATERIAL_FEATURE_FLAGS_TRANSMISSION_MODE_MIXED_THICKNESS)
&& NdotL < 0 && lightData.shadowIndex >= 0;
if (mixedThicknessMode)
{

正在加载...
取消
保存