这次又花了大概一周的时间把阴影加到了软渲染中。到这一步的时候mini3d和tinyrenderer基本起不到帮助了。同时《3D游戏编程大师技巧》里阴影的实现方式比较古老,是利用事先准备好的光照图做Alpha混合来实现阴影的效果。这里也不打算采用这种方式。
一个比较好实现动态硬阴影的技术叫做shadow map。这个时候就需要把目光放到 @zauonlok 大佬的renderer以及learnopengl-cn,参考并学习如何实现阴影。
场景准备
为了比较好观察阴影的效果,这个时候场景中需要有多个物体。这里选取了一个立方体和一个平面。
我在载入这两个物体后观察发现,又又又出现了模型漏缝的情况,如下图:
最后检查后发现,其实并不是严格意义上的漏缝。而是由于这个立方体是由24个顶点组成的。下面的黑边其实是一个独立的三角形。
由于此时没有开启背面剔除,同时z-buffer的判断还包含了相等的情况。换句话说就是当深度值一样的时候,后画的像素会把先画的像素覆盖掉。
所以这两个原因导致了下面那个三角形也被画了出来。这个时候就在画面上呈现出一个像素高的黑边。
开启背面剔除,同时把深度判断相等的情况去掉。黑边的问题解决。
阴影的原理
Shadow map的原理并不难,看LearnOpenGL的相关章节很容易弄明白。
阴影映射由两个步骤组成:首先,我们渲染深度贴图,然后我们像往常一样渲染场景,使用生成的深度贴图来计算片段是否在阴影之中。
这里的两个步骤(Pass)实际上就是渲染两次。第一次的时候把深度信息写入shadow map中。第二次的时候再根据shadow map中的深度值来判断当前像素是不是在阴影中即可。
第一个Pass
局部空间上的一个点最后变换到屏幕空间需要经过MVP变换和最后的视口变换。如下图: