|
|
|
|
|
|
#define BOX_LIGHT (2) |
|
|
|
#define DIRECTIONAL_LIGHT (3) |
|
|
|
|
|
|
|
#define SHADOW_FPTL |
|
|
|
# if defined(SHADER_API_D3D11) |
|
|
|
# include "../../ShaderLibrary/API/D3D11.hlsl" |
|
|
|
# elif defined(SHADER_API_PSSL) |
|
|
|
# include "../../ShaderLibrary/API/PSSL.hlsl" |
|
|
|
# elif defined(SHADER_API_XBOXONE) |
|
|
|
# include "../../ShaderLibrary/API/D3D11.hlsl" |
|
|
|
# include "../../ShaderLibrary/API/D3D11_1.hlsl" |
|
|
|
# elif defined(SHADER_API_METAL) |
|
|
|
# include "../../ShaderLibrary/API/Metal.hlsl" |
|
|
|
# else |
|
|
|
# error unsupported shader api |
|
|
|
# endif |
|
|
|
# include "../../ShaderLibrary/API/Validate.hlsl" |
|
|
|
# include "../../ShaderLibrary/Shadow/Shadow.hlsl" |
|
|
|
#undef SHADOW_FPTL |
|
|
|
|
|
|
|
//#include "../../ShaderLibrary/Shadow/Shadow.hlsl" |
|
|
|
//#include "../../fptl/ShadowContext.hlsl" |
|
|
|
//#include "../../fptl/ShadowDispatch.hlsl" |
|
|
|
|
|
|
|
CBUFFER_START(ShadowLightData) |
|
|
|
|
|
|
|
float4 g_vShadow3x3PCFTerms0; |
|
|
|
|
|
|
|
|
|
|
// StructuredBuffer<DirectionalLight> g_dirLightData; |
|
|
|
|
|
|
|
#define REVERSE_ZBUF |
|
|
|
#define DECLARE_SHADOWMAP( tex ) Texture2D tex; SamplerComparisonState sampler##tex |
|
|
|
#ifdef REVERSE_ZBUF |
|
|
|
#define SAMPLE_SHADOW( tex, coord ) tex.SampleCmpLevelZero( sampler##tex, (coord).xy, (coord).z ) |
|
|
|
#else |
|
|
|
#define SAMPLE_SHADOW( tex, coord ) tex.SampleCmpLevelZero( sampler##tex, (coord).xy, 1.0-(coord).z ) |
|
|
|
#endif |
|
|
|
|
|
|
|
DECLARE_SHADOWMAP(g_tShadowBuffer); |
|
|
|
|
|
|
|
float ComputeShadow_PCF_3x3_Gaussian(float3 vPositionWs, float4x4 matWorldToShadow) |
|
|
|
{ |
|
|
|
float4 vPositionTextureSpace = mul(float4(vPositionWs.xyz, 1.0), matWorldToShadow); |
|
|
|
vPositionTextureSpace.xyz /= vPositionTextureSpace.w; |
|
|
|
|
|
|
|
float2 shadowMapCenter = vPositionTextureSpace.xy; |
|
|
|
|
|
|
|
if ((shadowMapCenter.x < 0.0f) || (shadowMapCenter.x > 1.0f) || (shadowMapCenter.y < 0.0f) || (shadowMapCenter.y > 1.0f)) |
|
|
|
return 1.0f; |
|
|
|
|
|
|
|
float objDepth = saturate(257.0 / 256.0 - vPositionTextureSpace.z); |
|
|
|
|
|
|
|
float4 v20Taps; |
|
|
|
v20Taps.x = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.xy, objDepth)).x; // 1 1 |
|
|
|
v20Taps.y = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.zy, objDepth)).x; // -1 1 |
|
|
|
v20Taps.z = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.xw, objDepth)).x; // 1 -1 |
|
|
|
v20Taps.w = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms1.zw, objDepth)).x; // -1 -1 |
|
|
|
float flSum = dot(v20Taps.xyzw, float4(0.25, 0.25, 0.25, 0.25)); |
|
|
|
if ((flSum == 0.0) || (flSum == 1.0)) |
|
|
|
return flSum; |
|
|
|
flSum *= g_vShadow3x3PCFTerms0.x * 4.0; |
|
|
|
|
|
|
|
float4 v33Taps; |
|
|
|
v33Taps.x = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms2.xz, objDepth)).x; // 1 0 |
|
|
|
v33Taps.y = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms3.xz, objDepth)).x; // -1 0 |
|
|
|
v33Taps.z = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms3.zy, objDepth)).x; // 0 -1 |
|
|
|
v33Taps.w = SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy + g_vShadow3x3PCFTerms2.zy, objDepth)).x; // 0 1 |
|
|
|
flSum += dot(v33Taps.xyzw, g_vShadow3x3PCFTerms0.yyyy); |
|
|
|
|
|
|
|
flSum += SAMPLE_SHADOW(g_tShadowBuffer, float3(shadowMapCenter.xy, objDepth)).x * g_vShadow3x3PCFTerms0.z; |
|
|
|
|
|
|
|
return flSum; |
|
|
|
} |
|
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
|
/** |
|
|
|
* Gets the cascade weights based on the world position of the fragment and the positions of the split spheres for each cascade. |
|
|
|
* Returns an invalid split index if past shadowDistance (ie 4 is invalid for cascade) |
|
|
|
*/ |
|
|
|
float GetSplitSphereIndexForDirshadows(float3 wpos) |
|
|
|
{ |
|
|
|
float3 fromCenter0 = wpos.xyz - g_vDirShadowSplitSpheres[0].xyz; |
|
|
|
float3 fromCenter1 = wpos.xyz - g_vDirShadowSplitSpheres[1].xyz; |
|
|
|
float3 fromCenter2 = wpos.xyz - g_vDirShadowSplitSpheres[2].xyz; |
|
|
|
float3 fromCenter3 = wpos.xyz - g_vDirShadowSplitSpheres[3].xyz; |
|
|
|
float4 distances2 = float4(dot(fromCenter0, fromCenter0), dot(fromCenter1, fromCenter1), dot(fromCenter2, fromCenter2), dot(fromCenter3, fromCenter3)); |
|
|
|
|
|
|
|
float4 vDirShadowSplitSphereSqRadii; |
|
|
|
vDirShadowSplitSphereSqRadii.x = g_vDirShadowSplitSpheres[0].w; |
|
|
|
vDirShadowSplitSphereSqRadii.y = g_vDirShadowSplitSpheres[1].w; |
|
|
|
vDirShadowSplitSphereSqRadii.z = g_vDirShadowSplitSpheres[2].w; |
|
|
|
vDirShadowSplitSphereSqRadii.w = g_vDirShadowSplitSpheres[3].w; |
|
|
|
fixed4 weights = float4(distances2 < vDirShadowSplitSphereSqRadii); |
|
|
|
weights.yzw = saturate(weights.yzw - weights.xyz); |
|
|
|
return 4 - dot(weights, float4(4, 3, 2, 1)); |
|
|
|
} |
|
|
|
|
|
|
|
float SampleShadow(uint type, float3 vPositionWs, float3 vPositionToLightDirWs, uint lightIndex) |
|
|
|
{ |
|
|
|
float flShadowScalar = 1.0; |
|
|
|
int shadowSplitIndex = 0; |
|
|
|
|
|
|
|
if (type == DIRECTIONAL_LIGHT) |
|
|
|
{ |
|
|
|
shadowSplitIndex = GetSplitSphereIndexForDirshadows(vPositionWs); |
|
|
|
} |
|
|
|
|
|
|
|
else if (type == SPHERE_LIGHT) |
|
|
|
{ |
|
|
|
float3 absPos = abs(vPositionToLightDirWs); |
|
|
|
shadowSplitIndex = (vPositionToLightDirWs.z > 0) ? CUBEMAPFACE_NEGATIVE_Z : CUBEMAPFACE_POSITIVE_Z; |
|
|
|
if (absPos.x > absPos.y) |
|
|
|
{ |
|
|
|
if (absPos.x > absPos.z) |
|
|
|
{ |
|
|
|
shadowSplitIndex = (vPositionToLightDirWs.x > 0) ? CUBEMAPFACE_NEGATIVE_X : CUBEMAPFACE_POSITIVE_X; |
|
|
|
} |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
if (absPos.y > absPos.z) |
|
|
|
{ |
|
|
|
shadowSplitIndex = (vPositionToLightDirWs.y > 0) ? CUBEMAPFACE_NEGATIVE_Y : CUBEMAPFACE_POSITIVE_Y; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
flShadowScalar = ComputeShadow_PCF_3x3_Gaussian(vPositionWs.xyz, g_matWorldToShadow[lightIndex * MAX_SHADOWMAP_PER_LIGHT + shadowSplitIndex]); |
|
|
|
return flShadowScalar; |
|
|
|
} |
|
|
|
|
|
|
|
//debug |
|
|
|
//float3 GetViewPosFromLinDepth(float2 v2ScrPos, float fLinDepth) |
|
|
|
//{ |
|
|
|
|
|
|
float2 uv; |
|
|
|
float4 colorCookie = float4(1, 1, 1, 1); |
|
|
|
|
|
|
|
ShadowContext shadowContext = InitShadowContext(); |
|
|
|
|
|
|
|
OnChipDeferredFragSetup(i, uv, vpos, wpos, depth); |
|
|
|
|
|
|
|
// needed? old shadow code is commented out, we switched to new shadow code .. aka sampleShadow() |
|
|
|
|
|
|
atten *= tex2D (_LightTextureB0, att.rr).UNITY_ATTEN_CHANNEL; |
|
|
|
|
|
|
|
if (_LightIndexForShadowMatrixArray >= 0) |
|
|
|
atten *= SampleShadow(SPOT_LIGHT, wpos, 0, _LightIndexForShadowMatrixArray); |
|
|
|
atten *= GetPunctualShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, 0.0.xxx); |
|
|
|
|
|
|
|
// directional light case |
|
|
|
#elif defined (DIRECTIONAL) || defined (DIRECTIONAL_COOKIE) |
|
|
|
|
|
|
if (_LightIndexForShadowMatrixArray >= 0) |
|
|
|
atten *= SampleShadow(DIRECTIONAL_LIGHT, wpos, 0, _LightIndexForShadowMatrixArray); |
|
|
|
atten *= GetDirectionalShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, 0.0.xxx); |
|
|
|
|
|
|
|
#if defined (DIRECTIONAL_COOKIE) |
|
|
|
colorCookie = tex2Dlod (_LightTexture0, float4(mul(unity_WorldToLight, half4(wpos,1)).xy, 0, 0)); |
|
|
|
|
|
|
float atten = tex2D (_LightTextureB0, att.rr).UNITY_ATTEN_CHANNEL; |
|
|
|
|
|
|
|
if (_LightIndexForShadowMatrixArray >= 0) |
|
|
|
atten *= SampleShadow(SPHERE_LIGHT, wpos, lightDir, _LightIndexForShadowMatrixArray); |
|
|
|
atten *= GetPunctualShadowAttenuation(shadowContext, wpos, 0.0.xxx, _LightIndexForShadowMatrixArray, lightDir); |
|
|
|
|
|
|
|
#if defined (POINT_COOKIE) |
|
|
|
colorCookie = texCUBElod(_LightTexture0, float4(mul(unity_WorldToLight, float4(wpos,1)).xyz, 0)); |
|
|
|