[英]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.