You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
232 lines
9.3 KiB
232 lines
9.3 KiB
#ifndef UNITY_HD_RAYTRACING_SHADOW_LOOP_HLSL
|
|
#define UNITY_HD_RAYTRACING_SHADOW_LOOP_HLSL
|
|
|
|
#define USE_LIGHT_CLUSTER
|
|
|
|
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RayTracingLightCluster.hlsl"
|
|
|
|
//#define SHADOW_LOOP_MULTIPLY
|
|
//#define SHADOW_LOOP_AVERAGE
|
|
|
|
#if defined(SHADOW_LOOP_MULTIPLY) || defined(SHADOW_LOOP_AVERAGE)
|
|
#define SHADOW_LOOP_WEIGHT
|
|
#endif
|
|
|
|
void ShadowLoopMin(HDShadowContext shadowContext, PositionInputs posInput, float3 normalWS, uint featureFlags, uint renderLayer, out float3 shadow)
|
|
{
|
|
#ifdef SHADOW_LOOP_WEIGHT
|
|
float shadowCount = 0.0f;
|
|
#endif
|
|
|
|
#ifdef SHADOW_LOOP_MULTIPLY
|
|
shadow = float3(1, 1, 1);
|
|
#elif defined(SHADOW_LOOP_AVERAGE)
|
|
shadow = float3(0, 0, 0);
|
|
#else
|
|
shadow = float3(1, 1, 1);
|
|
#endif
|
|
|
|
// With XR single-pass and camera-relative: offset position to do lighting computations from the combined center view (original camera matrix).
|
|
// This is required because there is only one list of lights generated on the CPU. Shadows are also generated once and shared between the instanced views.
|
|
ApplyCameraRelativeXR(posInput.positionWS);
|
|
|
|
// Initialize the contactShadow and contactShadowFade fields
|
|
|
|
// First of all we compute the shadow value of the directional light to reduce the VGPR pressure
|
|
if (featureFlags & LIGHTFEATUREFLAGS_DIRECTIONAL)
|
|
{
|
|
// Evaluate sun shadows.
|
|
if (_DirectionalShadowIndex >= 0)
|
|
{
|
|
DirectionalLightData light = _DirectionalLightDatas[_DirectionalShadowIndex];
|
|
|
|
// TODO: this will cause us to load from the normal buffer first. Does this cause a performance problem?
|
|
float3 wi = -light.forward;
|
|
|
|
// Is it worth sampling the shadow map?
|
|
if (light.lightDimmer > 0 && light.shadowDimmer > 0)
|
|
{
|
|
// If we are in the ray tracing case, we want to be able to have the directional shadow fallback.
|
|
int shadowSplitIndex;
|
|
SHADOW_TYPE shadowD = EvalShadow_CascadedDepth_Dither_SplitIndex(shadowContext, _ShadowmapCascadeAtlas, s_linear_clamp_compare_sampler, posInput.positionSS, posInput.positionWS, normalWS, light.shadowIndex, wi, shadowSplitIndex);
|
|
if (shadowSplitIndex < 0.0)
|
|
shadowD = _DirectionalShadowFallbackIntensity;
|
|
|
|
#ifdef SHADOW_LOOP_MULTIPLY
|
|
shadow *= lerp(light.shadowTint, float3(1, 1, 1), shadowD);
|
|
#elif defined(SHADOW_LOOP_AVERAGE)
|
|
shadow += lerp(light.shadowTint, float3(1, 1, 1), shadowD);
|
|
#else
|
|
shadow = min(shadow, shadowD.SHADOW_TYPE_SWIZZLE);
|
|
#endif
|
|
#ifdef SHADOW_LOOP_WEIGHT
|
|
shadowCount += 1.0f;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
// Indices of the subranges to process
|
|
uint lightStart = 0, lightEnd = 0;
|
|
uint cellIndex;
|
|
|
|
// Index used to loop over the lights
|
|
uint i = 0;
|
|
|
|
// The light cluster is in actual world space coordinates,
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
// Get the actual world space position
|
|
float3 actualWSPos = posInput.positionWS;
|
|
#endif
|
|
|
|
if (featureFlags & LIGHTFEATUREFLAGS_PUNCTUAL)
|
|
{
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
// Get the punctual light count
|
|
GetLightCountAndStartCluster(actualWSPos, LIGHTCATEGORY_PUNCTUAL, lightStart, lightEnd, cellIndex);
|
|
#else
|
|
lightStart = 0;
|
|
lightEnd = _WorldPunctualLightCount;
|
|
#endif
|
|
|
|
for (i = lightStart; i < lightEnd; i++)
|
|
{
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
LightData lightData = FetchClusterLightIndex(cellIndex, i);
|
|
#else
|
|
LightData lightData = _WorldLightDatas[i];
|
|
#endif
|
|
if (IsMatchingLightLayer(lightData.lightLayers, renderLayer) &&
|
|
lightData.shadowIndex >= 0 &&
|
|
lightData.shadowDimmer > 0)
|
|
{
|
|
float shadowP;
|
|
float3 L;
|
|
float4 distances; // {d, d^2, 1/d, d_proj}
|
|
GetPunctualLightVectors(posInput.positionWS, lightData, L, distances);
|
|
|
|
// Projector lights (box, pyramid) always have cookies, so we can perform clipping inside the if().
|
|
float lightinBounds = 1.0;
|
|
if (lightData.lightType == GPULIGHTTYPE_PROJECTOR_PYRAMID || lightData.lightType == GPULIGHTTYPE_PROJECTOR_BOX)
|
|
{
|
|
float3 lightToSample = posInput.positionWS - lightData.positionRWS;
|
|
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
|
|
float3 positionLS = mul(lightToSample, transpose(lightToWorld));
|
|
|
|
// Perform orthographic or perspective projection.
|
|
float perspectiveZ = (lightData.lightType != GPULIGHTTYPE_PROJECTOR_BOX) ? positionLS.z : 1.0;
|
|
float2 positionCS = positionLS.xy / perspectiveZ;
|
|
|
|
float z = positionLS.z;
|
|
float r = lightData.range;
|
|
|
|
// Box lights have no range attenuation, so we must clip manually.
|
|
lightinBounds = Max3(abs(positionCS.x), abs(positionCS.y), abs(z - 0.5 * r) - 0.5 * r + 1) <= lightData.boxLightSafeExtent ? 1 : 0;
|
|
}
|
|
|
|
if (distances.x < lightData.range
|
|
&& PunctualLightAttenuation(distances, lightData.rangeAttenuationScale, lightData.rangeAttenuationBias, lightData.angleScale, lightData.angleOffset) > 0.0
|
|
&& lightinBounds > 0.0
|
|
&& L.y > 0.0)
|
|
{
|
|
shadowP = GetPunctualShadowAttenuation(shadowContext, posInput.positionSS, posInput.positionWS, normalWS, lightData.shadowIndex, L, distances.x, lightData.lightType == GPULIGHTTYPE_POINT, lightData.lightType != GPULIGHTTYPE_PROJECTOR_BOX);
|
|
shadowP = lightData.nonLightMappedOnly ? min(1.0f, shadowP) : shadowP;
|
|
shadowP = lerp(1.0f, shadowP, lightData.shadowDimmer);
|
|
|
|
#ifdef SHADOW_LOOP_MULTIPLY
|
|
shadow *= lerp(lightData.shadowTint, float3(1, 1, 1), shadowP);
|
|
#elif defined(SHADOW_LOOP_AVERAGE)
|
|
shadow += lerp(lightData.shadowTint, float3(1, 1, 1), shadowP);
|
|
#else
|
|
shadow = min(shadow, shadowP.xxx);
|
|
#endif
|
|
#ifdef SHADOW_LOOP_WEIGHT
|
|
shadowCount += 1.0f;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (featureFlags & LIGHTFEATUREFLAGS_AREA)
|
|
{
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
// Let's loop through all the
|
|
GetLightCountAndStartCluster(actualWSPos, LIGHTCATEGORY_AREA, lightStart, lightEnd, cellIndex);
|
|
#else
|
|
lightStart = _WorldPunctualLightCount;
|
|
lightEnd = _WorldPunctualLightCount + _WorldAreaLightCount;
|
|
#endif
|
|
|
|
for (i = lightStart; i < lightEnd; i++)
|
|
{
|
|
#ifdef USE_LIGHT_CLUSTER
|
|
LightData lightData = FetchClusterLightIndex(cellIndex, i);
|
|
#else
|
|
LightData lightData = _WorldLightDatas[i];
|
|
#endif
|
|
if (IsMatchingLightLayer(lightData.lightLayers, renderLayer))
|
|
{
|
|
float3 L;
|
|
float4 distances; // {d, d^2, 1/d, d_proj}
|
|
GetPunctualLightVectors(posInput.positionWS, lightData, L, distances);
|
|
float lightRadSqr = lightData.size.x;
|
|
float shadowP;
|
|
|
|
float coef = 0.0f;
|
|
float3 unL = lightData.positionRWS - posInput.positionWS;
|
|
if (dot(lightData.forward, unL) < FLT_EPS)
|
|
{
|
|
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, -lightData.forward);
|
|
unL = mul(unL, transpose(lightToWorld));
|
|
|
|
float halfWidth = lightData.size.x*0.5;
|
|
float halfHeight = lightData.size.y*0.5;
|
|
|
|
float range = lightData.range;
|
|
float3 invHalfDim = rcp(float3(range + halfWidth,
|
|
range + halfHeight,
|
|
range));
|
|
|
|
coef = EllipsoidalDistanceAttenuation(unL, invHalfDim,
|
|
lightData.rangeAttenuationScale,
|
|
lightData.rangeAttenuationBias);
|
|
}
|
|
|
|
if (distances.x < lightData.range && coef > 0.0)
|
|
{
|
|
float shadowA = GetRectAreaShadowAttenuation(shadowContext, posInput.positionSS, posInput.positionWS, normalWS, lightData.shadowIndex, normalize(lightData.positionRWS), length(lightData.positionRWS));
|
|
|
|
#ifdef SHADOW_LOOP_MULTIPLY
|
|
shadow *= lerp(lightData.shadowTint, float3(1, 1, 1), shadowA);
|
|
#elif defined(SHADOW_LOOP_AVERAGE)
|
|
shadow += lerp(lightData.shadowTint, float3(1, 1, 1), shadowA);
|
|
#else
|
|
shadow = min(shadow, shadowA.xxx);
|
|
#endif
|
|
#ifdef SHADOW_LOOP_WEIGHT
|
|
shadowCount += 1.0f;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef SHADOW_LOOP_MULTIPLY
|
|
if (shadowCount == 0.0f)
|
|
{
|
|
shadow = float3(1, 1, 1);
|
|
}
|
|
#elif defined(SHADOW_LOOP_AVERAGE)
|
|
if (shadowCount > 0.0f)
|
|
{
|
|
shadow /= shadowCount;
|
|
}
|
|
else
|
|
{
|
|
shadow = float3(1, 1, 1);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif // UNITY_HD_RAYTRACING_SHADOW_LOOP_HLSL
|