正如标题所示,我一直试图实施级联阴影贴图,但我似乎无法正确计算分割。我找到了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.有一些边界框,它的底部将高于场景中的最高点等等。我不确定我不理解所以所有将不胜感激!