之前写过一篇:Unity Shader - Custom DirectionalLight ShadowMap 自定义方向光的ShadowMap
但是因为这篇中的部分模型使用到以前公司的模型,所以DEMO没有公开,这篇,因为项目组之前发现内置 unity shadow map 会导致手机上崩溃,所以考虑自己写一个 shadow map
但是最终发现,如果没有 unity 阴影源码,还是不要重新显示 shadow map 阴影这块,因为有很多问题
之前那篇的 Shadow Map 基于 ClipSpace 下比较深度 我们下面是基于 ViewSpace 下比较深度
Shadow map 思路:
- 在 DirectionalLight 同向的 LightCamera 拍下所有需要投影部分的对象 的 ViewZ 到一个
ShadowDepthRT - 将
ShadowDepthRT 中的深度传入到每个需要接受阴影的 shader 中 - 接受阴影的 shader 中的 顶点着色器,获取正在绘制的顶点坐标转为 LightCamera 下的 View 坐标
ShadowPosOnLightCameraViewSpace ,并插值后传入 片段着色器中 - 片段着色器中,将
ShadowPosOnLightCameraViewSpace.xy / Camera.orthSize 得到投影面中的 -1, 1 坐标,再转为 0, 1 坐标 作为 ShadowDepthRT 的采样 uv 坐标:ShadowDepthRTUV ShadowPosOnLightCameraViewSpace.z 就是 fragDepth 就是当前片段的深度- 使用
ShadowDepthRTUV 采样 ShadowDepthRT 中的深度,与正在绘制片段的ShadowPosOnLightCameraViewSpace.z 也就是 LightCamera 下的 ViewZ:ShadowMapDepth - 这时已有
fragDepth 和 ShadowMapDepth ,如果 fragDepth 比 ShadowMapDepth 大,说明片段在阴影中
这其中,第 1 点有些非常致命的问题:
- 灯光视角下的 LightCamera 如果拍的内容有 LODGroup ,并且在 MainCamera 下显示时 LOD0,但是在 LightCamera 下显示时 LOD1,而 LOD1 是简模,因为减模可能模型表面的深度与 LOD0 的原模型深度不一致,那么可能导致阴影效果异常
- 在 LightCamera.SetReplacementShader 时,只能替换为一种 shader中 pass 来执行,而不能将不同的 Shader 替换成不同的 shader 中的 pass,什么意思呢,就是如果我有两个渲染对象,一个是石头,不透明的 Opaque,一个是树叶 AlphaTest,如果两个渲染对象的 shader 都替换为一个以 Opaque 方式来绘制阴影RT 的话,那么树叶的 AlphaTest 将不会镂空,导致树叶的投影都是一个一个面片,没有树叶的纹理轮廓的形状,所以正常的话,应该:Opaque 的替换才 Opaque 的 Shadow Caster 对应的 shader,而 AlphaTest 的应该就替换成 AlphaTest 的,如果还有顶点动画的呢?所以啊,最终就是想要每个 原始 shader 都应该有一个 对应的 Shadow Caster 的shader,这也为何 unity 内置 shadow map 功能时,为何 每个 shaderLab 中,如果需要有投影功能的话,就需要提供一个
"LightMode="ShadowCaster" 的 pass tags,这是 Camera.SetReplacementShader API 无法满足功能的源码
基于以上两个问题所在,所以我们就不使用 custom shadow map 的方式了,除非我们有 unity 引擎源码,自己封装:
- Camera.ReplaceShadowCasterShader 的API解决 Camera.SetReplacementShader 无法满足功能的问题
- Camera.GetUnionRenderWithOtherCamera 的 API 解决 MainCamera 下显示时 LOD0,但是在 LightCamera 下显示时 LOD1 的 模型深度绘制的问题
效果
Project
因为是自己的 DEMO,没有什么公司的资源,所以可以公开 DEMO TestingShadowMapNewVer 提取码: yfed
unity 版本:2019.3.8f1 实验场景名:CustomShadowMapScene.unity 渲染管线:builit-in
|