791 lines
42 KiB
HLSL
791 lines
42 KiB
HLSL
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
|
|
|
|
#ifndef UNITY_BUILTIN_SHADOW_LIBRARY_INCLUDED
|
|
#define UNITY_BUILTIN_SHADOW_LIBRARY_INCLUDED
|
|
|
|
// Shadowmap helpers.
|
|
#if defined( SHADOWS_SCREEN ) && defined( LIGHTMAP_ON )
|
|
#define HANDLE_SHADOWS_BLENDING_IN_GI 1
|
|
#endif
|
|
|
|
#define unityShadowCoord float
|
|
#define unityShadowCoord2 float2
|
|
#define unityShadowCoord3 float3
|
|
#define unityShadowCoord4 float4
|
|
#define unityShadowCoord4x4 float4x4
|
|
|
|
half UnitySampleShadowmap_PCF7x7(float4 coord, float3 receiverPlaneDepthBias); // Samples the shadowmap based on PCF filtering (7x7 kernel)
|
|
half UnitySampleShadowmap_PCF5x5(float4 coord, float3 receiverPlaneDepthBias); // Samples the shadowmap based on PCF filtering (5x5 kernel)
|
|
half UnitySampleShadowmap_PCF3x3(float4 coord, float3 receiverPlaneDepthBias); // Samples the shadowmap based on PCF filtering (3x3 kernel)
|
|
float3 UnityGetReceiverPlaneDepthBias(float3 shadowCoord, float biasbiasMultiply); // Receiver plane depth bias
|
|
|
|
// ------------------------------------------------------------------
|
|
// Spot light shadows
|
|
// ------------------------------------------------------------------
|
|
|
|
#if defined (SHADOWS_DEPTH) && defined (SPOT)
|
|
|
|
// declare shadowmap
|
|
#if !defined(SHADOWMAPSAMPLER_DEFINED)
|
|
UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
|
|
#define SHADOWMAPSAMPLER_DEFINED
|
|
#endif
|
|
|
|
// shadow sampling offsets and texel size
|
|
#if defined (SHADOWS_SOFT)
|
|
float4 _ShadowOffsets[4];
|
|
float4 _ShadowMapTexture_TexelSize;
|
|
#define SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
#endif
|
|
|
|
inline fixed UnitySampleShadowmap (float4 shadowCoord)
|
|
{
|
|
#if defined (SHADOWS_SOFT)
|
|
|
|
half shadow = 1;
|
|
|
|
// No hardware comparison sampler (ie some mobile + xbox360) : simple 4 tap PCF
|
|
#if !defined (SHADOWS_NATIVE)
|
|
float3 coord = shadowCoord.xyz / shadowCoord.w;
|
|
float4 shadowVals;
|
|
shadowVals.x = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[0].xy);
|
|
shadowVals.y = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[1].xy);
|
|
shadowVals.z = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[2].xy);
|
|
shadowVals.w = SAMPLE_DEPTH_TEXTURE(_ShadowMapTexture, coord + _ShadowOffsets[3].xy);
|
|
half4 shadows = (shadowVals < coord.zzzz) ? _LightShadowData.rrrr : 1.0f;
|
|
shadow = dot(shadows, 0.25f);
|
|
#else
|
|
// Mobile with comparison sampler : 4-tap linear comparison filter
|
|
#if defined(SHADER_API_MOBILE)
|
|
float3 coord = shadowCoord.xyz / shadowCoord.w;
|
|
half4 shadows;
|
|
shadows.x = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[0]);
|
|
shadows.y = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[1]);
|
|
shadows.z = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[2]);
|
|
shadows.w = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, coord + _ShadowOffsets[3]);
|
|
shadow = dot(shadows, 0.25f);
|
|
// Everything else
|
|
#else
|
|
float3 coord = shadowCoord.xyz / shadowCoord.w;
|
|
float3 receiverPlaneDepthBias = UnityGetReceiverPlaneDepthBias(coord, 1.0f);
|
|
shadow = UnitySampleShadowmap_PCF3x3(float4(coord, 1), receiverPlaneDepthBias);
|
|
#endif
|
|
shadow = lerp(_LightShadowData.r, 1.0f, shadow);
|
|
#endif
|
|
#else
|
|
// 1-tap shadows
|
|
#if defined (SHADOWS_NATIVE)
|
|
half shadow = UNITY_SAMPLE_SHADOW_PROJ(_ShadowMapTexture, shadowCoord);
|
|
shadow = lerp(_LightShadowData.r, 1.0f, shadow);
|
|
#else
|
|
half shadow = SAMPLE_DEPTH_TEXTURE_PROJ(_ShadowMapTexture, UNITY_PROJ_COORD(shadowCoord)) < (shadowCoord.z / shadowCoord.w) ? _LightShadowData.r : 1.0;
|
|
#endif
|
|
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
#endif // #if defined (SHADOWS_DEPTH) && defined (SPOT)
|
|
|
|
// ------------------------------------------------------------------
|
|
// Point light shadows
|
|
// ------------------------------------------------------------------
|
|
|
|
#if defined (SHADOWS_CUBE)
|
|
|
|
#if defined(SHADOWS_CUBE_IN_DEPTH_TEX)
|
|
UNITY_DECLARE_TEXCUBE_SHADOWMAP(_ShadowMapTexture);
|
|
#else
|
|
UNITY_DECLARE_TEXCUBE(_ShadowMapTexture);
|
|
inline float SampleCubeDistance (float3 vec)
|
|
{
|
|
return UnityDecodeCubeShadowDepth(UNITY_SAMPLE_TEXCUBE_LOD(_ShadowMapTexture, vec, 0));
|
|
}
|
|
|
|
#endif
|
|
|
|
inline half UnitySampleShadowmap (float3 vec)
|
|
{
|
|
#if defined(SHADOWS_CUBE_IN_DEPTH_TEX)
|
|
float3 absVec = abs(vec);
|
|
float dominantAxis = max(max(absVec.x, absVec.y), absVec.z); // TODO use max3() instead
|
|
dominantAxis = max(0.00001, dominantAxis - _LightProjectionParams.z); // shadow bias from point light is apllied here.
|
|
dominantAxis *= _LightProjectionParams.w; // bias
|
|
float mydist = -_LightProjectionParams.x + _LightProjectionParams.y/dominantAxis; // project to shadow map clip space [0; 1]
|
|
|
|
#if defined(UNITY_REVERSED_Z)
|
|
mydist = 1.0 - mydist; // depth buffers are reversed! Additionally we can move this to CPP code!
|
|
#endif
|
|
#else
|
|
float mydist = length(vec) * _LightPositionRange.w;
|
|
mydist *= _LightProjectionParams.w; // bias
|
|
#endif
|
|
|
|
#if defined (SHADOWS_SOFT)
|
|
float z = 1.0/128.0;
|
|
float4 shadowVals;
|
|
// No hardware comparison sampler (ie some mobile + xbox360) : simple 4 tap PCF
|
|
#if defined (SHADOWS_CUBE_IN_DEPTH_TEX)
|
|
shadowVals.x = UNITY_SAMPLE_TEXCUBE_SHADOW(_ShadowMapTexture, float4(vec+float3( z, z, z), mydist));
|
|
shadowVals.y = UNITY_SAMPLE_TEXCUBE_SHADOW(_ShadowMapTexture, float4(vec+float3(-z,-z, z), mydist));
|
|
shadowVals.z = UNITY_SAMPLE_TEXCUBE_SHADOW(_ShadowMapTexture, float4(vec+float3(-z, z,-z), mydist));
|
|
shadowVals.w = UNITY_SAMPLE_TEXCUBE_SHADOW(_ShadowMapTexture, float4(vec+float3( z,-z,-z), mydist));
|
|
half shadow = dot(shadowVals, 0.25);
|
|
return lerp(_LightShadowData.r, 1.0, shadow);
|
|
#else
|
|
shadowVals.x = SampleCubeDistance (vec+float3( z, z, z));
|
|
shadowVals.y = SampleCubeDistance (vec+float3(-z,-z, z));
|
|
shadowVals.z = SampleCubeDistance (vec+float3(-z, z,-z));
|
|
shadowVals.w = SampleCubeDistance (vec+float3( z,-z,-z));
|
|
half4 shadows = (shadowVals < mydist.xxxx) ? _LightShadowData.rrrr : 1.0f;
|
|
return dot(shadows, 0.25);
|
|
#endif
|
|
#else
|
|
#if defined (SHADOWS_CUBE_IN_DEPTH_TEX)
|
|
half shadow = UNITY_SAMPLE_TEXCUBE_SHADOW(_ShadowMapTexture, float4(vec, mydist));
|
|
return lerp(_LightShadowData.r, 1.0, shadow);
|
|
#else
|
|
half shadowVal = UnityDecodeCubeShadowDepth(UNITY_SAMPLE_TEXCUBE(_ShadowMapTexture, vec));
|
|
half shadow = shadowVal < mydist ? _LightShadowData.r : 1.0;
|
|
return shadow;
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
#endif // #if defined (SHADOWS_CUBE)
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Baked shadows
|
|
// ------------------------------------------------------------------
|
|
|
|
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
|
|
|
|
half4 LPPV_SampleProbeOcclusion(float3 worldPos)
|
|
{
|
|
const float transformToLocal = unity_ProbeVolumeParams.y;
|
|
const float texelSizeX = unity_ProbeVolumeParams.z;
|
|
|
|
//The SH coefficients textures and probe occlusion are packed into 1 atlas.
|
|
//-------------------------
|
|
//| ShR | ShG | ShB | Occ |
|
|
//-------------------------
|
|
|
|
float3 position = (transformToLocal == 1.0f) ? mul(unity_ProbeVolumeWorldToObject, float4(worldPos, 1.0)).xyz : worldPos;
|
|
|
|
//Get a tex coord between 0 and 1
|
|
float3 texCoord = (position - unity_ProbeVolumeMin.xyz) * unity_ProbeVolumeSizeInv.xyz;
|
|
|
|
// Sample fourth texture in the atlas
|
|
// We need to compute proper U coordinate to sample.
|
|
// Clamp the coordinate otherwize we'll have leaking between ShB coefficients and Probe Occlusion(Occ) info
|
|
texCoord.x = max(texCoord.x * 0.25f + 0.75f, 0.75f + 0.5f * texelSizeX);
|
|
|
|
return UNITY_SAMPLE_TEX3D_SAMPLER(unity_ProbeVolumeSH, unity_ProbeVolumeSH, texCoord);
|
|
}
|
|
|
|
#endif //#if UNITY_LIGHT_PROBE_PROXY_VOLUME
|
|
|
|
// ------------------------------------------------------------------
|
|
// Used by the forward rendering path
|
|
fixed UnitySampleBakedOcclusion (float2 lightmapUV, float3 worldPos)
|
|
{
|
|
#if defined (SHADOWS_SHADOWMASK)
|
|
#if defined(LIGHTMAP_ON)
|
|
fixed4 rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);
|
|
#else
|
|
fixed4 rawOcclusionMask = fixed4(1.0, 1.0, 1.0, 1.0);
|
|
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
|
|
if (unity_ProbeVolumeParams.x == 1.0)
|
|
rawOcclusionMask = LPPV_SampleProbeOcclusion(worldPos);
|
|
else
|
|
rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);
|
|
#else
|
|
rawOcclusionMask = UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);
|
|
#endif
|
|
#endif
|
|
return saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector));
|
|
|
|
#else
|
|
|
|
//In forward dynamic objects can only get baked occlusion from LPPV, light probe occlusion is done on the CPU by attenuating the light color.
|
|
fixed atten = 1.0f;
|
|
#if defined(UNITY_INSTANCING_ENABLED) && defined(UNITY_USE_SHCOEFFS_ARRAYS)
|
|
// ...unless we are doing instancing, and the attenuation is packed into SHC array's .w component.
|
|
atten = unity_SHC.w;
|
|
#endif
|
|
|
|
#if UNITY_LIGHT_PROBE_PROXY_VOLUME && !defined(LIGHTMAP_ON) && !UNITY_STANDARD_SIMPLE
|
|
fixed4 rawOcclusionMask = atten.xxxx;
|
|
if (unity_ProbeVolumeParams.x == 1.0)
|
|
rawOcclusionMask = LPPV_SampleProbeOcclusion(worldPos);
|
|
return saturate(dot(rawOcclusionMask, unity_OcclusionMaskSelector));
|
|
#endif
|
|
|
|
return atten;
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Used by the deferred rendering path (in the gbuffer pass)
|
|
fixed4 UnityGetRawBakedOcclusions(float2 lightmapUV, float3 worldPos)
|
|
{
|
|
#if defined (SHADOWS_SHADOWMASK)
|
|
#if defined(LIGHTMAP_ON)
|
|
return UNITY_SAMPLE_TEX2D(unity_ShadowMask, lightmapUV.xy);
|
|
#else
|
|
half4 probeOcclusion = unity_ProbesOcclusion;
|
|
|
|
#if UNITY_LIGHT_PROBE_PROXY_VOLUME
|
|
if (unity_ProbeVolumeParams.x == 1.0)
|
|
probeOcclusion = LPPV_SampleProbeOcclusion(worldPos);
|
|
#endif
|
|
|
|
return probeOcclusion;
|
|
#endif
|
|
#else
|
|
return fixed4(1.0, 1.0, 1.0, 1.0);
|
|
#endif
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Used by both the forward and the deferred rendering path
|
|
half UnityMixRealtimeAndBakedShadows(half realtimeShadowAttenuation, half bakedShadowAttenuation, half fade)
|
|
{
|
|
// -- Static objects --
|
|
// FWD BASE PASS
|
|
// ShadowMask mode = LIGHTMAP_ON + SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING
|
|
// Distance shadowmask mode = LIGHTMAP_ON + SHADOWS_SHADOWMASK
|
|
// Subtractive mode = LIGHTMAP_ON + LIGHTMAP_SHADOW_MIXING
|
|
// Pure realtime direct lit = LIGHTMAP_ON
|
|
|
|
// FWD ADD PASS
|
|
// ShadowMask mode = SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING
|
|
// Distance shadowmask mode = SHADOWS_SHADOWMASK
|
|
// Pure realtime direct lit = LIGHTMAP_ON
|
|
|
|
// DEFERRED LIGHTING PASS
|
|
// ShadowMask mode = LIGHTMAP_ON + SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING
|
|
// Distance shadowmask mode = LIGHTMAP_ON + SHADOWS_SHADOWMASK
|
|
// Pure realtime direct lit = LIGHTMAP_ON
|
|
|
|
// -- Dynamic objects --
|
|
// FWD BASE PASS + FWD ADD ASS
|
|
// ShadowMask mode = LIGHTMAP_SHADOW_MIXING
|
|
// Distance shadowmask mode = N/A
|
|
// Subtractive mode = LIGHTMAP_SHADOW_MIXING (only matter for LPPV. Light probes occlusion being done on CPU)
|
|
// Pure realtime direct lit = N/A
|
|
|
|
// DEFERRED LIGHTING PASS
|
|
// ShadowMask mode = SHADOWS_SHADOWMASK + LIGHTMAP_SHADOW_MIXING
|
|
// Distance shadowmask mode = SHADOWS_SHADOWMASK
|
|
// Pure realtime direct lit = N/A
|
|
|
|
#if !defined(SHADOWS_DEPTH) && !defined(SHADOWS_SCREEN) && !defined(SHADOWS_CUBE)
|
|
#if defined(LIGHTMAP_ON) && defined (LIGHTMAP_SHADOW_MIXING) && !defined (SHADOWS_SHADOWMASK)
|
|
//In subtractive mode when there is no shadow we kill the light contribution as direct as been baked in the lightmap.
|
|
return 0.0;
|
|
#else
|
|
return bakedShadowAttenuation;
|
|
#endif
|
|
#endif
|
|
|
|
#if (SHADER_TARGET <= 20) || UNITY_STANDARD_SIMPLE
|
|
//no fading nor blending on SM 2.0 because of instruction count limit.
|
|
#if defined(SHADOWS_SHADOWMASK) || defined(LIGHTMAP_SHADOW_MIXING)
|
|
return min(realtimeShadowAttenuation, bakedShadowAttenuation);
|
|
#else
|
|
return realtimeShadowAttenuation;
|
|
#endif
|
|
#endif
|
|
|
|
#if defined(LIGHTMAP_SHADOW_MIXING)
|
|
//Subtractive or shadowmask mode
|
|
realtimeShadowAttenuation = saturate(realtimeShadowAttenuation + fade);
|
|
return min(realtimeShadowAttenuation, bakedShadowAttenuation);
|
|
#endif
|
|
|
|
//In distance shadowmask or realtime shadow fadeout we lerp toward the baked shadows (bakedShadowAttenuation will be 1 if no baked shadows)
|
|
return lerp(realtimeShadowAttenuation, bakedShadowAttenuation, fade);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// Shadow fade
|
|
// ------------------------------------------------------------------
|
|
|
|
float UnityComputeShadowFadeDistance(float3 wpos, float z)
|
|
{
|
|
float sphereDist = distance(wpos, unity_ShadowFadeCenterAndType.xyz);
|
|
return lerp(z, sphereDist, unity_ShadowFadeCenterAndType.w);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
half UnityComputeShadowFade(float fadeDist)
|
|
{
|
|
return saturate(fadeDist * _LightShadowData.z + _LightShadowData.w);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Bias
|
|
// ------------------------------------------------------------------
|
|
|
|
/**
|
|
* Computes the receiver plane depth bias for the given shadow coord in screen space.
|
|
* Inspirations:
|
|
* http://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
|
|
* http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2012/10/Isidoro-ShadowMapping.pdf
|
|
*/
|
|
float3 UnityGetReceiverPlaneDepthBias(float3 shadowCoord, float biasMultiply)
|
|
{
|
|
// Should receiver plane bias be used? This estimates receiver slope using derivatives,
|
|
// and tries to tilt the PCF kernel along it. However, when doing it in screenspace from the depth texture
|
|
// (ie all light in deferred and directional light in both forward and deferred), the derivatives are wrong
|
|
// on edges or intersections of objects, leading to shadow artifacts. Thus it is disabled by default.
|
|
float3 biasUVZ = 0;
|
|
|
|
#if defined(UNITY_USE_RECEIVER_PLANE_BIAS) && defined(SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED)
|
|
float3 dx = ddx(shadowCoord);
|
|
float3 dy = ddy(shadowCoord);
|
|
|
|
biasUVZ.x = dy.y * dx.z - dx.y * dy.z;
|
|
biasUVZ.y = dx.x * dy.z - dy.x * dx.z;
|
|
biasUVZ.xy *= biasMultiply / ((dx.x * dy.y) - (dx.y * dy.x));
|
|
|
|
// Static depth biasing to make up for incorrect fractional sampling on the shadow map grid.
|
|
const float UNITY_RECEIVER_PLANE_MIN_FRACTIONAL_ERROR = 0.01f;
|
|
float fractionalSamplingError = dot(_ShadowMapTexture_TexelSize.xy, abs(biasUVZ.xy));
|
|
biasUVZ.z = -min(fractionalSamplingError, UNITY_RECEIVER_PLANE_MIN_FRACTIONAL_ERROR);
|
|
#if defined(UNITY_REVERSED_Z)
|
|
biasUVZ.z *= -1;
|
|
#endif
|
|
#endif
|
|
|
|
return biasUVZ;
|
|
}
|
|
|
|
/**
|
|
* Combines the different components of a shadow coordinate and returns the final coordinate.
|
|
* See UnityGetReceiverPlaneDepthBias
|
|
*/
|
|
float3 UnityCombineShadowcoordComponents(float2 baseUV, float2 deltaUV, float depth, float3 receiverPlaneDepthBias)
|
|
{
|
|
float3 uv = float3(baseUV + deltaUV, depth + receiverPlaneDepthBias.z);
|
|
uv.z += dot(deltaUV, receiverPlaneDepthBias.xy);
|
|
return uv;
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// PCF Filtering helpers
|
|
// ------------------------------------------------------------------
|
|
|
|
/**
|
|
* Assuming a isoceles rectangle triangle of height "triangleHeight" (as drawn below).
|
|
* This function return the area of the triangle above the first texel.
|
|
*
|
|
* |\ <-- 45 degree slop isosceles rectangle triangle
|
|
* | \
|
|
* ---- <-- length of this side is "triangleHeight"
|
|
* _ _ _ _ <-- texels
|
|
*/
|
|
float _UnityInternalGetAreaAboveFirstTexelUnderAIsocelesRectangleTriangle(float triangleHeight)
|
|
{
|
|
return triangleHeight - 0.5;
|
|
}
|
|
|
|
/**
|
|
* Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
|
|
* This function return the area of the triangle above each of those texels.
|
|
* | <-- offset from -0.5 to 0.5, 0 meaning triangle is exactly in the center
|
|
* / \ <-- 45 degree slop isosceles triangle (ie tent projected in 2D)
|
|
* / \
|
|
* _ _ _ _ <-- texels
|
|
* X Y Z W <-- result indices (in computedArea.xyzw and computedAreaUncut.xyzw)
|
|
*/
|
|
void _UnityInternalGetAreaPerTexel_3TexelsWideTriangleFilter(float offset, out float4 computedArea, out float4 computedAreaUncut)
|
|
{
|
|
//Compute the exterior areas
|
|
float offset01SquaredHalved = (offset + 0.5) * (offset + 0.5) * 0.5;
|
|
computedAreaUncut.x = computedArea.x = offset01SquaredHalved - offset;
|
|
computedAreaUncut.w = computedArea.w = offset01SquaredHalved;
|
|
|
|
//Compute the middle areas
|
|
//For Y : We find the area in Y of as if the left section of the isoceles triangle would
|
|
//intersect the axis between Y and Z (ie where offset = 0).
|
|
computedAreaUncut.y = _UnityInternalGetAreaAboveFirstTexelUnderAIsocelesRectangleTriangle(1.5 - offset);
|
|
//This area is superior to the one we are looking for if (offset < 0) thus we need to
|
|
//subtract the area of the triangle defined by (0,1.5-offset), (0,1.5+offset), (-offset,1.5).
|
|
float clampedOffsetLeft = min(offset,0);
|
|
float areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft;
|
|
computedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle;
|
|
|
|
//We do the same for the Z but with the right part of the isoceles triangle
|
|
computedAreaUncut.z = _UnityInternalGetAreaAboveFirstTexelUnderAIsocelesRectangleTriangle(1.5 + offset);
|
|
float clampedOffsetRight = max(offset,0);
|
|
float areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight;
|
|
computedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle;
|
|
}
|
|
|
|
/**
|
|
* Assuming a isoceles triangle of 1.5 texels height and 3 texels wide lying on 4 texels.
|
|
* This function return the weight of each texels area relative to the full triangle area.
|
|
*/
|
|
void _UnityInternalGetWeightPerTexel_3TexelsWideTriangleFilter(float offset, out float4 computedWeight)
|
|
{
|
|
float4 dummy;
|
|
_UnityInternalGetAreaPerTexel_3TexelsWideTriangleFilter(offset, computedWeight, dummy);
|
|
computedWeight *= 0.44444;//0.44 == 1/(the triangle area)
|
|
}
|
|
|
|
/**
|
|
* Assuming a isoceles triangle of 2.5 texel height and 5 texels wide lying on 6 texels.
|
|
* This function return the weight of each texels area relative to the full triangle area.
|
|
* / \
|
|
* _ _ _ _ _ _ <-- texels
|
|
* 0 1 2 3 4 5 <-- computed area indices (in texelsWeights[])
|
|
*/
|
|
void _UnityInternalGetWeightPerTexel_5TexelsWideTriangleFilter(float offset, out float3 texelsWeightsA, out float3 texelsWeightsB)
|
|
{
|
|
//See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
|
|
float4 computedArea_From3texelTriangle;
|
|
float4 computedAreaUncut_From3texelTriangle;
|
|
_UnityInternalGetAreaPerTexel_3TexelsWideTriangleFilter(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
|
|
|
|
//Triangle slop is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
|
|
//the 5 texel wide triangle can be seen as the 3 texel wide one but shifted up by one unit/texel.
|
|
//0.16 is 1/(the triangle area)
|
|
texelsWeightsA.x = 0.16 * (computedArea_From3texelTriangle.x);
|
|
texelsWeightsA.y = 0.16 * (computedAreaUncut_From3texelTriangle.y);
|
|
texelsWeightsA.z = 0.16 * (computedArea_From3texelTriangle.y + 1);
|
|
texelsWeightsB.x = 0.16 * (computedArea_From3texelTriangle.z + 1);
|
|
texelsWeightsB.y = 0.16 * (computedAreaUncut_From3texelTriangle.z);
|
|
texelsWeightsB.z = 0.16 * (computedArea_From3texelTriangle.w);
|
|
}
|
|
|
|
/**
|
|
* Assuming a isoceles triangle of 3.5 texel height and 7 texels wide lying on 8 texels.
|
|
* This function return the weight of each texels area relative to the full triangle area.
|
|
* / \
|
|
* _ _ _ _ _ _ _ _ <-- texels
|
|
* 0 1 2 3 4 5 6 7 <-- computed area indices (in texelsWeights[])
|
|
*/
|
|
void _UnityInternalGetWeightPerTexel_7TexelsWideTriangleFilter(float offset, out float4 texelsWeightsA, out float4 texelsWeightsB)
|
|
{
|
|
//See _UnityInternalGetAreaPerTexel_3TexelTriangleFilter for details.
|
|
float4 computedArea_From3texelTriangle;
|
|
float4 computedAreaUncut_From3texelTriangle;
|
|
_UnityInternalGetAreaPerTexel_3TexelsWideTriangleFilter(offset, computedArea_From3texelTriangle, computedAreaUncut_From3texelTriangle);
|
|
|
|
//Triangle slop is 45 degree thus we can almost reuse the result of the 3 texel wide computation.
|
|
//the 7 texel wide triangle can be seen as the 3 texel wide one but shifted up by two unit/texel.
|
|
//0.081632 is 1/(the triangle area)
|
|
texelsWeightsA.x = 0.081632 * (computedArea_From3texelTriangle.x);
|
|
texelsWeightsA.y = 0.081632 * (computedAreaUncut_From3texelTriangle.y);
|
|
texelsWeightsA.z = 0.081632 * (computedAreaUncut_From3texelTriangle.y + 1);
|
|
texelsWeightsA.w = 0.081632 * (computedArea_From3texelTriangle.y + 2);
|
|
texelsWeightsB.x = 0.081632 * (computedArea_From3texelTriangle.z + 2);
|
|
texelsWeightsB.y = 0.081632 * (computedAreaUncut_From3texelTriangle.z + 1);
|
|
texelsWeightsB.z = 0.081632 * (computedAreaUncut_From3texelTriangle.z);
|
|
texelsWeightsB.w = 0.081632 * (computedArea_From3texelTriangle.w);
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
// PCF Filtering
|
|
// ------------------------------------------------------------------
|
|
|
|
/**
|
|
* PCF gaussian shadowmap filtering based on a 3x3 kernel (9 taps no PCF hardware support)
|
|
*/
|
|
half UnitySampleShadowmap_PCF3x3NoHardwareSupport(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
half shadow = 1;
|
|
|
|
#ifdef SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
// when we don't have hardware PCF sampling, then the above 5x5 optimized PCF really does not work.
|
|
// Fallback to a simple 3x3 sampling with averaged results.
|
|
float2 base_uv = coord.xy;
|
|
float2 ts = _ShadowMapTexture_TexelSize.xy;
|
|
shadow = 0;
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(-ts.x, -ts.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(0, -ts.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(ts.x, -ts.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(-ts.x, 0), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(0, 0), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(ts.x, 0), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(-ts.x, ts.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(0, ts.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(ts.x, ts.y), coord.z, receiverPlaneDepthBias));
|
|
shadow /= 9.0;
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
/**
|
|
* PCF tent shadowmap filtering based on a 3x3 kernel (optimized with 4 taps)
|
|
*/
|
|
half UnitySampleShadowmap_PCF3x3Tent(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
half shadow = 1;
|
|
|
|
#ifdef SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
|
|
#ifndef SHADOWS_NATIVE
|
|
// when we don't have hardware PCF sampling, fallback to a simple 3x3 sampling with averaged results.
|
|
return UnitySampleShadowmap_PCF3x3NoHardwareSupport(coord, receiverPlaneDepthBias);
|
|
#endif
|
|
|
|
// tent base is 3x3 base thus covering from 9 to 12 texels, thus we need 4 bilinear PCF fetches
|
|
float2 tentCenterInTexelSpace = coord.xy * _ShadowMapTexture_TexelSize.zw;
|
|
float2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
|
|
float2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
|
|
|
|
// find the weight of each texel based
|
|
float4 texelsWeightsU, texelsWeightsV;
|
|
_UnityInternalGetWeightPerTexel_3TexelsWideTriangleFilter(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU);
|
|
_UnityInternalGetWeightPerTexel_3TexelsWideTriangleFilter(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV);
|
|
|
|
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
|
|
float2 fetchesWeightsU = texelsWeightsU.xz + texelsWeightsU.yw;
|
|
float2 fetchesWeightsV = texelsWeightsV.xz + texelsWeightsV.yw;
|
|
|
|
// move the PCF bilinear fetches to respect texels weights
|
|
float2 fetchesOffsetsU = texelsWeightsU.yw / fetchesWeightsU.xy + float2(-1.5,0.5);
|
|
float2 fetchesOffsetsV = texelsWeightsV.yw / fetchesWeightsV.xy + float2(-1.5,0.5);
|
|
fetchesOffsetsU *= _ShadowMapTexture_TexelSize.xx;
|
|
fetchesOffsetsV *= _ShadowMapTexture_TexelSize.yy;
|
|
|
|
// fetch !
|
|
float2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * _ShadowMapTexture_TexelSize.xy;
|
|
shadow = fetchesWeightsU.x * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.x * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
/**
|
|
* PCF tent shadowmap filtering based on a 5x5 kernel (optimized with 9 taps)
|
|
*/
|
|
half UnitySampleShadowmap_PCF5x5Tent(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
half shadow = 1;
|
|
|
|
#ifdef SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
|
|
#ifndef SHADOWS_NATIVE
|
|
// when we don't have hardware PCF sampling, fallback to a simple 3x3 sampling with averaged results.
|
|
return UnitySampleShadowmap_PCF3x3NoHardwareSupport(coord, receiverPlaneDepthBias);
|
|
#endif
|
|
|
|
// tent base is 5x5 base thus covering from 25 to 36 texels, thus we need 9 bilinear PCF fetches
|
|
float2 tentCenterInTexelSpace = coord.xy * _ShadowMapTexture_TexelSize.zw;
|
|
float2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
|
|
float2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
|
|
|
|
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
|
|
float3 texelsWeightsU_A, texelsWeightsU_B;
|
|
float3 texelsWeightsV_A, texelsWeightsV_B;
|
|
_UnityInternalGetWeightPerTexel_5TexelsWideTriangleFilter(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
|
|
_UnityInternalGetWeightPerTexel_5TexelsWideTriangleFilter(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
|
|
|
|
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
|
|
float3 fetchesWeightsU = float3(texelsWeightsU_A.xz, texelsWeightsU_B.y) + float3(texelsWeightsU_A.y, texelsWeightsU_B.xz);
|
|
float3 fetchesWeightsV = float3(texelsWeightsV_A.xz, texelsWeightsV_B.y) + float3(texelsWeightsV_A.y, texelsWeightsV_B.xz);
|
|
|
|
// move the PCF bilinear fetches to respect texels weights
|
|
float3 fetchesOffsetsU = float3(texelsWeightsU_A.y, texelsWeightsU_B.xz) / fetchesWeightsU.xyz + float3(-2.5,-0.5,1.5);
|
|
float3 fetchesOffsetsV = float3(texelsWeightsV_A.y, texelsWeightsV_B.xz) / fetchesWeightsV.xyz + float3(-2.5,-0.5,1.5);
|
|
fetchesOffsetsU *= _ShadowMapTexture_TexelSize.xxx;
|
|
fetchesOffsetsV *= _ShadowMapTexture_TexelSize.yyy;
|
|
|
|
// fetch !
|
|
float2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * _ShadowMapTexture_TexelSize.xy;
|
|
shadow = fetchesWeightsU.x * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.x * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.x * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
/**
|
|
* PCF tent shadowmap filtering based on a 7x7 kernel (optimized with 16 taps)
|
|
*/
|
|
half UnitySampleShadowmap_PCF7x7Tent(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
half shadow = 1;
|
|
|
|
#ifdef SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
|
|
#ifndef SHADOWS_NATIVE
|
|
// when we don't have hardware PCF sampling, fallback to a simple 3x3 sampling with averaged results.
|
|
return UnitySampleShadowmap_PCF3x3NoHardwareSupport(coord, receiverPlaneDepthBias);
|
|
#endif
|
|
|
|
// tent base is 7x7 base thus covering from 49 to 64 texels, thus we need 16 bilinear PCF fetches
|
|
float2 tentCenterInTexelSpace = coord.xy * _ShadowMapTexture_TexelSize.zw;
|
|
float2 centerOfFetchesInTexelSpace = floor(tentCenterInTexelSpace + 0.5);
|
|
float2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace;
|
|
|
|
// find the weight of each texel based on the area of a 45 degree slop tent above each of them.
|
|
float4 texelsWeightsU_A, texelsWeightsU_B;
|
|
float4 texelsWeightsV_A, texelsWeightsV_B;
|
|
_UnityInternalGetWeightPerTexel_7TexelsWideTriangleFilter(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsU_A, texelsWeightsU_B);
|
|
_UnityInternalGetWeightPerTexel_7TexelsWideTriangleFilter(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsV_A, texelsWeightsV_B);
|
|
|
|
// each fetch will cover a group of 2x2 texels, the weight of each group is the sum of the weights of the texels
|
|
float4 fetchesWeightsU = float4(texelsWeightsU_A.xz, texelsWeightsU_B.xz) + float4(texelsWeightsU_A.yw, texelsWeightsU_B.yw);
|
|
float4 fetchesWeightsV = float4(texelsWeightsV_A.xz, texelsWeightsV_B.xz) + float4(texelsWeightsV_A.yw, texelsWeightsV_B.yw);
|
|
|
|
// move the PCF bilinear fetches to respect texels weights
|
|
float4 fetchesOffsetsU = float4(texelsWeightsU_A.yw, texelsWeightsU_B.yw) / fetchesWeightsU.xyzw + float4(-3.5,-1.5,0.5,2.5);
|
|
float4 fetchesOffsetsV = float4(texelsWeightsV_A.yw, texelsWeightsV_B.yw) / fetchesWeightsV.xyzw + float4(-3.5,-1.5,0.5,2.5);
|
|
fetchesOffsetsU *= _ShadowMapTexture_TexelSize.xxxx;
|
|
fetchesOffsetsV *= _ShadowMapTexture_TexelSize.yyyy;
|
|
|
|
// fetch !
|
|
float2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * _ShadowMapTexture_TexelSize.xy;
|
|
shadow = fetchesWeightsU.x * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.w * fetchesWeightsV.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.w, fetchesOffsetsV.x), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.x * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.w * fetchesWeightsV.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.w, fetchesOffsetsV.y), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.x * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.w * fetchesWeightsV.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.w, fetchesOffsetsV.z), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.x * fetchesWeightsV.w * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.x, fetchesOffsetsV.w), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.y * fetchesWeightsV.w * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.y, fetchesOffsetsV.w), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.z * fetchesWeightsV.w * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.z, fetchesOffsetsV.w), coord.z, receiverPlaneDepthBias));
|
|
shadow += fetchesWeightsU.w * fetchesWeightsV.w * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(bilinearFetchOrigin, float2(fetchesOffsetsU.w, fetchesOffsetsV.w), coord.z, receiverPlaneDepthBias));
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
/**
|
|
* PCF gaussian shadowmap filtering based on a 3x3 kernel (optimized with 4 taps)
|
|
*
|
|
* Algorithm: http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/
|
|
* Implementation example: http://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
|
|
*/
|
|
half UnitySampleShadowmap_PCF3x3Gaussian(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
half shadow = 1;
|
|
|
|
#ifdef SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
|
|
#ifndef SHADOWS_NATIVE
|
|
// when we don't have hardware PCF sampling, fallback to a simple 3x3 sampling with averaged results.
|
|
return UnitySampleShadowmap_PCF3x3NoHardwareSupport(coord, receiverPlaneDepthBias);
|
|
#endif
|
|
|
|
const float2 offset = float2(0.5, 0.5);
|
|
float2 uv = (coord.xy * _ShadowMapTexture_TexelSize.zw) + offset;
|
|
float2 base_uv = (floor(uv) - offset) * _ShadowMapTexture_TexelSize.xy;
|
|
float2 st = frac(uv);
|
|
|
|
float2 uw = float2(3 - 2 * st.x, 1 + 2 * st.x);
|
|
float2 u = float2((2 - st.x) / uw.x - 1, (st.x) / uw.y + 1);
|
|
u *= _ShadowMapTexture_TexelSize.x;
|
|
|
|
float2 vw = float2(3 - 2 * st.y, 1 + 2 * st.y);
|
|
float2 v = float2((2 - st.y) / vw.x - 1, (st.y) / vw.y + 1);
|
|
v *= _ShadowMapTexture_TexelSize.y;
|
|
|
|
half sum = 0;
|
|
|
|
sum += uw[0] * vw[0] * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u[0], v[0]), coord.z, receiverPlaneDepthBias));
|
|
sum += uw[1] * vw[0] * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u[1], v[0]), coord.z, receiverPlaneDepthBias));
|
|
sum += uw[0] * vw[1] * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u[0], v[1]), coord.z, receiverPlaneDepthBias));
|
|
sum += uw[1] * vw[1] * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u[1], v[1]), coord.z, receiverPlaneDepthBias));
|
|
|
|
shadow = sum / 16.0f;
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
/**
|
|
* PCF gaussian shadowmap filtering based on a 5x5 kernel (optimized with 9 taps)
|
|
*
|
|
* Algorithm: http://the-witness.net/news/2013/09/shadow-mapping-summary-part-1/
|
|
* Implementation example: http://mynameismjp.wordpress.com/2013/09/10/shadow-maps/
|
|
*/
|
|
half UnitySampleShadowmap_PCF5x5Gaussian(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
half shadow = 1;
|
|
|
|
#ifdef SHADOWMAPSAMPLER_AND_TEXELSIZE_DEFINED
|
|
|
|
#ifndef SHADOWS_NATIVE
|
|
// when we don't have hardware PCF sampling, fallback to a simple 3x3 sampling with averaged results.
|
|
return UnitySampleShadowmap_PCF3x3NoHardwareSupport(coord, receiverPlaneDepthBias);
|
|
#endif
|
|
|
|
const float2 offset = float2(0.5, 0.5);
|
|
float2 uv = (coord.xy * _ShadowMapTexture_TexelSize.zw) + offset;
|
|
float2 base_uv = (floor(uv) - offset) * _ShadowMapTexture_TexelSize.xy;
|
|
float2 st = frac(uv);
|
|
|
|
float3 uw = float3(4 - 3 * st.x, 7, 1 + 3 * st.x);
|
|
float3 u = float3((3 - 2 * st.x) / uw.x - 2, (3 + st.x) / uw.y, st.x / uw.z + 2);
|
|
u *= _ShadowMapTexture_TexelSize.x;
|
|
|
|
float3 vw = float3(4 - 3 * st.y, 7, 1 + 3 * st.y);
|
|
float3 v = float3((3 - 2 * st.y) / vw.x - 2, (3 + st.y) / vw.y, st.y / vw.z + 2);
|
|
v *= _ShadowMapTexture_TexelSize.y;
|
|
|
|
half sum = 0.0f;
|
|
|
|
half3 accum = uw * vw.x;
|
|
sum += accum.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.x, v.x), coord.z, receiverPlaneDepthBias));
|
|
sum += accum.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.y, v.x), coord.z, receiverPlaneDepthBias));
|
|
sum += accum.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.z, v.x), coord.z, receiverPlaneDepthBias));
|
|
|
|
accum = uw * vw.y;
|
|
sum += accum.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.x, v.y), coord.z, receiverPlaneDepthBias));
|
|
sum += accum.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.y, v.y), coord.z, receiverPlaneDepthBias));
|
|
sum += accum.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.z, v.y), coord.z, receiverPlaneDepthBias));
|
|
|
|
accum = uw * vw.z;
|
|
sum += accum.x * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.x, v.z), coord.z, receiverPlaneDepthBias));
|
|
sum += accum.y * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.y, v.z), coord.z, receiverPlaneDepthBias));
|
|
sum += accum.z * UNITY_SAMPLE_SHADOW(_ShadowMapTexture, UnityCombineShadowcoordComponents(base_uv, float2(u.z, v.z), coord.z, receiverPlaneDepthBias));
|
|
shadow = sum / 144.0f;
|
|
|
|
#endif
|
|
|
|
return shadow;
|
|
}
|
|
|
|
half UnitySampleShadowmap_PCF3x3(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
return UnitySampleShadowmap_PCF3x3Tent(coord, receiverPlaneDepthBias);
|
|
}
|
|
|
|
half UnitySampleShadowmap_PCF5x5(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
return UnitySampleShadowmap_PCF5x5Tent(coord, receiverPlaneDepthBias);
|
|
}
|
|
|
|
half UnitySampleShadowmap_PCF7x7(float4 coord, float3 receiverPlaneDepthBias)
|
|
{
|
|
return UnitySampleShadowmap_PCF7x7Tent(coord, receiverPlaneDepthBias);
|
|
}
|
|
|
|
#endif // UNITY_BUILTIN_SHADOW_LIBRARY_INCLUDED
|