找回密码
 立即注册
查看: 293|回复: 0

Unity Shadow Map(二 实践)

[复制链接]
发表于 2023-4-6 14:12 | 显示全部楼层 |阅读模式
本文主要阐述Unity源码实现,理论部分请参考 Unity Shadow Map(一 理论) - 知乎 (zhihu.com)
关于shadow map 的参考资料:图形学中级学习推荐 - 知乎 (zhihu.com)
关于“卷积”的参考资料学习资料:图形学好书——虎书 - 知乎 (zhihu.com)
2. Unity实现阴影

试验场景中包含 cube, cylinder,plane,,绕y轴旋转60度的平行光源, 透视Camera.




2. 1 摄像机深度图

2.1.1 渲染Shader

每个摄像机都会渲染一张深度图,为后续步骤做准备. Unity中的默认深度渲染是通过Standard文件中的Name为ShadowCaster的Pass. 我们自己编写的Shader中,如果不写会通过FallBack找到;如果是FallBack Off, 那就不会将绑定此Shader的物体渲染到深度图. 图中一个是默认的ShadowCaster, 另一个是自己的ShadowCaster.


摄像机深度图的渲染结果如图所示.有时候会看不到这图象,此时可以调节摄像机的近截面数值会改变图像的敏感区域.左边时Camera的n=1时的深度图,右边是n=3 时的深度图.


2.2.2 摄像机深度图细节

每个摄像机都会渲染一张深度图,为后续各种渲染做准备. Unity中的默认深度渲染是通过Standard文件中的Name为ShadowCaster的Pass. 在自己编写的Shader中,如果不写会通过FallBack找到,如果是FallBack Off, 那就不会将绑定此Shader的物体渲染到深度图. 图中一个是默认的ShadowCaster, 另一个是自己的ShadowCaster. 摄像机深度图的渲染,就是利用深度测试和深度缓存实现的,将距离摄像机最近的物体z坐标写入深度缓存. 这个操作仅仅需要利用摄像机投影矩阵,将顶点坐标变换到剪裁空间,最后做一个齐次除法即可. 深度缓存里存储的,就是归一化的,而且可能是reverse-z的深度值. 另外这个深度缓存的内容,应该会保存到一个临时的贴图中,以为后续处理做准备.
UNITY_REVERSED_Z
如果定义了,剪裁空间中的近截面z=1,没定义,近截面z=0.
使用reversed-z技术的原因是为了弥补深度缓存的精度问题。由于z不是均匀分布的,离近剪裁面越近的地方,z的精度越高,而越远的地方,z的精度越低。而如果用浮点数来保存z的值,浮点数又在值靠近0时有较高的精度,靠近1时精度较差。因此,为了让其互补,就将z的取值进行reverse,这样靠近1的z值虽然浮点精度有限,但是离近剪裁面会更近;同样地,靠近0的z值虽然离近剪裁面较远,但是浮点精度更高








2. 2 绘制ShadowMap

2.2.1 Shader 信息

该步骤的主要目标是得到一张,光源坐标系的,场景深度图纹理,记录从光源角度“观察”,场景中距离光源最近的物体的光源空间深度Z坐标.渲染结果如图.


2.2.2 ShadowCaster Pass

首先来看下Cube使用的自己编写的Name 为“MyShadowCaster”的Pass, 就会发现和Standard.shader中的” ShadowCaster”Pass 基本一致,差别主要是官方的Pass中定义了很多宏,以方便处理各种情况.所以通过自己的Pass,可以发现,真正起到作用的就是图中的三条宏定义.


a.数据结构


b.顶点着色函数




Normal Bias
Normal Bias的数值设置,决定了在法线方向上,场景物体渲染shadow map 时深度增加的大小. 如果这个数值为0,就会出现自阴影,也就是shadow acne, 如图. 这种偏移对渲染点的法线方向更加敏感.


Shadow Cascaded
当Camera的远截面变大,光源深度图的精度就变差,同样的normal bias, 应用到精度差的shadowmap上,仍然会有自阴影, 如图. 所以Shadow Cascaded的必要性就非常大, 可以根据摄像机的深度,绘制出不同分辨率的shadow map. 然后进行插值得到效果更好的阴影.






Bias
Bias的数值设置,决定了在剪裁空间,根据距离光源的距离进行的深度增加,距离越远,增加越少. 也就是说bias偏移是方向无差别的,但对顶点和光源之间的距离敏感, 随与光源的距离,进行不同程度的偏移. 总之就是整体增加场景物体在shadow map 中的深度值, 相当于渲染时将场景中的物体整体向光源方向移动再和shadow map作比较.




2.3 绘制阴影衰减纹理

2.3.1 shader

该步骤的目标是,将场景中渲染目标的坐标,转换到光源空间中,并将Zlight与ShadowMap中相应的的 Zshadowmap比较,得出该目标点是否处于阴影之中,然后绘制一张,从摄像机角度观察,阴影造成的屏幕空间上衰减的纹理.


2.3.2 屏幕阴影衰减Pass

























2.3.3 屏幕阴影衰减Soft Pass







a. 阴影接受平面Bias




b. PCF 滤波












c. 不同等级shadow map 采样融合


2.4 生成阴影

2.4.1 屏幕阴影衰减纹理的使用

该步骤的目标是,采集屏幕空间的阴影衰减纹理,并完成最终的光照计算.
光照数值 * 阴影衰减 = 最终渲染结果


2.4.2 阴影Pass实现细节

定义阴影所需数据结构SHADOW_COORDS











参考资料:

Real-Time Rendering, Fourth Edition 4th
Fundamentals of Computer Graphics, Fourth Edition by Marschner, Steve Shirley, Peter (http://z-lib.org)
https://docs.unity3d.com/Manual/shadow-cascades.html
https://blog.csdn.net/cgy56191948/article/details/105726682
https://zhuanlan.zhihu.com/p/369761748
https://zhuanlan.zhihu.com/p/398474186

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-30 07:47 , Processed in 0.100176 second(s), 28 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表