Cascaded Shadow Maps

Good day !

I faced with problem connected with Shadow Map slices.
I took algorithm from article

Matrix Light::CalculateCropMatrix(Frustum splitFrustum)  
{  
  Matrix lightViewProjMatrix = viewMatrix * projMatrix;  
  // Find boundaries in light's clip space  
  BoundingBox cropBB = CreateAABB(splitFrustum.AABB,  
                                  lightViewProjMatrix);  
  // Use default near-plane value  
  cropBB.min.z = 0.0f;  
  // Create the crop matrix  
  float scaleX, scaleY, scaleZ;  
  float offsetX, offsetY, offsetZ;  
  scaleX = 2.0f / (cropBB.max.x - cropBB.min.x);  
  scaleY = 2.0f / (cropBB.max.y - cropBB.min.y);  
  offsetX = -0.5f * (cropBB.max.x + cropBB.min.x) * scaleX;  
  offsetY = -0.5f * (cropBB.max.y + cropBB.min.y) * scaleY;  
  scaleZ = 1.0f / (cropBB.max.z - cropBB.min.z);  
  offsetZ = -cropBB.min.z * scaleZ;  
  return Matrix( scaleX,     0.0f,     0.0f,  0.0f,  
                   0.0f,   scaleY,     0.0f,  0.0f,  
                   0.0f,     0.0f,   scaleZ,  0.0f,  
                offsetX,  offsetY,  offsetZ,  1.0f);  
}  

algorithm does next things:

  1. calculate frustum points for each split
  2. all 8 pointers multiply on lightViewProjMatrix to translate each point to light clip space
  3. finding AABB
  4. building crop matrix

i used this code in my program. but shadow maps for each slice are wrong (i will upload images with shadow maps soon).
my lightView matrix is lookat matrix with parameters:

scene.lightCamera.buildViewMatf(-600, 1000, -500, 0, 0, 0, 0, 1, 0);

   void buildViewMatf(float eye_x, float eye_y, float eye_z, 
	                  float earth_x, float earth_y, float earth_z,
					  float up_x, float up_y, float up_z)
   {
	   m_currEyePos[0] = eye_x; m_currEyePos[1] = eye_y; m_currEyePos[2] = eye_z;
	   m_earthPos[0] = earth_x; m_earthPos[1] = earth_y; m_earthPos[2] = earth_z;
	   m_up[0] = up_x; m_up[1] = up_y; m_up[2] = up_z;
	   
	   NvBuildLookatMatf(m_view, m_currEyePos, m_earthPos, m_up);
   } 

and i have light ortho projection matrix with parameters:
m_znear = 2.0f, m_zfar = 10000f;

NvBuildOrthoMatf(m_projection, -5000.0, 5000.0,
					-5000.0, 5000.0,
					m_znear, m_zfar); 

finding frustum points:

   void updateFrustrumPoints(float z_near, float z_far)
   {
	   vec3f up(m_up[0], m_up[1], m_up[2]);
	   vec3f camera_position(m_currEyePos[0], m_currEyePos[1], m_currEyePos[2]);
	   vec3f view_direction(m_earthPos[0]-m_currEyePos[0], 
		                    m_earthPos[1]-m_currEyePos[1], 
							m_earthPos[2]-m_currEyePos[2]);
       view_direction = normalize(view_direction);

	   vec3f right = normalize(cross(view_direction, up));
       up = normalize(cross(right, view_direction));

	   float angle = (float) tan(45.0 * M_PI / 360.0);
	   float near_height = z_near * angle;
	   float far_height  = z_far * angle;

	   float near_width  = (1.0f / m_aspectRatio) * near_height;
	   float far_width   = (1.0f / m_aspectRatio) * far_height;

	   vec3f fc = camera_position + (view_direction * z_far); 
       
	   m_frustrumPoints.resize(8, vec3f(0.0, 0.0, 0.0));

	   // far-top-left
	   m_frustrumPoints[0] = fc + up*far_height - right*far_width;

	   // far-top-right
	   m_frustrumPoints[1] = fc + up*far_height + right*far_width;

	   // far-bottom-left
	   m_frustrumPoints[2] = fc - up*far_height - right*far_width;

	   // far-bottom-right
	   m_frustrumPoints[3] = fc - up*far_height + right*far_width;

	   vec3f nc =  camera_position + (view_direction * z_near);

	   // near-top-left
	   m_frustrumPoints[4] = nc + up*near_height - right*near_width;

	   // near-top-right
	   m_frustrumPoints[5] = nc + up*near_height + right*near_width;

	   // near-bottom-left
	   m_frustrumPoints[6] = nc - up*near_height - right*near_width;

	   //near-bottom-right
	   m_frustrumPoints[7] = nc - up*near_height + right*near_width;
   }

