385 lines
12 KiB
C++
385 lines
12 KiB
C++
#include "StdAfx.h"
|
||
#include "EtTrapezoidShadowMap.h"
|
||
#include "EtConvexVolume.h"
|
||
#include "EtCamera.h"
|
||
#include "EtEngine.h"
|
||
|
||
#ifdef _DEBUG
|
||
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
|
||
#endif
|
||
|
||
CEtTrapezoidShadowMap::CEtTrapezoidShadowMap()
|
||
{
|
||
m_fShadowRange = 1000.0f;
|
||
}
|
||
|
||
CEtTrapezoidShadowMap::~CEtTrapezoidShadowMap()
|
||
{
|
||
}
|
||
|
||
int CEtTrapezoidShadowMap::FindContactVertex( D3DXVECTOR3 *pPoints, D3DXVECTOR2 vDir, bool bMax)
|
||
{
|
||
float fMax = bMax ? -FLT_MAX : FLT_MAX;
|
||
int nIndex = -1;
|
||
for( int i = 0; i < 8; i++) {
|
||
float fD = pPoints[i].x * vDir.x + pPoints[i].y * vDir.y;
|
||
if( bMax ? fD > fMax : fD < fMax ) {
|
||
fMax = fD;
|
||
nIndex = i;
|
||
}
|
||
}
|
||
return nIndex;
|
||
}
|
||
|
||
void CEtTrapezoidShadowMap::CalcShadowMat()
|
||
{
|
||
if( !CEtCamera::GetActiveCamera() ) {
|
||
return;
|
||
}
|
||
|
||
int i;
|
||
EtMatrix *pInvViewMat;
|
||
SLightInfo *pLightInfo;
|
||
EtVector3 Eye, At, CamDir;
|
||
|
||
pLightInfo = CEtLight::GetShadowCastDirLightInfo();
|
||
if( pLightInfo == NULL ) return;
|
||
|
||
pInvViewMat = CEtCamera::GetActiveCamera()->GetInvViewMat();
|
||
if(pInvViewMat->_41 != pInvViewMat->_41 ) {
|
||
return;
|
||
}
|
||
CamDir = *( EtVector3 * )&pInvViewMat->_31;
|
||
CamDir.y = 0.0f;
|
||
EtVec3Normalize( &CamDir, &CamDir );
|
||
At = *( EtVector3 * )&pInvViewMat->_41 + CamDir * m_fDistanceLightAt;
|
||
|
||
EtVector3 vLightDir = pLightInfo->Direction;
|
||
|
||
float fDot2 = fabsf(EtVec3Dot( &vLightDir, ( EtVector3 * )&pInvViewMat->_31));
|
||
if( fDot2 > 0.9999f) {
|
||
vLightDir.x += 0.01f;
|
||
EtVec3Normalize(&vLightDir, &vLightDir);
|
||
}
|
||
|
||
Eye = At - vLightDir * 10000.0f;
|
||
|
||
if( fabsf(EtVec3Dot( &(Eye-At), &EtVector3(0,1,0))) > 0.999f) {
|
||
EtMatrixLookAtLH( &m_LightViewMat, &Eye, &At, &EtVector3( 1.0f, 0.0f, 0.0f ) );
|
||
}
|
||
else {
|
||
EtMatrixLookAtLH( &m_LightViewMat, &Eye, &At, &EtVector3( 0.0f, 1.0f, 0.0f ) );
|
||
}
|
||
|
||
|
||
EtMatrixOrthoLH( &m_LightProjMat, m_fShadowRange * 2.0f, m_fShadowRange * 2.0f, 10.0f, 100000.0f );
|
||
|
||
static float fCamNear = 150.f;
|
||
float fCamFar = m_fShadowRange;
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
EtCameraHandle hCamera = CEtCamera::GetActiveCamera();
|
||
EtMatrix matInvProj, matInvView, matProj;
|
||
EtMatrixPerspectiveFovLH( &matProj, hCamera->GetFOV(), hCamera->GetAspectRatio(), fCamNear, fCamFar );
|
||
EtMatrixInverse(&matInvProj, 0, &matProj);
|
||
matInvView = *hCamera->GetInvViewMat();
|
||
*(D3DXVECTOR3*)&matInvView._41 -= (*(D3DXVECTOR3*)&matInvView._31) * fCamNear;
|
||
|
||
D3DXVECTOR3 vNear[4] = { D3DXVECTOR3(-1,1,0), D3DXVECTOR3(-1, -1, 0), D3DXVECTOR3( 1, 1, 0), D3DXVECTOR3( 1, -1, 0) };
|
||
D3DXVECTOR3 vFar[4] = { D3DXVECTOR3(-1,1,1), D3DXVECTOR3(-1, -1, 1), D3DXVECTOR3( 1, 1, 1), D3DXVECTOR3( 1, -1, 1) };
|
||
|
||
for( i = 0; i < 4; i++) {
|
||
D3DXVec3TransformCoord(&vNear[i], &vNear[i], &matInvProj);
|
||
D3DXVec3TransformCoord(&vFar[i], &vFar[i], &matInvProj);
|
||
D3DXVec3TransformCoord(&vNear[i], &vNear[i], &matInvView);
|
||
D3DXVec3TransformCoord(&vFar[i], &vFar[i], &matInvView);
|
||
D3DXVec3TransformCoord(&vNear[i], &vNear[i], &m_LightViewMat);
|
||
D3DXVec3TransformCoord(&vFar[i], &vFar[i], &m_LightViewMat);
|
||
}
|
||
|
||
D3DXVECTOR3 vPoint[8];
|
||
for( i = 0; i < 4; i++) {
|
||
D3DXVec3TransformCoord(&vNear[i], &vNear[i], &m_LightProjMat);
|
||
D3DXVec3TransformCoord(&vFar[i], &vFar[i], &m_LightProjMat);
|
||
vPoint[i] = vNear[i];
|
||
vPoint[i+4] = vFar[i];
|
||
}
|
||
|
||
D3DXVECTOR3 vNearCenter = (vNear[0]+vNear[1]+vNear[2]+vNear[3])*0.25f;
|
||
D3DXVECTOR3 vFarCenter = (vFar[0]+vFar[1]+vFar[2]+vFar[3])*0.25f;
|
||
|
||
D3DXVECTOR3 vCenterDir = vNearCenter - vFarCenter;
|
||
vCenterDir.z = 0.f;
|
||
D3DXVec3Normalize(&vCenterDir, &vCenterDir);
|
||
|
||
D3DXVECTOR3 vCenterCross( -vCenterDir.y, vCenterDir.x, 0 );
|
||
|
||
// Frustum <20><> <20><><EFBFBD>δ<EFBFBD> <20><><EFBFBD>ٸ<EFBFBD><D9B8><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||
int nIndex;
|
||
D3DXVECTOR3 vLine[4];
|
||
D3DXVECTOR3 vNearContact, vFarContact;
|
||
|
||
nIndex = FindContactVertex( vPoint, D3DXVECTOR2(vCenterDir.x, vCenterDir.y), true);
|
||
vLine[0].x = -vCenterCross.y;
|
||
vLine[0].y = vCenterCross.x;
|
||
vLine[0].z = -(vLine[0].x * vPoint[nIndex].x + vLine[0].y * vPoint[nIndex].y);
|
||
vNearContact = vPoint[nIndex];
|
||
int nNearContactIndex = nIndex-4;
|
||
|
||
nIndex = FindContactVertex( vPoint, D3DXVECTOR2(vCenterDir.x, vCenterDir.y), false);
|
||
vLine[1].x = -vCenterCross.y;
|
||
vLine[1].y = vCenterCross.x;
|
||
vLine[1].z = -(vLine[1].x * vPoint[nIndex].x + vLine[1].y * vPoint[nIndex].y);
|
||
vFarContact = vPoint[nIndex];
|
||
|
||
float fDot = fabsf(EtVec3Dot( (EtVector3*)&hCamera->GetInvViewMat()->_31, (EtVector3*)&pLightInfo->Direction ));
|
||
|
||
float add_slope = 0.0f;
|
||
float z, d, l, n;
|
||
z = -0.6f;
|
||
D3DXVECTOR3 pl = 0.5f*(vNearCenter+ vFarCenter);
|
||
d = fabsf(D3DXVec3Dot(&(vNearContact - pl), &vCenterDir));
|
||
l = fabsf(D3DXVec3Dot(&(vNearContact - vFarContact), &vCenterDir));
|
||
n = (l*d*(1+z))/(l-2*d-l*z);
|
||
vNearContact = pl + (n+d)*vCenterDir;
|
||
|
||
float max_slope = -FLT_MAX;
|
||
float min_slope = FLT_MAX;
|
||
|
||
for( i = 0; i < 4; i++) {
|
||
if( i == nNearContactIndex ) {
|
||
continue;
|
||
}
|
||
D3DXVECTOR3 v = vNearContact - vFar[i];
|
||
v.z = 0.f;
|
||
D3DXVec3Normalize(&v, &v);
|
||
float fAngle = EtAcos( D3DXVec3Dot(&vCenterDir, &v) );
|
||
assert(fAngle == fAngle);
|
||
D3DXVECTOR3 vCross;
|
||
D3DXVec3Cross(&vCross, &vCenterDir, &v);
|
||
if( vCross.z < 0.f ) fAngle = -fAngle;
|
||
max_slope = __max( max_slope, fAngle );
|
||
min_slope = __min( min_slope, fAngle);
|
||
}
|
||
|
||
float fMaxSlope = D3DX_PI*0.3f;
|
||
if( nNearContactIndex >= 0 || fDot > 0.6f ) {
|
||
fMaxSlope = D3DX_PI*0.1f;
|
||
}
|
||
|
||
max_slope = __min(fMaxSlope, max_slope) + add_slope;
|
||
min_slope = __min(fMaxSlope, fabsf(min_slope)) + add_slope;
|
||
|
||
D3DXVECTOR3 vRightDir, vLeftDir;
|
||
D3DXMATRIX matRot;
|
||
D3DXMatrixRotationZ(&matRot, max_slope );
|
||
D3DXVec3TransformNormal(&vRightDir, &vCenterDir, &matRot);
|
||
D3DXMatrixRotationZ(&matRot, -min_slope );
|
||
D3DXVec3TransformNormal(&vLeftDir, &vCenterDir, &matRot);
|
||
|
||
D3DXVECTOR2 vRightCross(-vRightDir.y, vRightDir.x);
|
||
nIndex = FindContactVertex( vPoint, vRightCross, false);
|
||
|
||
vLine[2].x = -vRightDir.y;
|
||
vLine[2].y = vRightDir.x;
|
||
vLine[2].z = -(vLine[2].x * vPoint[nIndex].x + vLine[2].y * vPoint[nIndex].y);
|
||
|
||
D3DXVECTOR2 vLeftCross(-vLeftDir.y, vLeftDir.x);
|
||
nIndex = FindContactVertex( vPoint, vLeftCross, true);
|
||
|
||
vLine[3].x = -vLeftDir.y;
|
||
vLine[3].y = vLeftDir.x;
|
||
vLine[3].z = -(vLine[3].x * vPoint[nIndex].x + vLine[3].y * vPoint[nIndex].y);
|
||
|
||
D3DXVECTOR3 t[5];
|
||
int i0[5] = {1,1,0,0, 2};
|
||
int i1[5] = {3,2,2,3, 3};
|
||
|
||
for( i = 0; i < 5; i++) {
|
||
t[i].y = (vLine[i0[i]].x*vLine[i1[i]].z - vLine[i0[i]].z*vLine[i1[i]].x) / (vLine[i0[i]].y*vLine[i1[i]].x-vLine[i0[i]].x*vLine[i1[i]].y);
|
||
t[i].x = (vLine[i0[i]].y*vLine[i1[i]].z - vLine[i0[i]].z*vLine[i1[i]].y) / (vLine[i0[i]].x*vLine[i1[i]].y-vLine[i0[i]].y*vLine[i1[i]].x);
|
||
t[i].z = 0.f;
|
||
}
|
||
///////////////////////////////////////////////////////////////
|
||
EtMatrix matTSM;
|
||
EtMatrixIdentity(&matTSM);
|
||
|
||
D3DXMATRIX T_1;
|
||
D3DXVECTOR2 vCenterOrig = (t[2] + t[3] ) * 0.5f;
|
||
D3DXMatrixTranslation(&T_1, -vCenterOrig.x, -vCenterOrig.y, 0.f);
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &T_1);
|
||
//////////////////////////////////////////////////////////////////////////
|
||
D3DXMATRIX R;
|
||
D3DXVECTOR3 u,v;
|
||
u = (t[2] - t[3]) / D3DXVec3Length(&(t[2] - t[3]));
|
||
assert(u.x == u.x);
|
||
D3DXMatrixIdentity(&R);
|
||
R._11 = u.x;
|
||
R._12 = u.y;
|
||
R._21 = u.y;
|
||
R._22 = -u.x;
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &R);
|
||
|
||
D3DXMATRIX T_2;
|
||
D3DXVec3TransformCoord(&u, &t[4], &matTSM);
|
||
D3DXMatrixTranslation(&T_2, -u.x, -u.y, 0.f);
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &T_2);
|
||
|
||
D3DXVec3TransformCoord(&u, &((t[2]+t[3])*0.5f), &matTSM);
|
||
assert(u.y != 0);
|
||
D3DXMATRIX H(1.f, 0.f, 0.f, 0.f,
|
||
-u.x/u.y, 1.f, 0.f, 0.f,
|
||
0.f, 0.f, 1.f, 0.f,
|
||
0.f, 0.f, 0.f, 1.f );
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &H);
|
||
|
||
D3DXVec3TransformCoord(&u, &t[2], &matTSM);
|
||
assert(u.x != 0 && u.y != 0);
|
||
D3DXMATRIX S_1(1/u.x, 0.f, 0.f, 0.f,
|
||
0.f, 1/u.y, 0.f, 0.f,
|
||
0.f, 0.f, 1.f, 0.f,
|
||
0.f, 0.f, 0.f, 1.f );
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &S_1);
|
||
assert(matTSM._11 == matTSM._11);
|
||
|
||
D3DXMATRIX N;
|
||
D3DXMatrixIdentity(&N);
|
||
N._24 = 1.f;
|
||
N._44 = 0.f;
|
||
N._42 = -1.0f;
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &N);
|
||
|
||
D3DXVec3TransformCoord(&u, &t[0], &matTSM);
|
||
float t3val = u.y;
|
||
D3DXVec3TransformCoord(&u, &t[2], &matTSM);
|
||
t3val += u.y;
|
||
D3DXMATRIX T3( 1.f, 0.f, 0.f, 0.f,
|
||
0.f, 1.f, 0.f, 0.f,
|
||
0.f, 0.f, 1.f, 0.f,
|
||
0.f, -(t3val)*0.5f, 0.f, 1.f );
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &T3);
|
||
|
||
D3DXVec3TransformCoord(&u, &t[0], &matTSM);
|
||
assert(u.y != 0);
|
||
D3DXMATRIX S2( 1.f, 0.f, 0.f, 0.f,
|
||
0.f, -1.f/u.y, 0.f, 0.f,
|
||
0.f, 0.f, 1.f, 0.f,
|
||
0.f, 0.f, 0.f, 1.f );
|
||
D3DXMatrixMultiply(&matTSM, &matTSM, &S2);
|
||
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &matTSM);
|
||
|
||
// Unit Cube Clipping
|
||
int nCount;
|
||
CEtConvexVolume Frustum;
|
||
EtMatrix ProjMat;
|
||
EtMatrixPerspectiveFovLH( &ProjMat, hCamera->GetFOV(), hCamera->GetAspectRatio(), hCamera->GetCameraNear(), m_fShadowRange*2 );
|
||
EtMatrixMultiply( &ProjMat, hCamera->GetViewMat(), &ProjMat );
|
||
Frustum.Initialize( ProjMat );
|
||
{
|
||
ScopeLock<CSyncLock> Lock( CEtObject::s_SmartPtrLock );
|
||
nCount = CEtObject::GetItemCount();
|
||
m_points.clear();
|
||
for( i = 0; i < nCount; i++ )
|
||
{
|
||
EtObjectHandle hHandle;
|
||
hHandle = CEtObject::GetItem( i );
|
||
if( ( !hHandle ) || ( !hHandle->GetSkin() ) || ( !hHandle->GetSkin()->GetMeshHandle() ) )
|
||
{
|
||
continue;
|
||
}
|
||
CEtObject *pObject = hHandle.GetPointer();
|
||
#ifdef PRE_CRASH_CHECK_BACKUP
|
||
static EtSkinHandle hBackupSkin;
|
||
static char szBAckupSkinFileName[ 256 ];
|
||
hBackupSkin = pObject->GetSkin();
|
||
strcpy( szBAckupSkinFileName, hBackupSkin->GetFileName() );
|
||
#endif // #ifdef PRE_CRASH_CHECK_BACKUP
|
||
if( pObject && ( pObject->GetFrustumMask() & g_nCurFrustumMask ) && ( pObject->IsShadowCast() ) && pObject->GetSkin()->GetMeshHandle()->GetSubMeshCount() > 0 )
|
||
{
|
||
EtVector3 Origin, Extent;
|
||
hHandle->GetExtent( Origin, Extent );
|
||
if( !hHandle->IsEnableCull() || Frustum.TesToBox( Origin, Extent ) )
|
||
{
|
||
SOBB obb;
|
||
hHandle->GetBoundingBox(obb);
|
||
obb.CalcVertices();
|
||
|
||
if( fabsf(obb.Center.x) > 1000000.0f || fabsf(obb.Center.y) > 1000000.0f || fabsf(obb.Center.z) > 1000000.0f ) {
|
||
continue;
|
||
}
|
||
|
||
for( int j = 0; j < 8; j++) {
|
||
m_points.push_back( obb.Vertices[j] );
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if( m_points.empty() ) {
|
||
D3DXMatrixTranslation(&m_LightProjMat, 0.0f, 0.0f, 0.5f );
|
||
m_LightProjMat._11 = 0.f;
|
||
m_LightProjMat._22 = 0.f;
|
||
m_LightProjMat._33 = 0.f;
|
||
return;
|
||
}
|
||
|
||
EtMatrix matTrans;
|
||
EtMatrixMultiply(&matTrans, &m_LightViewMat, &m_LightProjMat);
|
||
|
||
SAABox aabb;
|
||
aabb.Reset();
|
||
nCount = (int)m_points.size();
|
||
for( i = 0; i < nCount; i++) {
|
||
EtVector3 point;
|
||
EtVec3TransformCoord(&point, &m_points[i], &matTrans);
|
||
aabb.AddPoint( point );
|
||
}
|
||
|
||
EtVector3 vExtent = aabb.GetExtent();
|
||
float fLength = EtVec3Length( &vExtent );
|
||
vExtent /= fLength;
|
||
|
||
const float fMinLength = 1.0f;
|
||
|
||
if( fLength < fMinLength ) {
|
||
float fAddLength = (fMinLength - fLength)*0.5f;
|
||
aabb.Min -= vExtent * fAddLength;
|
||
aabb.Max += vExtent * fAddLength;
|
||
}
|
||
|
||
if( aabb.Max.x - aabb.Min.x > 2.f ) {
|
||
aabb.Max.x = 1.f;
|
||
aabb.Min.x = -1.f;
|
||
}
|
||
if( aabb.Max.y - aabb.Min.y > 2.f ) {
|
||
aabb.Max.y = 1.f;
|
||
aabb.Min.y = -1.f;
|
||
}
|
||
|
||
EtVector3 vExt = aabb.GetExtent();
|
||
aabb.Min.x -= vExt.x*0.1f;
|
||
aabb.Max.x += vExt.x*0.1f;
|
||
aabb.Min.y -= vExt.y*0.1f;
|
||
aabb.Max.y += vExt.y*0.1f;
|
||
aabb.Min.z -= vExt.z*0.1f;
|
||
aabb.Max.z += vExt.z*0.1f;
|
||
|
||
EtMatrix matFit;
|
||
D3DXMatrixOrthoOffCenterLH( &matFit, aabb.Min.x, aabb.Max.x, aabb.Min.y, aabb.Max.y, aabb.Min.z, aabb.Max.z);
|
||
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &matFit);
|
||
|
||
// for depth matrix
|
||
aabb.Reset();
|
||
nCount = (int)m_points.size();
|
||
for( i = 0; i < nCount; i++) {
|
||
EtVector3 point;
|
||
EtVec3TransformCoord(&point, &m_points[i], &m_LightViewMat );
|
||
aabb.AddPoint( point );
|
||
}
|
||
vExt = aabb.GetExtent();
|
||
aabb.Min.z -= vExt.z*0.5f;
|
||
|
||
D3DXMatrixOrthoOffCenterLH( &m_LightProjDepthMat, aabb.Min.x, aabb.Max.x, aabb.Min.y, aabb.Max.y,
|
||
aabb.Min.z, aabb.Min.z + hCamera->GetCameraFar() * 2.0f );
|
||
}
|