Hey guys,
I'm trying to implement CSM in my engine (using this tutorial: http://www.ogldev.org/www/tutorial49/tutorial49.html) but i'm having trouble with the frustums direction (which is the sun).
The problem is that in the first frame the shadows are correctly working but as soon as i rotate the viewers camera, each camera rotates to the opposite side of what it should. For example if i look to the left, each frustum rotates to the right (from the viewers perspective) which causes the depth map to be looking at the wrong spot.
The code that i have to calculate the MVP matrix for each cascaded camera is:
void deferredRenderer::calcOrthoProjections(openGLCamera::Camera lightCamera, openGLCamera::Camera camera)
{
float lambda = 0.5; // Lambda value for split distance calc. (based on GPU gems paralel splits by nvidia)
float n = camera.getNearClip();
float f = camera.getFarClip();
m_cascadeEnd[0] = camera.getNearClip();
glm::mat4 invCameraView = glm::inverse(camera.View);
// Get the light view transform (lookat is always (0,0-1)
glm::mat4 lightView = glm::lookAt(glm::vec3(0), lightCamera.getCameraLookAt(), glm::vec3(0,1,0));
float ar = 1.0f/camera.GetAspectRatio();
float tanHalfHFOV = tanf(glm::radians((camera.GetFOV()) / 2.0f));
float tanHalfVFOV = tanf(glm::radians((camera.GetFOV() * ar) / 2.0f));
// Projection information
openGLCamera::shadowOrthoProjInfo m_shadowOrthoProjInfo;
for (uint i = 0 ; i < nShadowMaps ; i++)
{
// Calculate the split distance (based on GPU gems parallel splits by novidia)
float cuni = n + ((f-n)*((i+1)/(float)nShadowMaps));
float clog = n * std::powf(f/n, (i+1)/(float)nShadowMaps);
float c = lambda*cuni + (1-lambda)*clog;
m_cascadeEnd[i+1] = c;
float xn = m_cascadeEnd[i] * tanHalfHFOV;
float xf = m_cascadeEnd[i + 1] * tanHalfHFOV;
float yn = m_cascadeEnd[i] * tanHalfVFOV;
float yf = m_cascadeEnd[i + 1] * tanHalfVFOV;
// These corners are view space vectors
glm::vec4 frustumCorners[8] =
{
// near face
glm::vec4(xn, yn, m_cascadeEnd[i], 1.0),
glm::vec4(-xn, yn, m_cascadeEnd[i], 1.0),
glm::vec4(xn, -yn, m_cascadeEnd[i], 1.0),
glm::vec4(-xn, -yn, m_cascadeEnd[i], 1.0),
// far face
glm::vec4(xf, yf, m_cascadeEnd[i + 1], 1.0),
glm::vec4(-xf, yf, m_cascadeEnd[i + 1], 1.0),
glm::vec4(xf, -yf, m_cascadeEnd[i + 1], 1.0),
glm::vec4(-xf, -yf, m_cascadeEnd[i + 1], 1.0)
};
glm::vec4 frustumCornersL[8];
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();
// Rotate the camera so its facing from up -> down
glm::mat4 modelMatrix = glm::rotate(glm::mat4(1), 3.1415f/3.0f, glm::vec3(1,0,0));
for (uint j = 0 ; j < 8 ; j++)
{
// Transform the frustum coordinate from view to world space
glm::vec4 vW = invCameraView * frustumCorners[j];
// Transform the frustum coordinate from world to light space
frustumCornersL[j] = lightView * vW;
minX = std::min(minX, frustumCornersL[j].x);
maxX = std::max(maxX, frustumCornersL[j].x);
minY = std::min(minY, frustumCornersL[j].y);
maxY = std::max(maxY, frustumCornersL[j].y);
minZ = std::min(minZ, frustumCornersL[j].z);
maxZ = std::max(maxZ, frustumCornersL[j].z);
}
m_shadowOrthoProjInfo.l = minX;
m_shadowOrthoProjInfo.r = maxX;
m_shadowOrthoProjInfo.b = minY;
m_shadowOrthoProjInfo.t = maxY;
m_shadowOrthoProjInfo.n = minZ;
m_shadowOrthoProjInfo.f = maxZ;
glm::mat4 Projection = glm::ortho(m_shadowOrthoProjInfo.l, m_shadowOrthoProjInfo.r,
m_shadowOrthoProjInfo.b, m_shadowOrthoProjInfo.t,
m_shadowOrthoProjInfo.n, m_shadowOrthoProjInfo.f);
lightProjView[i] = Projection * lightView * modelMatrix;
}
}
Any information that you need i will gladly provide. Thank you in advance.