【发布时间】:2021-03-24 18:07:28
【问题描述】:
我已经在 GLSL 中实现了shadow maps,方法是将视图从灯光渲染到深度纹理中,然后在第二遍比较这些值时从相机视图渲染我的几何体。
在缩写代码中,第二个(主)渲染通道的顶点着色器是:
...
gl_Position = camviewprojmat * position;
shadowcoord = lightviewprojmat * postion;
...
和片段着色器我在阴影纹理中查找此shadowcoord texel,以查看光线是否看到相同的东西(照亮)或更接近的东西(阴影)。这是通过将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;
如何处理光深度缓冲区中的这种非线性?是否可以有具有线性深度值的透视投影?我应该以不同的方式计算我的阴影坐标吗?事后可以改正吗?
注意:我确实考虑过在片段着色器中进行投影,但由于场景中有很多灯光,所以在片段着色器中进行所有这些矩阵乘法的计算成本太高。
【问题讨论】:
标签: glsl depth-buffer perspectivecamera shadow-mapping