calculate crop matrix:


   void buildCropMatrix(vector<vec3f>& _frustumPoints, int number_of_split){
    
       vector<vec3f> frustumPoints(8, vec3f(0.0, 0.0, 0.0));

       for(int i = 0; i < 8; i++) {	      
	       NvTransformPointf((GLfloat*) &frustumPoints[i], m_model_view_projection, (GLfloat*) &_frustumPoints[i]);
	   }

	   /* Find minX, maxX, minY, maxY, minZ, maxZ */
	   float minX = frustumPoints[0].x, maxX = frustumPoints[0].x;
	   float minY = frustumPoints[0].y, maxY = frustumPoints[0].y;
       float minZ = frustumPoints[0].z, maxZ = frustumPoints[0].z;

       for(int i = 1; i < 8; i++){

			if(frustumPoints[i].x < minX) minX = frustumPoints[i].x;
	        if(frustumPoints[i].x > maxX) maxX = frustumPoints[i].x;
	       
	        if(frustumPoints[i].y < minY) minY = frustumPoints[i].y;
	        if(frustumPoints[i].y > maxY) maxY = frustumPoints[i].y;

            if(frustumPoints[i].z < minZ) minZ = frustumPoints[i].z;
            if(frustumPoints[i].z > maxZ) maxZ = frustumPoints[i].z;
       }

       float scaleX = 2.0f / (maxX - minX);
       m_CropMatrix[number_of_split][0][0] = scaleX;
       m_CropMatrix[number_of_split][0][1] = 0.0f;
       m_CropMatrix[number_of_split][0][2] = 0.0f;
       m_CropMatrix[number_of_split][0][3] = 0.0f; 

       float scaleY = 2.0f / (maxY - minY);
	   float scaleZ = 1.0f / (maxZ - minZ);

       m_CropMatrix[number_of_split][1][0] = 0.0f;
       m_CropMatrix[number_of_split][1][1] = scaleY;
       m_CropMatrix[number_of_split][1][2] = 0.0f;
       m_CropMatrix[number_of_split][1][3] = 0.0f; 

       m_CropMatrix[number_of_split][2][0] = 0.0f;
       m_CropMatrix[number_of_split][2][1] = 0.0f;
       m_CropMatrix[number_of_split][2][2] = scaleZ; 
       m_CropMatrix[number_of_split][2][3] = 0.0f; 
       
       m_CropMatrix[number_of_split][3][0]  = -0.5f * (maxX + minX) * scaleX;
       m_CropMatrix[number_of_split][3][1]  = -0.5f * (maxY + minY) * scaleY;
       m_CropMatrix[number_of_split][3][2]  = -minZ * scaleZ; 
       m_CropMatrix[number_of_split][3][3]  = 1.0f; 
   }

Also i found algorithm

with code


Mat4 CreateDirLightVPMatrix(const CameraFrustrum& cameraFrustrum, const Vec3& lightDir)
    {
        const Vec3 lightDirx = glm::normalize(lightDir);
        const Vec3 perpVec1  = glm::normalize(glm::cross(lightDirx, Vec3(0.0f, 0.0f, 1.0f)));
        const Vec3 perpVec2  = glm::normalize(glm::cross(lightDirx, perpVec1));
        Mat4 lightViewMatrix(Vec4(perpVec1, 0.0f), Vec4(perpVec2, 0.0f), Vec4(lightDirx, 0.0f), Vec4(0.0f, 0.0f, 0.0f, 1.0f));

        Vec4 transf = lightViewMatrix * cameraFrustrum[0]; // cameraFrustrum is a std::array<Vec4, 8> and 0-3 is near-points and 4-7 are far points of the frustrum
        float maxZ = cameraFrustrum[0].z, minZ = cameraFrustrum[0].z;
        for (uint32_t i = 1; i < 8; i++)
        {
            transf = lightViewMatrix * cameraFrustrum[i];
            if (cameraFrustrum[i].z > maxZ)
                maxZ = cameraFrustrum[i].z;
            if (cameraFrustrum[i].z < minZ)
                minZ = cameraFrustrum[i].z;
        }

        const Mat4 mvp = glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, maxZ, minZ) * lightViewMatrix;

        float maxX = -1000.0f, minX = 1000.0f;
        float maxY = -1000.0f, minY = 1000.0f;
        for (uint32_t i = 0; i < 8; i++)
        {
            transf = mvp * cameraFrustrum[i];

            if (cameraFrustrum[i].x > maxX)
                maxX = cameraFrustrum[i].x;
            if (cameraFrustrum[i].x < minX)
                minX = cameraFrustrum[i].x;
            if (cameraFrustrum[i].y > maxY)
                maxY = cameraFrustrum[i].y;
            if (cameraFrustrum[i].y < minY)
                minY = cameraFrustrum[i].y;
        }

        float scaleX = 2.0f / (maxX - minX);
        float scaleY = 2.0f / (maxY - minY);
        float offsetX = -0.5f * (maxX + minX) * scaleX;
        float offsetY = -0.5f * (maxY + minY) * scaleY;

        Mat4 cropMatrix(1.0f);
        cropMatrix[0][0] = scaleX;
        cropMatrix[1][1] = scaleY;
        cropMatrix[3][0] = offsetX;
        cropMatrix[3][1] = offsetY;

        return cropMatrix * glm::ortho(-1.0f, 1.0f, -1.0f, 1.0f, maxZ, minZ) * lightViewMatrix;
    }
  1. Does the first method correct ?
  2. And what the difference (mathematical) between those two methods?