Cascaded Shadow Mapping Problem

Started by
-1 comments, last by Andr 7 years, 11 months ago

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.

This topic is closed to new replies.

Advertisement