static void CalculateLisPSM( const CCameraEntity& cam, Light& light ) { CalculateOrthoShadow( cam, light ); const SVector3& lightDir = light.mWorldMat.getAxisZ(); const SVector3& viewDir = cam.mWorldMat.getAxisZ(); double dotProd = lightDir.dot( viewDir ); if( fabs(dotProd) >= 0.999 ) { // degenerates to uniform shadow map return; } // calculate the hull of body B in world space HullFace bodyB; SMatrix4x4 invCamVP; D3DXMatrixInverse( &invCamVP, NULL, &cam.mWorldMat ); invCamVP *= cam.getProjectionMatrix(); D3DXMatrixInverse( &invCamVP, NULL, &invCamVP ); CalculateFocusedLightHull( invCamVP, lightDir, gCasterBounds, bodyB ); int zzz = bodyB.v.size(); int i, j; /* Frustum camFrustum( cam.getProjectionMatrix() ); std::vector<SVector3> bodyB; bodyB.reserve( gSceneCasters.size()*8 + 8 ); for( i = 0; i < 8; ++i ) bodyB.push_back( camFrustum.pntList[i] ); int ncasters = gSceneCasters.size(); for( i = 0; i < ncasters; ++i ) { const CAABox& aabb = gSceneCasters[i].aabb; for( j = 0; j < 8; ++j ) { SVector3 p; p.x = (j&1) ? aabb.getMin().x : aabb.getMax().x; p.y = (j&2) ? aabb.getMin().y : aabb.getMax().y; p.z = (j&4) ? aabb.getMin().z : aabb.getMax().z; bodyB.push_back( p ); } } */ // calculate basis of light space projection SVector3 ly = -lightDir; SVector3 lx = ly.cross( viewDir ).getNormalized(); SVector3 lz = lx.cross( ly ); SMatrix4x4 lightW; lightW.identify(); lightW.getAxisX() = lx; lightW.getAxisY() = ly; lightW.getAxisZ() = lz; SMatrix4x4 lightV; D3DXMatrixInverse( &lightV, NULL, &lightW ); // rotate bound body points from world into light projection space and calculate AABB there D3DXVec3TransformCoordArray( &bodyB.v[0], sizeof(SVector3), &bodyB.v[0], sizeof(SVector3), &lightV, bodyB.v.size() ); CAABox bodyLBounds; bodyLBounds.setNull(); for( i = 0; i < bodyB.v.size(); ++i ) bodyLBounds.extend( bodyB.v[i] ); float zextent = cam.getZFar() - cam.getZNear(); float zLextent = bodyLBounds.getMax().z - bodyLBounds.getMin().z; if( zLextent < zextent ) zextent = zLextent; // calculate free parameter N double sinGamma = sqrt( 1.0-dotProd*dotProd ); const double n = ( cam.getZNear() + sqrt(cam.getZNear() * (cam.getZNear() + zextent)) ) / sinGamma; // origin in this light space: looking at center of bounds, from distance n SVector3 lightSpaceO = bodyLBounds.getCenter(); lightSpaceO.z = bodyLBounds.getMin().z - n; // go through bound points in light space, and compute projected bound float maxx = 0.0f, maxy = 0.0f, maxz = 0.0f; for( i = 0; i < bodyB.v.size(); ++i ) { SVector3 tmp = bodyB.v[i] - lightSpaceO; assert( tmp.z > 0.0f ); maxx = max( maxx, fabsf(tmp.x / tmp.z) ); maxy = max( maxy, fabsf(tmp.y / tmp.z) ); maxz = max( maxz, tmp.z ); } SVector3 lpos; D3DXVec3TransformCoord( &lpos, &lightSpaceO, &lightW ); lightW.getOrigin() = lpos; SMatrix4x4 lightProj; D3DXMatrixPerspectiveLH( &lightProj, 2.0f*maxx*n, 2.0f*maxy*n, n, maxz ); SMatrix4x4 lsPermute, lsOrtho; lsPermute._11 = 1.f; lsPermute._12 = 0.f; lsPermute._13 = 0.f; lsPermute._14 = 0.f; lsPermute._21 = 0.f; lsPermute._22 = 0.f; lsPermute._23 =-1.f; lsPermute._24 = 0.f; lsPermute._31 = 0.f; lsPermute._32 = 1.f; lsPermute._33 = 0.f; lsPermute._34 = 0.f; lsPermute._41 = 0.f; lsPermute._42 = -0.5f; lsPermute._43 = 1.5f; lsPermute._44 = 1.f; D3DXMatrixOrthoLH( &lsOrtho, 2.f, 1.f, 0.5f, 2.5f ); lsPermute *= lsOrtho; lightProj *= lsPermute; G_RENDERCTX->getCamera().setCameraMatrix( lightW ); SMatrix4x4 lightFinal = G_RENDERCTX->getCamera().getViewMatrix() * lightProj; // unit cube clipping /* { // receiver hull std::vector<SVector3> receiverPts; receiverPts.reserve( gSceneReceivers.size() * 8 ); int nreceivers = gSceneReceivers.size(); for( i = 0; i < nreceivers; ++i ) { const CAABox& aabb = gSceneReceivers[i].aabb; for( j = 0; j < 8; ++j ) { SVector3 p; p.x = (j&1) ? aabb.getMin().x : aabb.getMax().x; p.y = (j&2) ? aabb.getMin().y : aabb.getMax().y; p.z = (j&4) ? aabb.getMin().z : aabb.getMax().z; receiverPts.push_back( p ); } } // transform to light post-perspective space D3DXVec3TransformCoordArray( &receiverPts[0], sizeof(SVector3), &receiverPts[0], sizeof(SVector3), &lightFinal, receiverPts.size() ); CAABox recvBounds; recvBounds.setNull(); for( i = 0; i < receiverPts.size(); ++i ) recvBounds.extend( receiverPts[i] ); recvBounds.getMax().x = min( 1.f, recvBounds.getMax().x ); recvBounds.getMin().x = max(-1.f, recvBounds.getMin().x ); recvBounds.getMax().y = min( 1.f, recvBounds.getMax().y ); recvBounds.getMin().y = max(-1.f, recvBounds.getMin().y ); float boxWidth = recvBounds.getMax().x - recvBounds.getMin().x; float boxHeight = recvBounds.getMax().y - recvBounds.getMin().y; if( !FLT_ALMOST_ZERO(boxWidth) && !FLT_ALMOST_ZERO(boxHeight) ) { float boxX = ( recvBounds.getMax().x + recvBounds.getMin().x ) * 0.5f; float boxY = ( recvBounds.getMax().y + recvBounds.getMin().y ) * 0.5f; SMatrix4x4 clipMatrix( 2.f/boxWidth, 0.f, 0.f, 0.f, 0.f, 2.f/boxHeight, 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, -2.f*boxX/boxWidth, -2.f*boxY/boxHeight, 0.f, 1.f ); lightProj *= clipMatrix; } } */ G_RENDERCTX->getCamera().setProjectionMatrix( lightProj ); }