Files
Shopping_UnityVR/Packages/com.baddog.rendering.arealight/Shaders/Include/BGAreaLightShadows.hlsl
2026-04-16 04:58:10 +09:00

151 lines
6.9 KiB
HLSL

#ifndef BADDOG_AREA_LIGHT_SHADOWS_INCLUDED
#define BADDOG_AREA_LIGHT_SHADOWS_INCLUDED
// URP shadow sampling utilities
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
#include "Packages/com.baddog.rendering.arealight/Shaders/Include/HDPCSS.hlsl"
//-----------------------------------------------------------------------------
// Area Light Shadow Data
//-----------------------------------------------------------------------------
// Maximum number of area lights that can cast shadows
#define MAX_AREA_LIGHT_SHADOW_COUNT 8
// Area Light Shadow Atlas
TEXTURE2D_SHADOW(_AreaLightsShadowmapTexture);
// Area Light Shadow Atlas Size
// x: 1.0 / width (texel size)
// y: 1.0 / height (texel size)
// z: width (resolution)
// w: height (resolution)
float4 _AreaLightShadowmapSize;
// Area Light Shadow Parameters (per area light, indexed by areaLightIndex)
// x: shadow strength [0,1]
// y: soft shadow (1.0 for soft, 0.0 for hard) - reserved for future use
// z: light type identifier (for shader variants) - reserved for future use
// w: areaLightIndex (same as array index, or -1 if no shadow)
float4 _AreaLightShadowParams[MAX_AREA_LIGHT_SHADOW_COUNT];
// Area Light World-to-Shadow Matrices (per area light, indexed by areaLightIndex)
float4x4 _AreaLightsWorldToShadow[MAX_AREA_LIGHT_SHADOW_COUNT];
// PCSS Parameters for Area Light Shadows
// x: shadowSoftness (world space units)
// y: blockerSampleCount
// z: filterSampleCount
// w: rangeScale (for directional lights, 1.0 for area lights)
float4 _PCSSAdditionalLightParams;
//-----------------------------------------------------------------------------
// PCSS Support Function (if not provided by URP Shadows.hlsl)
//-----------------------------------------------------------------------------
real SampleShadowmapFilteredPCSS(TEXTURE2D_SHADOW_PARAM(ShadowMap, sampler_ShadowMap), float4 shadowCoord, ShadowSamplingData samplingData, float4 pcssParams, float3 positionWS, bool isPerspectiveProjection)
{
// Generate jitter for PCSS using screen pixel coordinates
float4 clipPos = TransformWorldToHClip(positionWS);
float2 screenPos = ComputeScreenPos(clipPos).xy * _ScreenParams.xy;
float sampleJitterAngle = InterleavedGradientNoise(screenPos, 0) * 2.0 * PI;
float2 sampleJitter = float2(sin(sampleJitterAngle), cos(sampleJitterAngle));
// Extract PCSS parameters
float shadowSoftness = pcssParams.x;
int blockerSampleCount = (int)pcssParams.y;
int filterSampleCount = (int)pcssParams.z;
float lightRangeScale = pcssParams.w;
float minFilterRadius = 2.0;
// shadowmapSize format: (texelWidth, texelHeight, width, height)
// We need to convert shadowSoftness (world units) to UV space
// shadowSoftness is in world units, we convert to texels then to UV
float lightArea = shadowSoftness * samplingData.shadowmapSize.x; // Convert to UV space using texel size
float maxLightArea = 0.04; // 4% of UV space
lightArea = min(lightArea, maxLightArea);
// Shadow map bounds (full texture for non-atlas)
float UMin = 0.0, UMax = 1.0, VMin = 0.0, VMax = 1.0;
// Perform PCSS blocker search
real averageBlockerDepth;
real numBlockers;
bool blockerFound = BlockerSearch(averageBlockerDepth, numBlockers, lightArea, shadowCoord.xyz, UMin, UMax, VMin, VMax, sampleJitter, ShadowMap, sampler_PointClamp, blockerSampleCount);
// Calculate filter size based on penumbra estimation
float filterSize = shadowSoftness * (isPerspectiveProjection ? PenumbraSizePunctual(shadowCoord.z, averageBlockerDepth) : PenumbraSizeDirectional(shadowCoord.z, averageBlockerDepth, lightRangeScale));
filterSize = blockerFound ? max(filterSize, minFilterRadius) : minFilterRadius;
// Convert filter size to UV space (filterSize is in world units, multiply by texel size)
filterSize *= samplingData.shadowmapSize.x;
// Perform PCSS filtering
return PCSS(shadowCoord.xyz, UMin, UMax, VMin, VMax, filterSize, sampleJitter, ShadowMap, sampler_ShadowMap, filterSampleCount);
}
//-----------------------------------------------------------------------------
// Area Light Shadow Sampling
//-----------------------------------------------------------------------------
// Sample area light shadow for a given area light index
// areaLightIndex: Index of the area light (matches _AreaLightDataBuffer index)
// positionWS: World space position to sample shadow at
// Returns: Shadow attenuation [0,1], where 1 = fully lit, 0 = fully shadowed
half SampleAreaLightShadow(uint areaLightIndex, float3 positionWS)
{
float4 shadowParams = _AreaLightShadowParams[areaLightIndex];
// Check if this light has shadow (w >= 0)
// w contains the areaLightIndex if shadow is enabled, or -1 if disabled
if (shadowParams.w < 0.0)
return 1.0;
// Transform position to shadow space
float4 shadowCoord = mul(_AreaLightsWorldToShadow[areaLightIndex], float4(positionWS, 1.0));
// Build sampling data compatible with URP shadow sampling
ShadowSamplingData samplingData;
samplingData.shadowOffset0 = 0;
samplingData.shadowOffset1 = 0;
samplingData.shadowmapSize = _AreaLightShadowmapSize;
samplingData.softShadowQuality = half(shadowParams.y);
// Perspective divide and out-of-bounds handling
shadowCoord.xyz /= max(shadowCoord.w, 1e-5);
if (BEYOND_SHADOW_FAR(shadowCoord))
return 1.0;
real attenuation;
// Directly call URP shadow filter entry points by BG keywords (no macro remap).
#if defined(_BG_AREALIGHT_SHADOWS_PCF2X2)
attenuation = SampleShadowmapFilteredLowQuality(TEXTURE2D_SHADOW_ARGS(_AreaLightsShadowmapTexture, sampler_LinearClampCompare), shadowCoord, samplingData);
#elif defined(_BG_AREALIGHT_SHADOWS_TENT5X5)
attenuation = SampleShadowmapFilteredMediumQuality(TEXTURE2D_SHADOW_ARGS(_AreaLightsShadowmapTexture, sampler_LinearClampCompare), shadowCoord, samplingData);
#elif defined(_BG_AREALIGHT_SHADOWS_TENT7X7)
attenuation = SampleShadowmapFilteredHighQuality(TEXTURE2D_SHADOW_ARGS(_AreaLightsShadowmapTexture, sampler_LinearClampCompare), shadowCoord, samplingData);
#elif defined(_BG_AREALIGHT_SHADOWS_PCSS)
// PCSS for area lights: reuse the PCSS path implemented in Shadows.hlsl,
// controlled by _PCSSAdditionalLightParams (x: softness, y: blockerSamples, z: filterSamples, w: rangeScale)
attenuation = SampleShadowmapFilteredPCSS(
TEXTURE2D_SHADOW_ARGS(_AreaLightsShadowmapTexture, sampler_LinearClampCompare),
float4(shadowCoord.xyz, 1.0),
samplingData,
_PCSSAdditionalLightParams,
positionWS,
/*isPerspectiveProjection*/ true);
#else
attenuation = real(SAMPLE_TEXTURE2D_SHADOW(_AreaLightsShadowmapTexture, sampler_LinearClampCompare, shadowCoord.xyz));
#endif
// Apply shadow strength
attenuation = LerpWhiteTo(attenuation, shadowParams.x);
return half(attenuation);
}
#endif // BADDOG_AREA_LIGHT_SHADOWS_INCLUDED