自动调整阴影贴图投影通过将关注点投影到光源的近裁剪平面上

问题描述

我正在使用OpenGL,因此使用C ++进行编码。

任务: 我有一个简单的场景,其中有一个对象,一个点光源和一个照相机。现在,我将灯光移动到物体周围并向上移动。当我到达所需的所有位置时,我旋转对象和/或向上移动照相机。当我获得了灯光和摄像机的所有位置后,便切换了对象。 当然,所有时间照明和阴影都应该正确。但是目前情况并非如此。导致我进入...

问题: 有时背景中有阴影,实际上不应成为阴影 image with the wrong shadow in the back

我希望阴影贴图的大小不足以捕获场景的这一部分。由于场景中有多个更改,因此我想自动定义阴影贴图的大小。

我到目前为止所拥有的: 我在每个对象周围定义了最大边界框,以了解此处的最大尺寸。通过绘制边界框并进行调试,我可以说这是正确计算的。 (我知道我还必须考虑基础表面的范围,但要弄清楚我的算法是否工作良好,我将其保留一秒钟)

要在近裁剪平面上绘制范围,我将它们投影到光源的近裁剪平面上,以获得需要使用的阴影贴图的维数。对于投影,我将平面的底部向上扩展和飞机的正确向量。我用A * (A^T * A)^(-1) * A^T计算的投影矩阵 现在,当我切换视图以便从灯光的角度看场景时,我看到了我的期望:整个图片只是对象。

object from the light perspective

到目前为止一切顺利。但是,当我将灯光向右或向左移动时,图像的一部分会移出视野。

light moved to the right

当我向上移动灯光时,物体被模压了。

light moved up

这是我的代码来调整lightsource_projection:

void CGRenderer::adjustLight()
    {
        glm::mat2x3 A(9.0f);
        A[1] = lightsource_camera.getUp();
        A[0] = lightsource_camera.getRight();

        //projection matrix = A(ATA)^-1 AT.
        glm::mat3 P = A * glm::inverse(glm::transpose(A) * A) * glm::transpose(A);
std::vector<glm::vec3> bbPoints;
        bbPoints.push_back(glm::vec3(object.boundingBoxViewSpace[0][0],object.boundingBoxViewSpace[0][1],object.boundingBoxViewSpace[0][2]));
        bbPoints.push_back(glm::vec3(object.boundingBoxViewSpace[1][0],object.boundingBoxViewSpace[0][2]));
        bbPoints.push_back(glm::vec3(object.boundingBoxViewSpace[0][0],object.boundingBoxViewSpace[1][2]));
        bbPoints.push_back(glm::vec3(object.boundingBoxViewSpace[1][0],object.boundingBoxViewSpace[1][2]));
        bbPoints.push_back(glm::vec3(object.boundingBoxViewSpace[0][0],object.boundingBoxViewSpace[1][1],object.boundingBoxViewSpace[1][2]));

        glm::vec3 tmp;
        float x_min = 0.f;
        float x_max = 0.f;
        float y_min = 0.f;
        float y_max = 0.f;
        for (glm::vec3 v : bbPoints)
        {
            tmp = v * P;

            if (tmp.x < x_min)
                x_min = tmp.x;
            if (tmp.x > x_max)
                x_max = tmp.x;
            if (tmp.y < y_min)
                y_min = tmp.y;
            if (tmp.y > y_max)
                y_max = tmp.y;
        }

        parameter.lightprojection_x_min = x_min;
        parameter.lightprojection_x_max = x_max;
        parameter.lightprojection_y_min = y_min;
        parameter.lightprojection_y_max = y_max;

        lightsource_projection = glm::ortho(parameter.lightprojection_x_min,parameter.lightprojection_x_max,parameter.lightprojection_y_min,parameter.lightprojection_y_max,parameter.lightprojection_z_min,parameter.lightprojection_z_max);
}

这里是我的阴影传递函数,可在其中调节光线并使用新计算的lightsource_projection:

    void CGRenderer::shadowmap_pass()
{
    glBindFramebuffer(GL_FRAMEBUFFER,framebuffers.shadowmap_buffer);
    
    glViewport(0,shadowmap_width,shadowmap_height);

    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    model = glm::scale(glm::mat4_cast(parameter.globalRotation),glm::vec3(parameter.modelScalation));
    model = glm::rotate(glm::mat4(1.f),glm::radians(parameter.modelRotation),glm::vec3(0.f,1.f,0.f)) * model;

    glm::mat4 shadow_view = lightsource_camera.getViewMatrix();

    glm::mat4 shadow_model_view = shadow_view * model;


    adjustLight();

    shader->use();
    glUniformMatrix4fv(locs.modelViewProjection,1,GL_FALSE,glm::value_ptr(lightsource_projection * shadow_model_view));

    glUniformSubroutinesuiv(GL_VERTEX_SHADER,&locs.placementVS);
    glUniformSubroutinesuiv(GL_FRAGMENT_SHADER,&locs.depthmapFS);

    glBindVertexArray(basesurface.vao);
    glDrawArrays(GL_TRIANGLES,basesurface.vertsToDraw);

    glBindVertexArray(object.vao);
    glDrawArrays(GL_TRIANGLES,object.vertsToDraw);
}

问题: 为什么不能正确更新投影?我该如何解决这个问题?我是否需要更改视图矩阵以解决问题?

解决方法

这是我的解决方案:

我将边界顶点转换为光视图空间。然后投影。通过使用标准化的正交投影矩阵,我可以直接获得所需的值。

    void adjustLight(glm::mat4 shadow_model_view)
{
glm::vec4 tmp;
float x_min = 0.f;
float x_max = 0.f;
float y_min = 0.f;
float y_max = 0.f;
for (glm::vec3 v : object.boundingVertices) // before bbPoints
{
    tmp = shadow_model_view * glm::vec4(v,1.f) ;
    tmp = glm::ortho(-1.f,1.f,-1.f,1.f) * tmp;

    if (tmp.x < x_min)
        x_min = tmp.x;
    if (tmp.x > x_max)
        x_max = tmp.x;
    if (tmp.y < y_min)
        y_min = tmp.y;
    if (tmp.y > y_max)
        y_max = tmp.y;
}
        // z_min und z_max are predefined
lightsource_projection = glm::ortho(x_min,x_max,y_min,y_max,z_min,z_max);
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...