阴影失真
从下面的图可以看到阴影出现了很大的问题,出现了很多摩尔纹,而且还在闪烁。

首先回顾一下阴影的渲染流程:
成因分析:

第一次渲染的时候,从光源的视角计算深度并将其存储到纹理中。上图就是这个过程,红色的线表示纹理的一个单元,同一个纹素存储的深度信息是相同的。但是在上图可以看到,同一个纹素存储相同的深度信息,但是实际上是有误差的,这个片段中有些深度大于纹素存储的,有些小于纹素存储的深度。在第二次渲染的时候,我们比较用真实深度与深度贴图中的深度信息进行比较,这时候就会存在误差,进行阴影渲染的时候就会造成同一个片段有些地方有阴影有些地方没有,这种现象叫做 Shadow Acne。
为了解决这个问题,我们可以给深度添加一个偏差值,如下图所示,这样我们在比较深度信息的时候,就不容易出现误判的情况了。这种方法叫做shadow bias ,阴影偏移。

float shadow = currentDepth - shadowBias > closestDepth ? 1.0 : 0.0f;

这样子可以很好的解决问题,但不是完美解决,如果光线与片段的倾角特别大的话,还是会出现这个问题的,我们可以根据光线和片段之间的角度关系来更改这个偏移量:
float bias = max(0.05 * (1.0f - dot(normalize(fs_in.normal), lightDir)), shadowBias);
float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0f;

阴影悬浮
上面的方法虽然解决了阴影失真的问题,但同样地带来了新的问题,就是当我们使用的偏移值太大了的时候,我们渲染出来的阴影会明显的偏离实际物体,如下图所示,这样渲染出来的图像,会感觉物体悬浮在了阴影上面。本质是深度偏移过度地将阴影边界推离实际几何体表面。

为了解决这个问题,我们可以在渲染深度贴图的时候,开启正面剔除。这是因为默认的是背面剔除,这时候的深度贴图记录的是可见表面(正面)的最浅深度,当物体贴近地面的时候,实际深度约等于地面的深度,这时候使用过大的Bias,会导致 实际深度 - Bias << 深度贴图值,就会地面被误判在阴影区 → 阴影向后退。

当我们使用正面剔除的时候,深度值增大了,因为 背面的深度 > 正面的深度,所以深度贴图中记录的深度值就变大了,在上述比较重就不容易被误判为阴影了。
glCullFace(GL_FRONT);
RenderSceneToDepthMap();
glCullFace(GL_BACK); // 不要忘记设回原先的面剔除
744

被折叠的 条评论
为什么被折叠?



