2026-04-16 오브젝트 그림자
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
#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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user