Files
bluflame/evoke-64k/ev10/PSSM.cpp
2026-04-18 22:31:51 +02:00

156 lines
5.8 KiB
C++

#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;
}