繁体   English   中英

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

[英]Dealing with the non-linearity of perspective shadowmap depth values

我已经在 GLSL 中通过将视图从灯光渲染到深度纹理来实现阴影贴图,然后在第二遍比较这些值时从相机视图渲染我的几何图形。

在缩写代码中,第二个(主)渲染通道的顶点着色器是:

...
gl_Position = camviewprojmat * position;
shadowcoord = lightviewprojmat * postion;
...

和片段着色器我在阴影纹理中查找这个shadowcoord texel,看看光线是否看到相同的东西(点亮),或者更接近的东西(阴影)。这是通过将深度纹理的GL_COMPARE_REF_TO_TEXTURE设置为GL_COMPARE_REF_TO_TEXTURE来完成的。

这对于具有正交投影的灯光非常有用。 但是一旦我使用透视投影来创建广角聚光灯,我就会在图像中遇到错误。

我已经确定我的问题的原因是插值不正确的深度值shadowcoord.z / shadowcoord.w ,由于透视投影,它不是线性的。 然而,三角形上的插值是线性的。

在顶点位置,深度值是精确确定的,但顶点位置之间的片段会得到错误的深度插值值。

下图证明了这一点。 黄色十字准线是光 position,它是一个直向下看的聚光灯。 颜色编码是从 -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答案描述了如何做一个线性深度缓冲区。

它需要在顶点着色器中写出深度(modelviewprojmat * position).z ,然后在片段着色器中计算线性深度:

gl_FragDepth = ( depth - zNear ) / ( zFar - zNear );

使用线性深度缓冲区,片段插值器可以正常工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM