无法计算层叠阴影贴图的边界框拆分

时间:2018-04-08 13:36:12

标签: c++ opengl glm-math

正如标题所示,我一直试图实施级联阴影贴图,但我似乎无法正确计算分割。我找到了this教程,它解释得很好,甚至提供了代码示例,但在计算每个级联的边界框时我一定做错了。如果我对光的正投影lightProj = glm::ortho(-50.f, 50.f, -50.f, 50.f, 0.1f, 120.f);进行硬编码(基本上每个级联跨越整个场景),它就可以工作(显然每个级联的分辨率都很差)。这是代码:

void calcCascadeProjections() {
    glm::vec3 sunPos(0, 50, -50);
    glm::mat4 view = glm::lookAt(cam.Position, cam.Position + cam.Front, cam.Up); 
    glm::mat4 viewInverse = glm::inverse(view);
    glm::mat4 lightView = glm::lookAt(sunPos, glm::vec3(0), glm::vec3(0.0f, 1.0f, 0.0f));

    float ar = (float)SCR_HEIGHT / (float)SCR_WIDTH;
    float tanHalfHFov = tan(glm::radians(45.0f / 2.0f));
    float tanHalfVFov = tan(glm::radians((45.0f * ar) / 2.0f));  

    //tan of half the FOV = x of frustum corner/ z of frustum corner
    //since we know the z of each cascade (where each cascade ends)
    //then x of frustum = tan of half FOV * z of frustum corner
    for (uint8_t i = 0; i < CSM_CASCADES; i++) {
        float xn = cascadeEnds[i] * tanHalfHFov;
        float xf = cascadeEnds[i + 1] * tanHalfHFov;
        float yn = cascadeEnds[i] * tanHalfVFov;
        float yf = cascadeEnds[i + 1] * tanHalfVFov;

        glm::vec4 frustumCorners[8] = {
            glm::vec4(xn, yn, cascadeEnds[i], 1.0),
            glm::vec4(-xn, yn, cascadeEnds[i], 1.0),
            glm::vec4(xn, -yn, cascadeEnds[i], 1.0),
            glm::vec4(-xn, -yn, cascadeEnds[i], 1.0),

            glm::vec4(xf, yf, cascadeEnds[i + 1], 1.0),
            glm::vec4(-xf, yf, cascadeEnds[i + 1], 1.0),
            glm::vec4(xf, -yf, cascadeEnds[i + 1], 1.0),
            glm::vec4(-xf, -yf, cascadeEnds[i + 1], 1.0)        
        };
        glm::vec4 frustumCornersLight[8];
        float minx = FLT_MAX;
        float maxx = FLT_MIN;
        float miny = FLT_MAX;
        float maxy = FLT_MIN;
        float minz = FLT_MAX;
        float maxz = FLT_MIN;

        for (uint8_t j = 0; j < 8; j++) {
            //to get the position in view space multiply view matrix * position vector in world space
            //so multiplying the inverse view matrix to both sides should result in the position vector in world space
            glm::vec4 world = viewInverse * frustumCorners[j];
            frustumCornersLight[j] = lightView * world;

            minx = MIN(minx, frustumCornersLight[j].x);
            maxx = MAX(maxx, frustumCornersLight[j].x);
            miny = MIN(miny, frustumCornersLight[j].y);
            maxy = MAX(maxy, frustumCornersLight[j].y);
            minz = MIN(minz, frustumCornersLight[j].z);
            maxz = MAX(maxz, frustumCornersLight[j].z);
            //turn the light frustum into a bounding box which is then passed to glm::ortho()

        }
        cascadeBoundingBoxes[i]l = minx; //left
        cascadeBoundingBoxes[i]r = maxx; //right
        cascadeBoundingBoxes[i]b = miny; //bottom
        cascadeBoundingBoxes[i]t = maxy; //top
        cascadeBoundingBoxes[i]n = minz; //near
        cascadeBoundingBoxes[i]f = maxz; //far
        printf("Box %d: %f %f %f %f %f %f \n", i, minx, maxx, miny, maxy, minz, maxz);
    }
}

我预先设置的级联结束数组cascadeEnds[0]是近深度(0.1f),cascadeEnds[4]是原始光投影的远深度(120.f)。

计算这些边界框后,对于每个级联,我会使用边界框来设置光的正投影矩阵

            for (int i = 0; i < CSM_CASCADES; i++) {
                bindCSMforWriting(i); //selects the correct depth texture
                lightProj = glm::ortho(cascadeBoundingBoxes[i]l, cascadeBoundingBoxes[i]r, cascadeBoundingBoxes[i]b, cascadeBoundingBoxes[i]t, cascadeBoundingBoxes[i]n, cascadeBoundingBoxes[i]f);
                lightSpaceTransform = lightProj * lightView;

                USE_SHADER(shader->id);
                std::string uniform = "lightSpaceMatrix[" + std::to_string(i) + "]";
                SHADER_SET_MAT4(shader->id, uniform.c_str(), lightSpaceTransform);
                USE_SHADER(depthShader);

                SHADER_SET_MAT4(depthShader, "lightSpaceMat", lightSpaceTransform);
                glClear(GL_DEPTH_BUFFER_BIT);
                glActiveTexture(GL_TEXTURE0 + i);
                glBindTexture(GL_TEXTURE_2D, depthTextures[i]);
                if (graphics != 0) {
                    //if shadows are enabled
                    scene->renderScene(depthShader, true, cam, deltaTime, graphics);
                }
            }

计算边界框时,我会得到非常奇怪的值。我注意到每个级联的深度总是为0.有一些边界框,它的底部将高于场景中的最高点等等。我不确定我不理解所以所有将不胜感激!

0 个答案:

没有答案