简体   繁体   English

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

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

I have implemented shadow maps in GLSL by rendering the view from a light into a depth texture, and then in a second pass compare these values when rendering my geometry from camera view.我已经在 GLSL 中通过将视图从灯光渲染到深度纹理来实现阴影贴图,然后在第二遍比较这些值时从相机视图渲染我的几何图形。

In abbreviated code, the vertex shader of the second (main) render pass is:在缩写代码中,第二个(主)渲染通道的顶点着色器是:

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

and fragment shader I lookup this shadowcoord texel in the shadow texture to see if the light sees the same thing (lit), or something closer (shadowed.) This is done by setting GL_TEXTURE_COMPARE_MODE to GL_COMPARE_REF_TO_TEXTURE for the depth texture.和片段着色器我在阴影纹理中查找这个shadowcoord texel,看看光线是否看到相同的东西(点亮),或者更接近的东西(阴影)。这是通过将深度纹理的GL_COMPARE_REF_TO_TEXTURE设置为GL_COMPARE_REF_TO_TEXTURE来完成的。

This works great for lights that have an orthogonal projection.这对于具有正交投影的灯光非常有用。 But once I use a perspective projection to create wide-angle spot lights, I encounter errors in the image.但是一旦我使用透视投影来创建广角聚光灯,我就会在图像中遇到错误。

I have determined the cause of my issues to be the incorrectly interpolated depth values shadowcoord.z / shadowcoord.w which, due to the perspective projection, are not linear.我已经确定我的问题的原因是插值不正确的深度值shadowcoord.z / shadowcoord.w ,由于透视投影,它不是线性的。 Yet, the interpolation over the triangle is linear.然而,三角形上的插值是线性的。

At the vertex locations, the depth values are determined exactly, but the fragments between vertex locations get incorrectly interpolated values for depth.在顶点位置,深度值是精确确定的,但顶点位置之间的片段会得到错误的深度插值值。

This is demonstrated by the image below.下图证明了这一点。 The yellow crosshairs are the light position, which is a spot-light looking straight down.黄色十字准线是光 position,它是一个直向下看的聚光灯。 The colour-coding is the light-depth from -1 (red) to +1 (blue.)颜色编码是从 -1(红色)到 +1(蓝色)的光深度。

深度插值

The pillar in the middle has long tall triangles from top to bottom, and all the interpolated light-depth values are off by a lot.中间的柱子从上到下有长而高的三角形,所有插值的光深度值都偏离了很多。

The stairs on the left have much more vertex locations, so it samples the non-linear depths more accurately.左边的楼梯有更多的顶点位置,因此它可以更准确地对非线性深度进行采样。

The project matrix I use for the spot light is created like this (I use a very wide angle of 170 deg):我用于聚光灯的项目矩阵是这样创建的(我使用 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;

How can I deal with this non-linearity in the light depth buffer?如何处理光深度缓冲区中的这种非线性? Is it possible to have perspective projection that has linear depth values?是否可以有具有线性深度值的透视投影? Should I compute my shadow coordinates differently?我应该以不同的方式计算我的阴影坐标吗? Can they be corrected after the fact?事后可以纠正吗?

Note: I did consider doing the projection in the fragment shader instead, but as I have many lights in the scene, doing all those matrix multiplications in the fragment shader would be too costly in computation.注意:我确实考虑过在片段着色器中进行投影,但由于场景中有很多灯光,所以在片段着色器中进行所有这些矩阵乘法计算成本太高。

This stackoverflow answer describes how to do a linear depth buffer.这个stackoverflow答案描述了如何做一个线性深度缓冲区。

It entails writing out the depth (modelviewprojmat * position).z in the vertex shader, and then in the fragment shader compute the linear depth as:它需要在顶点着色器中写出深度(modelviewprojmat * position).z ,然后在片段着色器中计算线性深度:

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

And with a linear depth buffer, the fragment interpolators can do their job properly.使用线性深度缓冲区,片段插值器可以正常工作。

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

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