如何解决处理透视阴影贴图深度值的非线性
我在 GLSL 中实现了 shadow maps,方法是将视图从灯光渲染到深度纹理,然后在第二遍中,在从相机视图渲染我的几何体时比较这些值。
在缩写代码中,第二个(主)渲染通道的顶点着色器是:
...
gl_Position = camviewprojmat * position;
shadowcoord = lightviewprojmat * postion;
...
和片段着色器我在阴影纹理中查找此 shadowcoord
纹素以查看灯光是否看到相同的事物(点亮)或更近的事物(阴影)。这是通过将 GL_TEXTURE_COMPARE_MODE 设置为GL_COMPARE_REF_TO_TEXTURE
用于深度纹理。
这适用于具有正交投影的灯光。但是一旦我使用透视投影创建广角聚光灯,我就会在图像中遇到错误。
我已确定问题的原因是错误插入的深度值 shadowcoord.z / shadowcoord.w
,由于透视投影,该值不是线性的。然而,三角形的插值是线性的。
在顶点位置,深度值是准确确定的,但顶点位置之间的片段获得了错误的深度插值。
下图展示了这一点。黄色十字准线是灯光位置,这是一个直视下的聚光灯。颜色编码是从 -1(红色)到 +1(蓝色)的光深度。
中间的柱子从上到下都有长长的三角形,所有插值的光深度值都相差很多。
左侧的楼梯有更多的顶点位置,因此可以更准确地采样非线性深度。
我用于聚光灯的项目矩阵是这样创建的(我使用了 170 度的非常广角):
// create a perspective projection matrix
const float f = 1.0f / tanf(fov/2.0f);
const float aspect = 1.0f;
float* mout = sl_proj.data;
mout[0] = f / aspect;
mout[1] = 0.0f;
mout[2] = 0.0f;
mout[3] = 0.0f;
mout[4] = 0.0f;
mout[5] = f;
mout[6] = 0.0f;
mout[7] = 0.0f;
mout[8] = 0.0f;
mout[9] = 0.0f;
mout[10] = (zFar+zNear) / (zNear-zFar);
mout[11] = -1.0f;
mout[12] = 0.0f;
mout[13] = 0.0f;
mout[14] = 2 * zFar * zNear / (zNear-zFar);
mout[15] = 0.0f;
如何处理光深度缓冲区中的这种非线性?是否可以使用具有线性深度值的透视投影?我应该以不同的方式计算阴影坐标吗?事后可以纠正吗?
注意:我确实考虑过在片段着色器中进行投影,但由于场景中有很多灯光,因此在片段着色器中进行所有这些矩阵乘法的计算成本太高。
解决方法
这个 stackoverflow answer 描述了如何做一个线性深度缓冲。
它需要在顶点着色器中写出深度(modelviewprojmat * position).z
,然后在片段着色器中计算线性深度为:
gl_FragDepth = ( depth - zNear ) / ( zFar - zNear );
并且使用线性深度缓冲区,片段插值器可以正常工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。