参考教程
学习记录
这篇文章中我们介绍在 DX11 中实现阴影映射。
阴影的示意图如下:
The basic shadowmap algorithm consists in two passes. First, the scene is rendered from the point of view of the light. Only the depth of each fragment is computed. Next, the scene is rendered as usual, but with an extra test to see it the current fragment is in the shadow.
The “being in the shadow” test is actually quite simple. If the current sample is further from the light than the shadowmap at the same point, this means that the scene contains an object that is closer to the light. In other words, the current fragment is in the shadow.
我们对于动态阴影的渲染可以分为以下两个部分:1. 以光的视角来渲染一张纹理,这张纹理上存储了像素点的深度,我们称它为深度图。2. 正常渲染,不同的是我们在像素着色器中判断当前像素的深度,如果它大于深度图中存储的深度,则它处于阴影中。
这么想的话其实并不复杂,我们首先使用 RenderToTexture 技术将像素的深度存入我们的深度图,我们需要一个 DepthShaderClass
以及对应着色器。由于只是存入深度信息,所以比较简单。
着色器代码如下:
1 | //////////////////////////////////////////////////////////////////////////////// |
其对应的 DepthShaderClass
类也比较简单,在此我们贴出声明:
1 | //////////////////////////////////////////////////////////////////////////////// |
相比较而言,我们需要注意的是 shadow
着色器的内容,如我们上边所言,我们需要使用深度图中的深度进行比较,所以需要计算当前像素相对于光源的深度,在 vertex
中我们完成计算光源坐标以及方向,如下:
1 | //////////////////////////////////////////////////////////////////////////////// |
在像素着色器中我们读出投影到当前像素的深度图中的深度,然后使用变换后的相对于光源的坐标来得到相对于光源的深度,然后进行比较,当深度小于深度图中深度的时候我们对他进行正常光照,相反则只进行环境光计算,达到阴影效果。像素着色器中代码如下:
1 | //////////////////////////////////////////////////////////////////////////////// |
关于光照,投影映射我们之前的文章中都有介绍。
Shadow shader 对应的着色器类也仅仅是缓冲的不同,我们依旧只列出其类声明,具体实现可以参考源码:
1 | //////////////////////////////////////////////////////////////////////////////// |
在 GraphicsClass
中我们首先通过 DepthShaderClass
对象将深度信息绘制进纹理中,然后再使用 ShadowShaderClass
对象进行渲染,部分代码如下:
1 | bool GraphicsClass::Frame(float posX, float posY, float posZ, float rotX, float rotY, float rotZ) |
我们设计了一个在场景上方缓缓移动的光源,这样我们可以看到阴影的变化,某一刻的效果如下: