#include "defines.h" #include "PSSM.h" #include "shader.h" #include "globals.h" #include "intrin.h" void PSSM::Init() { m_iSplitCount = -1; m_fRange = 0.0f; } void PSSM::UpdateSplits(const D3DXVECTOR3 &vLightDir, const D3DXMATRIX &mView, const D3DXMATRIX &mProj) { assert( m_iSplitCount >= 0 && m_iSplitCount <= MaxSplitCount ); assert( m_fRange >= 0.0f ); // Extract cam data D3DXVECTOR3 vCamPos( -(mView._11 * mView._41 + mView._12 * mView._42 + mView._13 * mView._43), -(mView._21 * mView._41 + mView._22 * mView._42 + mView._23 * mView._43), -(mView._31 * mView._41 + mView._32 * mView._42 + mView._33 * mView._43) ); D3DXVECTOR3 vCamRight(mView._11, mView._21, mView._31); D3DXVECTOR3 vCamUp(mView._12, mView._22, mView._32); D3DXVECTOR3 vCamLook(mView._13, mView._23, mView._33); // Extract plane distances float fNearPlane = mProj._43 / -mProj._33; float fFarPlane = mProj._43 / (1.0f - mProj._33); // Extract FOV float fTanHalfFOVX = 1.0f / mProj._11; float fTanHalfFOVY = 1.0f / mProj._22; // Compute maximum shadow split clip plane float fMaxClipPlane = max( fFarPlane, max(2.0f * fTanHalfFOVX * fFarPlane, 2.0f * fTanHalfFOVY * fFarPlane) ); // Adjust range if(fFarPlane - fNearPlane > m_fRange) fFarPlane = fNearPlane + m_fRange; // Compute frustum depth float fFrustumDepth = fFarPlane - fNearPlane; // Complete light vector set D3DXVECTOR3 vLightUp(0.0f, 1.0f, 0.0f), vLightRight; if(abs(D3DXVec3Dot(&vLightUp, &vLightDir)) > 0.95f) vLightUp = D3DXVECTOR3(0.0f, 0.0f, 1.0f); D3DXVec3Cross(&vLightRight, &vLightUp, &vLightDir); D3DXVec3Normalize(&vLightRight, &vLightRight); D3DXVec3Cross(&vLightUp, &vLightDir, &vLightRight); D3DXVec3Normalize(&vLightUp, &vLightUp); // Loop over splits for(int iSplit = 0; iSplit < m_iSplitCount; iSplit++) { // Compute both uniform and logarithmic split distribution float fUniformSplitNear = fNearPlane + fFrustumDepth * ((float)iSplit / m_iSplitCount); float fUniformSplitFar = fNearPlane + fFrustumDepth * ((float)(iSplit + 1) / m_iSplitCount); float fLogSplitNear = fNearPlane * mypow(fFarPlane / fNearPlane, (float)iSplit / m_iSplitCount); float fLogSplitFar = fNearPlane * mypow(fFarPlane / fNearPlane, (float)(iSplit + 1) / m_iSplitCount); // Take average of both distributions float fSplitNear = (fUniformSplitNear + fLogSplitNear) / 2.0f; float fSplitFar = (fUniformSplitFar + fLogSplitFar) / 2.0f; // Center D3DXVECTOR3 vSplitCenter = vCamPos + (fSplitNear + fSplitFar) / 2.0f * vCamLook; // Compute split view matrix D3DXMatrixIdentity(&m_ViewMatrices[iSplit]); memcpy(&m_ViewMatrices[iSplit]._11, &vLightRight, sizeof(float) * 3); memcpy(&m_ViewMatrices[iSplit]._21, &vLightUp, sizeof(float) * 3); memcpy(&m_ViewMatrices[iSplit]._31, &vLightDir, sizeof(float) * 3); D3DXMatrixTranspose(&m_ViewMatrices[iSplit], &m_ViewMatrices[iSplit]); m_ViewMatrices[iSplit]._41 = -D3DXVec3Dot(&vSplitCenter, &vLightRight); m_ViewMatrices[iSplit]._42 = -D3DXVec3Dot(&vSplitCenter, &vLightUp); m_ViewMatrices[iSplit]._43 = -D3DXVec3Dot(&vSplitCenter, &vLightDir); // Update split view m_ViewPos[iSplit] = vSplitCenter; m_ViewDir[iSplit] = vLightDir; D3DXVECTOR3 splitCorners[8]; // Compute all eight frustum split corner points ComputeCornerPoints(splitCorners, fSplitNear, fSplitFar, fTanHalfFOVX, fTanHalfFOVY, vCamPos, vCamRight, vCamUp, vCamLook, 0.1f); float fMinX = FLT_MAX, fMaxX = FLT_MIN; float fMinY = FLT_MAX, fMaxY = FLT_MIN; float fMinZ = FLT_MAX, fMaxZ = FLT_MIN; // Loop over corner points for(int i = 0; i < 8; i++) { // Transform corner to view space D3DXVECTOR4 vViewSpaceCorner; D3DXVec3Transform(&vViewSpaceCorner, &splitCorners[i], &m_ViewMatrices[iSplit]); // Find min and max values if(vViewSpaceCorner.x > fMaxX) fMaxX = vViewSpaceCorner.x; if(vViewSpaceCorner.x < fMinX) fMinX = vViewSpaceCorner.x; if(vViewSpaceCorner.y > fMaxY) fMaxY = vViewSpaceCorner.y; if(vViewSpaceCorner.y < fMinY) fMinY = vViewSpaceCorner.y; if(vViewSpaceCorner.z > fMaxZ) fMaxZ = vViewSpaceCorner.z; if(vViewSpaceCorner.z < fMinZ) fMinZ = vViewSpaceCorner.z; } // Bias fMinX -= 2.0f; fMinY -= 2.0f; fMinZ -= 2.0f; fMaxX += 2.0f; fMaxY += 2.0f; fMaxZ += 2.0f; // Compute split projection matrix D3DXMatrixOrthoOffCenterLH(&m_ProjMatrices[iSplit], fMinX, fMaxX, fMinY, fMaxY, fMinZ - fMaxClipPlane, fMaxZ + fMaxClipPlane); } } void PSSM::ComputeCornerPoints(D3DXVECTOR3 *pCorners, float fNear, float fFar, float fTanHalfFOVX, float fTanHalfFOVY, const D3DXVECTOR3 &vCamPos, const D3DXVECTOR3 &vCamRight, const D3DXVECTOR3 &vCamUp, const D3DXVECTOR3 &vCamLook, float fOverlap) { float fNearHalfWidth = fTanHalfFOVX * fNear; float fNearHalfHeight = fTanHalfFOVY * fNear; float fFarHalfWidth = fTanHalfFOVX * fFar; float fFarHalfHeight = fTanHalfFOVY * fFar; D3DXVECTOR3 vNearCenter = vCamPos + fNear * vCamLook; D3DXVECTOR3 vFarCenter = vCamPos + fFar * vCamLook; // Compute eight frustum split corner points pCorners[0] = vNearCenter + fNearHalfWidth * vCamRight + fNearHalfHeight * vCamUp; pCorners[1] = vNearCenter + fNearHalfWidth * vCamRight - fNearHalfHeight * vCamUp; pCorners[2] = vNearCenter - fNearHalfWidth * vCamRight + fNearHalfHeight * vCamUp; pCorners[3] = vNearCenter - fNearHalfWidth * vCamRight - fNearHalfHeight * vCamUp; pCorners[4] = vFarCenter + fFarHalfWidth * vCamRight + fFarHalfHeight * vCamUp; pCorners[5] = vFarCenter + fFarHalfWidth * vCamRight - fFarHalfHeight * vCamUp; pCorners[6] = vFarCenter - fFarHalfWidth * vCamRight + fFarHalfHeight * vCamUp; pCorners[7] = vFarCenter - fFarHalfWidth * vCamRight - fFarHalfHeight * vCamUp; D3DXVECTOR3 vCenter = (vNearCenter + vFarCenter) / 2.0f; // Apply split overlap scaling for(int i = 0; i < 8; i++) pCorners[i] += (pCorners[i] - vCenter) * fOverlap; }