问题描述
我正在尝试使用opengl实现级联阴影映射,但是遇到了一些问题。
我首先将我的视图视锥体划分为三个分割,每个分割都有一个
1-附近
2远
3个角(在世界空间中这种特定的平截头体的角落)
4-深度图(尺寸为1024 * 1024的2D纹理)
对于每个拆分,我首先按如下方式计算其角,并根据世界空间中的这些角,我计算出视锥中心用于计算光视图矩阵。
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,glm::vec3(-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;
在获得此特定拆分的视锥中心之后,我需要弄清楚将用于渲染场景的 light view matrix (在近远之间)的分裂),我这样做如下。
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,0.0f));
最后,我要做的最后一件事是在将它们转换为 light space 空间后,使用平截头体角来计算正交光矩阵 >使用光视图矩阵,我计算了上一步。
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);
当我运行程序时,我的阴影可以正常工作
但是当我向后移动摄像机直到地板进入第二个分割的范围而不是使用第二个分割阴影时,它消失了,但是当我开始上下移动摄像机时,阴影又出现了,所以我认为问题是在计算光视图矩阵时,但我无法弄清楚。
这些是我的拆分范围
near-> far
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,0.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);
应该是
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,near,maxZ - minZ);
光正交投影矩阵的近点和远点应等于平截锥体的近点,远点应等于最近角和最远角(z轴)之间的距离