微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

处理透视阴影贴图深度值的非线性

如何解决处理透视阴影贴图深度值的非线性

我在 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(蓝色)的光深度。

depth interpolation

间的柱子从上到下都有长长的三角形,所有插值的光深度值都相差很多。

左侧的楼梯有更多的顶点位置,因此可以更准确地采样非线性深度。

我用于聚光灯的项目矩阵是这样创建的(我使用了 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 举报,一经查实,本站将立刻删除。