这两个方法用于计算阴影渐变衰减
1,UnityComputeShadowFadeDistance:
源码:
float UnityComputeShadowFadeDistance(float3 wpos, float z)
{
float sphereDist = distance(wpos, unity_ShadowFadeCenterAndType.xyz);
return lerp(z, sphereDist, unity_ShadowFadeCenterAndType.w);
}
作用:计算世界坐标到阴影衰减中心的距离。
原理:
传入的两个参数分别是:片元的世界坐标,片元视口空间下的z值
衰减中心有两种类型:1:位于相机位置的前方0.2666(1/3.75)倍阴影距离处,下面称为偏移衰减中心。2:位于摄像机所在坐标
unity_ShadowFadeCenterAndType.w:存储着衰减类型,数值是0或者1,0代表为偏移衰减中心,1代表衰减中心位于摄像机所在坐标
unity_ShadowFadeCenterAndType.xyz:当衰减中心偏移到摄像机前面2.66666倍阴影距离的时候(衰减中心是摄像机坐标的时候xyz分量没有意义),unity_ShadowFadeCenterAndType.xyz储存的是阴影衰减中心的世界坐标。数值上等于camPos + normalize( camFront ) * 0.26666f * shadowDistance,其中shadowDistance是阴影距离对应我们的设置ProjectSettings -> Quality -> Shadows -> Shadow Distance。
2,UnityComputeShadowFade:
half UnityComputeShadowFade(float fadeDist)
{
return saturate(fadeDist * _LightShadowData.z + _LightShadowData.w);
}
作用:根据片元到衰减中心的距离计算阴影衰减值,返回数值范围是0~1,0表示没有衰减,1表示全衰减。
原理:
_LightShadowData.x = 1.0 - shadow_strength // shadow_strength就是灯光组件里面的阴影强度,Strength(0~1)
_LightShadowData.y = max(camera_far_clip / shadow_distance, 1.0) // 但未在当前内置着色器代码库中使用
_LightShadowData.z = 5.0f * 1 / min(camera_far_clip, shadow_distance) // 不太确定,但看起来是这样的
_LightShadowData.w = -1.0f * (2.0f + camera_field_of_view / 180.0f * 2.0f) // 正交时,fov被视为0
以偏移衰减中心以及shadow_distance = 100 、camera_far_clip = 1000,camera_field_of_view = 60为例:
o点为摄像机位置,a点位偏移衰减中心,位于摄像机前0.266666倍阴影距离处(26.66666),以a点为圆心,画一个半径为1 - 0.266666被阴影距离的圆,这个圆就是阴影投影区域。
当shadow_distance = 100 、camera_far_clip = 1000,camera_field_of_view = 60时,_LightShadowData.z = 1 / 20, _LightShadowData.w = -2.66667
现在计算最远处片元的阴影衰减:预期计算结果应该是1,全衰减,即最远处阴影应该衰减到没有。
最远处片元到衰减中心的距离是73.33333333,
代入fadeDist * _LightShadowData.z + _LightShadowData.w = 73.333 * 1/20 - 2.667 = 3.667 - 2.667 = 1。与预期一样
计算五分之四处片元的阴影衰减:预期计算结果应该是0,从4/5倍阴影距离开始衰减。五分之四处到衰减中心的距离是100 * 4/5 - 26.667 = 53.333
代入fadeDist * _LightShadowData.z + _LightShadowData.w = 53.333 * 1/20 - 2.667 = 2.667 - 2.667 = 0。与预期一样
由此可知,从shadow_distance的五分之四处,开始渐变衰减,到了五分之五处渐变成全衰减。
用法:
// 直接光(uv:屏幕空间坐标,worldPos:片元世界坐标,viewZ:片元视口空间z值)
UnityLight CreateLight(float uv, float3 worldPos, float viewZ){
UnityLight light;
light.dir = -_LightDir; // 光源到片元的向量转换成片元到光源的向量
float shadowAttenuation = 1; // 阴影,1表示没有阴影
#if defined(SHADOWS_SCREEN) // 判断是否启用了屏幕空间阴影
shadowAttenuation = tex2D(_ShadowMapTexture, uv).r // 从阴影贴图采样阴影值
// 得到片元与阴影衰减中心的距离
float shadowFadeDistance = UnityComputeShadowFadeDistance(worldPos, viewZ)
// 得到阴影衰减值
float shadowFade = UnityComputeShadowFade(shadowFadeDistance);
// 把阴影衰减应用到阴影值里
shadowAttenuation = saturate(shadowAttenuation + shadowFade);
#endif
light.color = _LightColor.rgb * shadowAttenuation; // 把阴影应用到光照颜色中
return light;
}