Files
Cielonos/Assets/PotaToon/Shaders/ChracterShadow/DeclareCharacterShadowTexture.hlsl
SoulliesOfficial 50ee502684 完善
2026-02-13 09:22:11 -05:00

247 lines
9.7 KiB
HLSL

#ifndef CHARACTER_SHADOW_DEPTH_INPUT_INCLUDED
#define CHARACTER_SHADOW_DEPTH_INPUT_INCLUDED
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
#include "./CharacterShadowTransforms.hlsl"
#if _USE_2D_FACE_SHADOW
#include "../Common/PotaToonGlobalInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
#endif
// We use custom samplers for 2021
#if UNITY_VERSION >= 60000023
#define sampler_PotaToonPointClamp sampler_PointClamp
#define sampler_PotaToonLinearClamp sampler_LinearClamp
#else
SAMPLER(sampler_PotaToonPointClamp);
SAMPLER(sampler_PotaToonLinearClamp);
#endif
#define MAX_CHAR_SHADOWMAPS 1
uint LocalLightIndexToShadowmapIndex(uint lightindex)
{
if (_UseBrightestLight > 0 && lightindex == _BrightestLightIndex)
return 0;
return MAX_CHAR_SHADOWMAPS;
}
#define ADDITIONAL_CHARSHADOW_CHECK(i, lightIndex) { \
i = LocalLightIndexToShadowmapIndex(lightIndex); \
if (i >= MAX_CHAR_SHADOWMAPS) \
return 0; }
float3 TransformWorldToCharShadowCoord(float3 worldPos)
{
float4 clipPos = CharShadowWorldToHClipWithoutBias(worldPos);
#if UNITY_REVERSED_Z
clipPos.z = min(clipPos.z, UNITY_NEAR_CLIP_VALUE);
#else
clipPos.z = max(clipPos.z, UNITY_NEAR_CLIP_VALUE);
#endif
float3 ndc = clipPos.xyz / clipPos.w;
float2 ssUV = ndc.xy * 0.5 + 0.5;
#if UNITY_UV_STARTS_AT_TOP
ssUV.y = 1.0 - ssUV.y;
#endif
return float3(ssUV, ndc.z);
}
void ScaleUVForCascadeCharShadow(inout float2 uv)
{
uv *= _CharShadowUVScale;
uv = (1.0 - _CharShadowUVScale) * 0.5 + uv;
}
half SampleCharShadowTexture(TEXTURE2D_PARAM(tex, samplerTex), float2 uv, half isFace = 0)
{
float2 value = SAMPLE_TEXTURE2D_LOD(tex, samplerTex, uv, 0).rg;
return lerp(value.r, value.g, isFace);
}
half SampleScreenSpaceCharacterShadowTexture(float2 ssUV, half isFace = 0)
{
half2 value = SAMPLE_TEXTURE2D_LOD(_ScreenSpaceCharShadowmapTexture, sampler_PotaToonPointClamp, ssUV, 0).rg;
return lerp(value.r, value.g, isFace);
}
half2 SpiralBlurScreenSpaceCharacterShadow(float2 uv, float distance, float distanceSteps, float radialSteps, float radialOffset, float kernelPower)
{
float2 newUV = uv;
int i = 0;
float stepSize = distance / (int)distanceSteps;
float curDistance = 0;
float2 curOffset = 0;
float subOffset = 0;
float accumdist = 0;
// half2 value = SAMPLE_TEXTURE2D_LOD(_ScreenSpaceCharShadowmapTexture, sampler_PotaToonPointClamp, uv, 0).rg;
// if (distanceSteps < 1)
// return value;
half2 value = 0;
while (i < (int)distanceSteps)
{
curDistance += stepSize;
for (int j = 0; j < (int)radialSteps; j++)
{
subOffset += 1;
curOffset.x = cos(TWO_PI * (subOffset / radialSteps));
curOffset.y = sin(TWO_PI * (subOffset / radialSteps));
newUV = uv + curOffset * curDistance.xx;
float distpow = PositivePow(curDistance, kernelPower);
value += SAMPLE_TEXTURE2D_LOD(_ScreenSpaceCharShadowmapTexture, sampler_PotaToonPointClamp, newUV, 0).rg * distpow;
accumdist += distpow;
}
subOffset += radialOffset;
i++;
}
value /= accumdist;
return value;
}
half SampleScreenSpaceCharacterShadowTextureFiltered(float2 ssUV, half isFace = 0)
{
half2 attenuation = SAMPLE_TEXTURE2D_LOD(_ScreenSpaceCharShadowmapTexture, sampler_PotaToonPointClamp, ssUV, 0).rg;
half4 gatherR = GATHER_RED_TEXTURE2D(_ScreenSpaceCharShadowmapTexture, sampler_PotaToonPointClamp, ssUV);
half4 gatherG = GATHER_GREEN_TEXTURE2D(_ScreenSpaceCharShadowmapTexture, sampler_PotaToonPointClamp, ssUV);
float avg = lerp(gatherR.x + gatherR.y + gatherR.z + gatherR.w, gatherG.x + gatherG.y + gatherG.z + gatherG.w, isFace) * 0.25;
if (avg < 0.001 || avg > 0.999)
return lerp(attenuation.r, attenuation.g, isFace);
attenuation = SpiralBlurScreenSpaceCharacterShadow(ssUV, max(_ScreenSize.z, _ScreenSize.w) * 2, 2, 2, 0.62, 0.1);
return lerp(attenuation.r, attenuation.g, isFace);
}
#if _USE_2D_FACE_SHADOW
half Sample2DFaceShadow(float2 ssUV, float3 worldPos, half isFace)
{
float sceneDepth = SampleSceneDepth(ssUV);
#if UNITY_REVERSED_Z
half depthMultiplier = 1.0 - sceneDepth;
#else
half depthMultiplier = sceneDepth;
#endif
half width = _2DFaceShadowWidth * (0.25 + saturate(dot(_FaceForward.xyz, GetWorldSpaceViewDir(worldPos))) * 0.75) * depthMultiplier;
float4 positionCS = TransformWorldToHClip(worldPos + _BrightestLightDirection.xyz * width * 0.04);
positionCS.xyz /= positionCS.w;
float2 sampleDepthUV = positionCS.xy * 0.5 + 0.5;
#if UNITY_UV_STARTS_AT_TOP
sampleDepthUV.y = 1.0 - sampleDepthUV.y;
#endif
if (any(sampleDepthUV) < 0 || any(sampleDepthUV) > 1)
return 0;
half charMask = SAMPLE_TEXTURE2D_X(_PotaToonCharMask, sampler_PotaToonLinearClamp, sampleDepthUV).g;
const half minMask = 0.75;
#if UNITY_REVERSED_Z
float sampleDepth = charMask > minMask ? SampleSceneDepth(sampleDepthUV) : 0;
if (sampleDepth - sceneDepth > 0.000001)
return smoothstep(minMask, 1, charMask);
#else
float sampleDepth = charMask > minMask ? SampleSceneDepth(sampleDepthUV) : 1.0;
if (sceneDepth - sampleDepth > 0.000001)
return smoothstep(minMask, 1, charMask);
#endif
return 0;
}
#endif
half SampleCharacterShadowmapFiltered(float2 uv, float z, SamplerState s)
{
// UV must be the scaled value with ScaleUVForCascadeCharShadow()
z += 0.00001;
float ow = _CharShadowmapSize.x * _CharShadowCascadeParams.y;
float attenuation = SampleCharShadowTexture(TEXTURE2D_ARGS(_CharShadowMap, s), uv)
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_CharShadowMap, s), uv + float2(ow, ow))
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_CharShadowMap, s), uv + float2(ow, -ow))
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_CharShadowMap, s), uv + float2(-ow, ow))
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_CharShadowMap, s), uv + float2(-ow, -ow));
attenuation *= 0.2f;
return attenuation - (z + _CharShadowBias.x);
}
half SampleTransparentShadowmapFiltered(float2 uv, float z, SamplerState s)
{
// UV must be the scaled value with ScaleUVForCascadeCharShadow()
z += 0.00001;
float ow = _CharTransparentShadowmapSize.x * _CharShadowCascadeParams.y;
float attenuation = SampleCharShadowTexture(TEXTURE2D_ARGS(_TransparentShadowMap, s), uv)
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_TransparentShadowMap, s), uv + float2(ow, ow))
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_TransparentShadowMap, s), uv + float2(ow, -ow))
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_TransparentShadowMap, s), uv + float2(-ow, ow))
+ SampleCharShadowTexture(TEXTURE2D_ARGS(_TransparentShadowMap, s), uv + float2(-ow, -ow));
attenuation *= 0.2f;
return attenuation - (z + _CharShadowBias.x);
}
half TransparentAttenuation(float2 uv, half opacity)
{
// UV must be the scaled value with ScaleUVForCascadeCharShadow()
// Saturate since texture could have value more than 1
return saturate(SampleCharShadowTexture(TEXTURE2D_ARGS(_TransparentAlphaSum, sampler_PotaToonLinearClamp), uv) - opacity); // Total alpha sum - current pixel's alpha
}
// For transparent shadow, we assume that 'isFace' is always false. (The face should not be transparent by design)
half GetTransparentShadow(float2 uv, float z, half opacity)
{
// Ignore if transparent shadow is disabled.
if (_CharTransparentShadowmapSize.x > 0.99)
return 0;
// UV must be the scaled value with ScaleUVForCascadeCharShadow()
half hidden = SampleTransparentShadowmapFiltered(uv, z, sampler_PotaToonLinearClamp) > 0 ? 1 : 0;
half atten = TransparentAttenuation(uv, opacity);
return hidden * atten;
}
half CharacterAndTransparentShadowmap(float2 ssUV, float3 worldPos, half opacity, half isFace)
{
// TODO: Scale uv first for cascade char shadow map
// ScaleUVForCascadeCharShadow(uv);
float3 coord = TransformWorldToCharShadowCoord(worldPos);
#if _USE_2D_FACE_SHADOW
return max(Sample2DFaceShadow(ssUV, worldPos, isFace), GetTransparentShadow(coord.xy, coord.z, opacity));
#else
#if _ALPHATEST_ON
// We assume that 'isFace' is always false. (The face should not be transparent by design)
half charShadowAtten = SampleCharacterShadowmapFiltered(coord.xy, coord.z, sampler_PotaToonLinearClamp);
return max(smoothstep(0, 0.0002, charShadowAtten), GetTransparentShadow(coord.xy, coord.z, opacity));
#else
return max(SampleScreenSpaceCharacterShadowTextureFiltered(ssUV, isFace), GetTransparentShadow(coord.xy, coord.z, opacity));
#endif
#endif
}
half SampleCharacterAndTransparentShadow(float2 ssUV, float3 worldPos, half opacity, half isFace)
{
if (_IsBrightestLightMain == 0)
return 0;
half fallback = isFace ? 0 : SAMPLE_TEXTURE2D_LOD(_CharContactShadowTexture, sampler_PotaToonPointClamp, ssUV, 0).r;
return lerp(CharacterAndTransparentShadowmap(ssUV, worldPos, opacity, isFace), fallback, GetCharShadowFade(TransformWorldToView(worldPos).z));
}
half SampleAdditionalCharacterAndTransparentShadow(float2 ssUV, float3 worldPos, half opacity, half isFace, uint lightIndex = 0)
{
#ifndef USE_FORWARD_PLUS
return 0;
#endif
uint i;
ADDITIONAL_CHARSHADOW_CHECK(i, lightIndex)
if (_IsBrightestLightMain == 1)
return 0;
half fallback = isFace ? 0 : SAMPLE_TEXTURE2D_LOD(_CharContactShadowTexture, sampler_PotaToonPointClamp, ssUV, 0).r;
return lerp(CharacterAndTransparentShadowmap(ssUV, worldPos, opacity, isFace), fallback, GetCharShadowFade(TransformWorldToView(worldPos).z));
}
#endif