Shadowmap 适用于正射投影,但不适用于透视投影

Posted

技术标签:

【中文标题】Shadowmap 适用于正射投影,但不适用于透视投影【英文标题】:Shadowmap works with ortho projection, but not perspective projection 【发布时间】:2020-09-05 18:15:26 【问题描述】:

我已经实现了阴影映射,只要我使用正交投影(例如,从“太阳”获得阴影),它就可以很好地工作

但是,一旦我切换到聚光灯的透视投影,阴影贴图就不再适合我了。即使我使用完全相同的矩阵代码来创建我的(工作)透视相机投影。

透视阴影贴图是否存在一些我不知道的陷阱?

这个投影矩阵(正交)有效:

        const float projectionSize = 50.0f;

        const float left  = -projectionSize;
        const float right =  projectionSize;
        const float bottom= -projectionSize;
        const float top   =  projectionSize;

        const float r_l = right - left;
        const float t_b = top - bottom;
        const float f_n = zFar - zNear;
        const float tx = - (right + left) / (right - left);
        const float ty = - (top + bottom) / (top - bottom);
        const float tz = - (zFar + zNear) / (zFar - zNear);

        float* mout = sl_proj.data;

        mout[0] = 2.0f / r_l;
        mout[1] = 0.0f;
        mout[2] = 0.0f;
        mout[3] = 0.0f;

        mout[4] = 0.0f;
        mout[5] = 2.0f / t_b;
        mout[6] = 0.0f;
        mout[7] = 0.0f;

        mout[8] = 0.0f;
        mout[9] = 0.0f;
        mout[10] = -2.0f / f_n;
        mout[11] = 0.0f;

        mout[12] = tx;
        mout[13] = ty;
        mout[14] = tz;
        mout[15] = 1.0f;

此投影矩阵(透视)可用作相机,但无法使用阴影贴图:

        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;

考虑到它当然是不现实的,正射投影会按预期(见下文)创建光和影。

要创建 lightviewprojection 矩阵,我只需将投影矩阵与光变换的逆矩阵相乘即可​​。

透视相机一切正常,但不适用于透视(聚光灯)。

我的意思是“不工作”:零光出现,因为不知何故,没有一个片段落在光的视野内? (这不是纹理问题,而是转换问题。)

【问题讨论】:

【参考方案1】:

这是 GLSL 代码中的齐次 W 坐标 缺少除法的情况。

不知何故,使用正交投影,不除以 W 就可以了。

使用透视投影,光空间中的坐标需要除以W。

【讨论】:

以上是关于Shadowmap 适用于正射投影,但不适用于透视投影的主要内容,如果未能解决你的问题,请参考以下文章

Model, View(Camera), Perspective

正射投影的问题 | OpenGL

OpenGL中投影矩阵基础知识

UE4移动端动态阴影ShadowMap使用率过低问题

opengl两种投影类型

OpenGL正射投影被破坏