After being success in implementing a decent shadow map for my game engine ( with a great help of this community ), I'm very very keen to jump into some advance shadow map techniques like Cascaded Shadow Map(CSM), Parallel-Split Shadow Map(PSSM), Variance Shadow Map(VSM) etc. Cause I want a shadow technique that will be able to cover big area in game very efficiently. After doing a lots of search in Internet, I found CSM most useful. I may be wrong but this technique has really impressed me. And I really want to implement it.
First looked into the Cascaded Shadow Map sample of Microsoft DirectX SDK(June 2010) called CascadedShadowMaps11 to get the basic idea. But what I actually understand is nothing. Uff! This sample is really really complex ( for me ). What actually bother me is the DX11 and XNA stuffs.
So I started doing something simpler in that way -
I render ( only depth ) all the shadow casting object three times into three different render target texture. Every RT texture has its own View and Projection matrix ( Actually a shadow camera ). three times means I just simply render them inside a for loop and I call the following function inside the loop to update the shadow camera for every RT texture -
void SceneManager::UpdateShadowCamera(Camera* cam, Light* light, Camera* texCam, size_t cascadeIndex)
{
// Build View Matrix
D3DXVECTOR3 dir = -light->mSunDirection;
::T3DNormalize(&dir);
D3DXVECTOR3 pos(-3, 30, -57);
//-------------------------------
D3DXVECTOR3 up(0, 1, 0);
// Check it's not coincident with dir
if (abs(DotProduct(&up, &dir)) >= 1.0f)
{
// Use camera up
up = D3DXVECTOR3(0, 0, 1);
}
// cross twice to rederive, only direction is unaltered
D3DXVECTOR3 left = CrossProduct(&dir, &up);
Normalize(&left);
up = CrossProduct(&dir, &left);
Normalize(&up);
// Derive quaternion from axes
Quaternion q;
q.FromAxes(left, up, dir);
q.Normalize();
texCam->matView = MakeViewMatrix(pos, q, NULL);
ViewFrustum* frustum = cam->mFrustum;
D3DXVECTOR3 camPos = cam->GetPosition();
float mSplitPoints[4] = { 1.0f, 20.0f, 80.0f, 300.0f };
// Apply the right clip distance.
float nearSplit = mSplitPoints[cascadeIndex];
float farSplit = mSplitPoints[cascadeIndex + 1];
// Build Projection Matrix
texCam->matProjection = MakeProjectionOrtho(
100, 100, // width and height
1.0f, 100.0f // near and far
);
// Now I'm stuck here!
}
So basically, this function has got four parameters. The cam is the main view camera, the light is carrying only a direction. texCam is the light/shadow camera. cascadeIndex is the for loop current index. Inside this function, I just did some basic calculation what I do for a simple shadow map.
And also, my shadow receiver pixel shader uses following code to determine which shadow map to use now -
float shadow = 1.0f;
if ( pixelDepth < 20 ) {
shadow = tex2Dproj(gDepthMap, SMPos);
splitCol = float4(0.1, 0.0, 0.0, 1.0);
}
else if ( pixelDepth < 80 ) {
shadow = tex2Dproj(gDepthMap2, SMPos2);
splitCol = float4(0.0, 0.1, 0.0, 1.0);
}
else if ( pixelDepth < 300 ) {
shadow = tex2Dproj(gDepthMap3, SMPos3);
splitCol = float4(0.0, 0.0, 0.1, 1.0);
}
pixelDepth is screenSpace Z value passed by vertex shader. Both in main code and pixel shader, split distances are hand-coded for the testing purpose. Those codes are working perfectly. I mean split colors are showing perfectly according to their distance.
That's it! I could not go anymore. I don't know how to calculate proper projection and view matrix for Cascaded shadow map. I think that my view matrix calculation is just fine. Or maybe not?
All the samples in Internet are very tough for me to understand. Some of them only calculates different projection matrix for each texture and the view matrix is same. and some of them recalculates both! Things are getting horrible. So I really need help.
Please help.