级联阴影贴图无法按预期工作

Cascaded Shadow Maps don't work as expected

我正在尝试使用 opengl 实现级联阴影贴图,但我遇到了一些问题。

我首先将我的视锥体分成三个分割,每个分割都有一个

1- 附近
2- 远
3-角(世界中这个特定分裂的截锥体的角space)
4-深度图(2D纹理,尺寸为1024 * 1024)

并且对于每个拆分,我开始计算其 角点 如下,并使用世界中的这些 角点 space 我计算frustum center 我将用来计算光视图矩阵。

float width = float(mRenderer->GetGame()->GetWidth()); 
float height = float(mRenderer->GetGame()->GetHeight()); 
mProjMatrix = glm::perspective(glm::radians(90.0f), (float)width / (float)height, mNear, mFar); 
mViewMatrix = mRenderer->GetView();

glm::mat4 viewProj = mProjMatrix * mViewMatrix; 

glm::vec3 frustumCorners[8] =
{
    glm::vec3(-1.0f, 1.0f, -1.0f),
    glm::vec3(1.0f, 1.0f, -1.0f),
    glm::vec3(1.0f, -1.0f, -1.0f),
    glm::vec3(-1.0f, -1.0f, -1.0f),
    glm::vec3(-1.0f, 1.0f, 1.0f),
    glm::vec3(1.0f, 1.0f, 1.0f),
    glm::vec3(1.0f, -1.0f, 1.0f),
    glm::vec3(-1.0f, -1.0f, 1.0f),
};

for (int i = 0; i < 8; ++i) 
{
    glm::vec4 inversePoint = glm::inverse(viewProj) * glm::vec4(frustumCorners[i], 1.0f);
    mCorners[i] = glm::vec3(inversePoint / inversePoint.w); 
}

for (int i = 0; i < 8; ++i) 
{
    mFrustumCenter += mCorners[i]; 
}

mFrustumCenter /= 8.0f;

在我得到这个特定分割的 截锥体中心后 我需要弄清楚我将要使用的 光视图矩阵 渲染场景(在分裂的近处和远处之间),我按如下方式进行。
mRenderer->GetLightDirection() = {0.0f, 20.0f, -1.0f}

glm::vec3 lightDir = glm::normalize(mRenderer->GetLightDirection()); 
glm::vec3 lightPos = mFrustumCenter + lightDir; 

mLightView = glm::lookAt(lightPos, mFrustumCenter , glm::vec3(0.0f, 1.0f, 0.0f));

最后我做的最后一件事是计算 光的正交矩阵 在我将它们转换成light space 加上我上一步计算的light view matrix

for (int i = 0; i < 8; ++i) 
{
    mCorners[i] = glm::vec3(mLightView * glm::vec4(mCorners[i], 1.0f)); 
}


float minX = std::numeric_limits<float>::max(); 
float maxX = std::numeric_limits<float>::min(); 
float minY = std::numeric_limits<float>::max(); 
float maxY = std::numeric_limits<float>::min(); 
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();

for (int i = 0; i < 8; ++i) 
{
    minX = std::min(minX, mCorners[i].x);
    maxX = std::max(maxX, mCorners[i].x);
    minY = std::min(minY, mCorners[i].y);
    maxY = std::max(maxY, mCorners[i].y);
    minZ = std::min(minZ, mCorners[i].z);
    maxZ = std::max(maxZ, mCorners[i].z);
}

mLightProj = glm::ortho(minX, maxX, minY, maxY, minZ, maxZ); 

当我 运行 我的程序时,我的影子可以正常工作

但是当我将相机向后移动直到地板进入第二次分割的范围而不是使用第二个分割阴影时它消失了但是当我开始上下移动相机时阴影再次出现所以我认为问题是在计算光视图矩阵,但我想不通。

这些是我的拆分范围
近->远
0.1 -> 30.0
0.1 -> 50.0
0.1 -> 1000.0

好吧,我发现我没有正确放置灯光所以这个片段

glm::vec3 lightDir = glm::normalize(mRenderer->GetLightDirection()); 
glm::vec3 lightPos = mFrustumCenter + lightDir; 

mLightView = glm::lookAt(lightPos, mFrustumCenter , glm::vec3(0.0f, 1.0f, 0.0f));

应该是

glm::vec3 lightDir = glm::normalize(mRenderer->GetLightDirection()); 
glm::vec3 lightPos = mFrustumCenter + lightDir * (mFar - mNear); 
mLightView = glm::lookAt(lightPos, mFrustumCenter , glm::vec3(0.0f, 1.0f, 0.0f));

i 应该将光的位置向另一个方向移动,其移动量等于当前分割平截头体的远近距离之差。

还有这个片段

float minX = std::numeric_limits<float>::max(); 
float maxX = std::numeric_limits<float>::min(); 
float minY = std::numeric_limits<float>::max(); 
float maxY = std::numeric_limits<float>::min(); 
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();

for (int i = 0; i < 8; ++i) 
{
    minX = std::min(minX, mCorners[i].x);
    maxX = std::max(maxX, mCorners[i].x);
    minY = std::min(minY, mCorners[i].y);
    maxY = std::max(maxY, mCorners[i].y);
    minZ = std::min(minZ, mCorners[i].z);
    maxZ = std::max(maxZ, mCorners[i].z);
}

mLightProj = glm::ortho(minX, maxX, minY, maxY, minZ, maxZ);

应该是

float minX = std::numeric_limits<float>::max(); 
float maxX = std::numeric_limits<float>::min(); 
float minY = std::numeric_limits<float>::max(); 
float maxY = std::numeric_limits<float>::min(); 
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();

for (int i = 0; i < 8; ++i) 
{
    minX = std::min(minX, mCorners[i].x);
    maxX = std::max(maxX, mCorners[i].x);
    minY = std::min(minY, mCorners[i].y);
    maxY = std::max(maxY, mCorners[i].y);
    minZ = std::min(minZ, mCorners[i].z);
    maxZ = std::max(maxZ, mCorners[i].z);
}

mLightProj = glm::ortho(minX, maxX, minY, maxY, near, maxZ - minZ);

光正交投影矩阵的near和far应等于分裂平截头体的near,far应等于最近角点和最远角点之间的距离(z轴)