DragonNest/Common/EternityEngine/EtLiSPShadowMap.cpp

545 lines
14 KiB
C++
Raw Permalink Normal View History

#include "StdAfx.h"
#include "EtLiSPShadowMap.h"
#include "EtCollisionFunc.h"
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
CEtLiSPShadowMap::CEtLiSPShadowMap(void)
{
m_fShadowRange = 2000.0f;
}
CEtLiSPShadowMap::~CEtLiSPShadowMap(void)
{
Clear();
}
void CEtLiSPShadowMap::Clear()
{
SAFE_RELEASE_SPTR( m_hShadowMap );
SAFE_RELEASE_SPTR( m_hShadowMapDepth );
}
void CEtLiSPShadowMap::Initialize( ShadowQuality Quality )
{
switch( Quality )
{
case SQ_HIGH:
m_nShadowMapSize = 2048;
break;
case SQ_NORMAL:
m_nShadowMapSize = 1024;
break;
case SQ_NONE:
m_nShadowMapSize = 512;
break;
default:
m_nShadowMapSize = 2048;
break;
}
if( ( !m_hShadowMap ) || ( m_hShadowMap->Width() != m_nShadowMapSize ) )
{
SAFE_RELEASE_SPTR( m_hShadowMap );
SAFE_RELEASE_SPTR( m_hShadowMapDepth );
m_hShadowMap = CEtTexture::CreateRenderTargetTexture( m_nShadowMapSize, m_nShadowMapSize, FMT_R32F );
m_hShadowMap->SetFileName( "EtLiSPShadowMap" );
m_hShadowMapDepth = CEtDepth::CreateDepthStencil( m_nShadowMapSize, m_nShadowMapSize );
m_hShadowMapDepth->SetFileName( "EtLiSPShadowMapDepth" );
}
}
void CEtLiSPShadowMap::CalcFrustumPoly( std::vector< SPolygon > &vecPolygon )
{
unsigned i;
EtMatrix InvViewProjMat;
SAABox Box( &EtVector3( -1.0f, -1.0f, -1.0f ), &EtVector3( 1.0f, 1.0f, 1.0f ) );
DNVector(EtVector3) vecVertex;
Box.GetVertices( vecVertex );
EtMatrixInverse( &InvViewProjMat, NULL, CEtCamera::GetActiveCamera()->GetViewProjMatForCull() );
for( i = 0; i < vecVertex.size(); i++ )
{
EtVec3TransformCoord( &vecVertex[ i ], &vecVertex[ i ], &InvViewProjMat );
}
vecPolygon.resize( 6 );
for( i = 0; i < 6; i++ )
{
vecPolygon[ i ].Polygon.resize( 4 );
}
//near poly ccw
for( i = 0; i < 4; i++ )
{
vecPolygon[ 0 ].Polygon[i] = vecVertex[ i ];
}
//far poly ccw
for( i = 4; i < 8; i++ )
{
vecPolygon[ 1 ].Polygon[ i - 4 ] = vecVertex[ 11 - i ];
}
//left poly ccw
vecPolygon[ 2 ].Polygon[ 0 ] = vecVertex[ 0 ];
vecPolygon[ 2 ].Polygon[ 1 ] = vecVertex[ 3 ];
vecPolygon[ 2 ].Polygon[ 2 ] = vecVertex[ 7 ];
vecPolygon[ 2 ].Polygon[ 3 ] = vecVertex[ 4 ];
//right poly ccw
vecPolygon[ 3 ].Polygon[ 0 ] = vecVertex[ 1 ];
vecPolygon[ 3 ].Polygon[ 1 ] = vecVertex[ 5 ];
vecPolygon[ 3 ].Polygon[ 2 ] = vecVertex[ 6 ];
vecPolygon[ 3 ].Polygon[ 3 ] = vecVertex[ 2 ];
//bottom poly ccw
vecPolygon[ 4 ].Polygon[ 0 ] = vecVertex[ 4 ];
vecPolygon[ 4 ].Polygon[ 1 ] = vecVertex[ 5 ];
vecPolygon[ 4 ].Polygon[ 2 ] = vecVertex[ 1 ];
vecPolygon[ 4 ].Polygon[ 3 ] = vecVertex[ 0 ];
//top poly ccw
vecPolygon[ 5 ].Polygon[ 0 ] = vecVertex[ 6 ];
vecPolygon[ 5 ].Polygon[ 1 ] = vecVertex[ 7 ];
vecPolygon[ 5 ].Polygon[ 2 ] = vecVertex[ 3 ];
vecPolygon[ 5 ].Polygon[ 3 ] = vecVertex[ 2 ];
}
void CEtLiSPShadowMap::ClipPolygonByPlane( std::vector< EtVector3 > &Polygon, EtVector4 &Plane,
std::vector< EtVector3 > &PolyOut, std::vector< EtVector3 > &PolyIntersect )
{
if( Polygon.size() < 3 )
{
return;
}
unsigned i;
std::vector< bool > vecOutside;
vecOutside.resize( Polygon.size() );
for( i = 0; i < Polygon.size(); i++ )
{
vecOutside[ i ] = IsBehindPoint( Plane, Polygon[ i ] );
}
for( i = 0; i < Polygon.size(); i++ )
{
unsigned nNext;
EtVector3 Intersect;
nNext = ( i + 1 ) % Polygon.size();
if( ( vecOutside[ i ] ) && ( vecOutside[ nNext ] ) )
{
continue;
}
if( vecOutside[ i ] )
{
if( TestEdgeToPlane( Polygon[ i ], Polygon[ nNext ], Plane, Intersect ) )
{
PolyOut.push_back( Intersect );
PolyIntersect.push_back( Intersect );
}
PolyOut.push_back( Polygon[ nNext ] );
continue;
}
if( vecOutside[ nNext ] )
{
if( TestEdgeToPlane( Polygon[ i ], Polygon[ nNext ], Plane, Intersect ) )
{
PolyOut.push_back( Intersect );
PolyIntersect.push_back( Intersect );
}
continue;
}
PolyOut.push_back( Polygon[ nNext ] );
}
}
void CEtLiSPShadowMap::ClosePolygon( std::vector< EtVector3 > &PolyOut, std::vector< SPolygon > &IntersectEdges, EtVector4 &Plane )
{
std::vector< SPolygon >::iterator iter;
iter = IntersectEdges.begin();
while( iter != IntersectEdges.end() )
{
if( ( *iter ).Polygon.size() != 2 )
{
iter = IntersectEdges.erase( iter );
}
else
{
iter++;
}
}
if( IntersectEdges.size() < 3 )
{
return;
}
PolyOut.push_back( IntersectEdges.back().Polygon[ 0 ] );
PolyOut.push_back( IntersectEdges.back().Polygon[ 1 ] );
IntersectEdges.pop_back();
while( IntersectEdges.size() > 0 )
{
unsigned i, nLastPointIndex, nFindIndex;
nFindIndex = -1;
nLastPointIndex = ( unsigned )PolyOut.size() - 1;
for( i = 0; i < IntersectEdges.size(); i++ )
{
if( IsNearPoint( IntersectEdges[ i ].Polygon[ 0 ], PolyOut[ nLastPointIndex ] ) )
{
PolyOut.push_back( IntersectEdges[ i ].Polygon[ 1 ] );
nFindIndex = i;
break;
}
if( IsNearPoint( IntersectEdges[ i ].Polygon[ 1 ], PolyOut[ nLastPointIndex ] ) )
{
PolyOut.push_back( IntersectEdges[ i ].Polygon[ 0 ] );
nFindIndex = i;
break;
}
}
if( nFindIndex != -1 )
{
IntersectEdges.erase( IntersectEdges.begin() + nFindIndex );
}
else
{
PolyOut.clear();
return;
}
}
PolyOut.pop_back();
EtVector3 PolyNormal;
EtVec3Cross( &PolyNormal, &( PolyOut[ 1 ] - PolyOut[ 0 ] ), &( PolyOut[ 2 ] - PolyOut[ 1 ] ) );
if( EtVec3Dot( &PolyNormal, ( EtVector3 * )&Plane ) <= 0 )
{
std::reverse( PolyOut.begin(), PolyOut.end() );
}
}
void CEtLiSPShadowMap::ClipFrustumByPlane( std::vector< SPolygon > &vecPolygon, EtVector4 &Plane, std::vector< SPolygon > &vecOutput )
{
if( vecPolygon.size() <= 0 )
{
return;
}
unsigned i, nSize;
std::vector< SPolygon > vecIntersectEdge;
std::vector< SPolygon > vecInputPoly( vecPolygon );
vecOutput.clear();
nSize = 0;
for( i = 0; i < vecInputPoly.size(); i++ )
{
vecOutput.resize( nSize + 1 );
vecIntersectEdge.resize( nSize + 1 );
ClipPolygonByPlane( vecInputPoly[ i ].Polygon, Plane, vecOutput[ nSize ].Polygon, vecIntersectEdge[ nSize ].Polygon );
if( vecOutput[ nSize ].Polygon.size() != 0 )
{
nSize++;
}
}
if( vecOutput.back().Polygon.size() == 0 )
{
vecOutput.pop_back();
}
if( vecIntersectEdge.size() > 0 )
{
vecOutput.resize( vecOutput.size() + 1 );
ClosePolygon( vecOutput.back().Polygon, vecIntersectEdge, Plane );
if( vecOutput.back().Polygon.size() == 0 )
{
vecOutput.pop_back();
}
}
}
void CEtLiSPShadowMap::ClipFrustumBySceneBox( std::vector< SPolygon > &vecPolygon )
{
unsigned i;
DNVector(EtVector4) vecPlane;
m_SceneBox.GetPlanes( vecPlane );
for( i = 0; i < vecPlane.size(); i++ )
{
ClipFrustumByPlane( vecPolygon, vecPlane[ i ], vecPolygon );
}
}
void CEtLiSPShadowMap::CalcNearCameraPoint()
{
int i;
float fMinDist;
fMinDist = FLT_MAX;
for( i = 0; i < ( int )m_vecFocusRegion.size(); i++ )
{
float fDist;
fDist = EtVec3LengthSq( &( m_vecFocusRegion[ i ] - m_CamPos ) );
if( fDist < fMinDist )
{
fMinDist = fDist;
m_NearCameraPoint = m_vecFocusRegion[ i ];
}
}
}
void CEtLiSPShadowMap::GetSCameraInfo()
{
EtMatrix InvViewMat, *pViewMat;
pViewMat = CEtCamera::GetActiveCamera()->GetViewMat();
EtMatrixInverse( &InvViewMat, NULL, pViewMat );
memcpy( &m_CamPos, &InvViewMat._41, sizeof( EtVector3 ) );
m_CamDir.x = pViewMat->_13;
m_CamDir.y = pViewMat->_23;
m_CamDir.z = pViewMat->_33;
m_LightDir = CEtLight::GetShadowCastDirLightInfo()->Direction;
m_SceneBox.Min = m_CamPos + EtVector3( -m_fShadowRange, -m_fShadowRange / 4, -m_fShadowRange );
m_SceneBox.Max = m_CamPos + EtVector3( m_fShadowRange, m_fShadowRange / 4, m_fShadowRange );
}
void CEtLiSPShadowMap::CalcFocusRegion()
{
std::vector< SPolygon > vecPolygon;
GetSCameraInfo();
CalcFrustumPoly( vecPolygon );
ClipFrustumBySceneBox( vecPolygon );
unsigned i, j;
m_vecFocusRegion.clear();
for( i = 0; i < vecPolygon.size(); i++ )
{
const std::vector< EtVector3 > &Polygon = vecPolygon[ i ].Polygon;
for( j = 0; j < Polygon.size(); j++ )
{
m_vecFocusRegion.push_back( Polygon[ j ] );
}
}
CalcNearCameraPoint();
unsigned nSize;
EtVector3 LightDir;
float fDist;
nSize = ( unsigned )m_vecFocusRegion.size();
LightDir = -m_LightDir;
for( i = 0; i < nSize; i++ )
{
// by mapping m_vecFocusRegion[ i ]<5D><> <20>ڽ<EFBFBD><DABD><EFBFBD> <20><><EFBFBD>ο<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>±<EFBFBD><C2B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ȱ<EFBFBD><C8B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.. <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>..
if( TestLineToBox( m_vecFocusRegion[ i ], LightDir, m_SceneBox, fDist ) )
{
if( fDist > 10e-5 )
{
m_vecFocusRegion.push_back( m_vecFocusRegion[ i ] + LightDir * fDist );
}
}
}
}
void CEtLiSPShadowMap::CalcLightSpaceViewProjDir( EtVector3 &LightSpaceViewProjDir )
{
EtMatrix LightSpaceMat;
EtVector3 NearLS, EdgeLS;
EtMatrixMultiply( &LightSpaceMat, &m_LightViewMat, &m_LightProjMat );
EtVec3TransformCoord( &NearLS, &m_NearCameraPoint, &LightSpaceMat );
EtVec3TransformCoord( &EdgeLS, &( m_NearCameraPoint + m_CamDir ), &LightSpaceMat );
LightSpaceViewProjDir = EdgeLS - NearLS;
LightSpaceViewProjDir.y = 0.0f;
}
void CEtLiSPShadowMap::CalcZ0LS( EtVector3 &Output, EtMatrix &LightSpaceMat, float fBoxMaxZ )
{
EtMatrix InvLightSpaceMat;
EtVector3 NearLS;
EtVector4 Plane;
float fLength;
EtMatrixInverse( &InvLightSpaceMat, NULL, &LightSpaceMat );
EtMatrixTranspose( &InvLightSpaceMat, &InvLightSpaceMat );
Plane.x = m_CamDir.x;
Plane.y = m_CamDir.y;
Plane.z = m_CamDir.z;
Plane.w = -EtVec3Dot( &m_CamDir, &m_NearCameraPoint );
EtVec4Transform( &Plane, &Plane, &InvLightSpaceMat );
Plane.w = -Plane.w;
fLength = EtVec3Length( ( EtVector3 * )&Plane );
Plane /= fLength;
EtVec3TransformCoord( &NearLS, &m_NearCameraPoint, &LightSpaceMat );
Output = EtVector3( NearLS.x, ( Plane.w - Plane.z * fBoxMaxZ - Plane.x * NearLS.x ) / Plane.y, fBoxMaxZ );
}
float CEtLiSPShadowMap::CalcNParam( EtMatrix &LightSpaceMat, SAABox &Box )
{
EtVector3 Z0, Z1;
EtMatrix InvLightSpaceMat, ViewMat;
CalcZ0LS( Z0, LightSpaceMat, Box.Min.z );
Z1 = EtVector3( Z0.x, Z0.y, Box.Max.z );
EtMatrixInverse( &InvLightSpaceMat, NULL, &LightSpaceMat );
EtVec3TransformCoord( &Z0, &Z0, &InvLightSpaceMat );
EtVec3TransformCoord( &Z1, &Z1, &InvLightSpaceMat );
ViewMat = *CEtCamera::GetActiveCamera()->GetViewMat();
EtVec3TransformCoord( &Z0, &Z0, &ViewMat );
EtVec3TransformCoord( &Z1, &Z1, &ViewMat );
return fabs( Box.Max.z - Box.Min.z ) / ( sqrtf( Z1.z / Z0.z ) - 1.0f );
}
void CEtLiSPShadowMap::CalcLiSPSMat()
{
unsigned i;
float fNParam, fDepth;
EtMatrix LightSpaceMat, ProjCenterMat, Frustum;
EtVector3 NearPointLS, Center;
SAABox Box;
EtMatrixMultiply( &LightSpaceMat, &m_LightViewMat, &m_LightProjMat );
Box.Reset();
for( i = 0; i < m_vecFocusRegion.size(); i++ )
{
EtVector3 PointLS;
EtVec3TransformCoord( &PointLS, &m_vecFocusRegion[ i ], &LightSpaceMat );
Box.AddPoint( PointLS );
}
EtVec3TransformCoord( &NearPointLS, &m_NearCameraPoint, &LightSpaceMat );
fNParam = CalcNParam( LightSpaceMat, Box );
EtMatrixIdentity( &ProjCenterMat );
ProjCenterMat._41 = -NearPointLS.x;
ProjCenterMat._42 = -NearPointLS.y;
ProjCenterMat._43 = ( fNParam - Box.Min.z );
fDepth = fabs( Box.Max.z - Box.Min.z );
EtMatrixPerspectiveOffCenterLH( &Frustum, -1.0f, 1.0f, -1.0f, 1.0f, fNParam, fNParam + fDepth );
Frustum._33 = ( fNParam + fNParam + fDepth ) / fDepth;
Frustum._43 = 2.0f * Frustum._43;
EtMatrixMultiply( &Frustum, &ProjCenterMat, &Frustum );
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &Frustum );
}
void CEtLiSPShadowMap::RescaleShadowMat()
{
unsigned i;
EtMatrix LightSpaceMat, ScaleMat, TransMat;
SAABox Box;
EtMatrixMultiply( &LightSpaceMat, &m_LightViewMat, &m_LightProjMat );
Box.Reset();
for( i = 0; i < m_vecFocusRegion.size(); i++ )
{
EtVector3 PointLS;
EtVec3TransformCoord( &PointLS, &m_vecFocusRegion[ i ], &LightSpaceMat );
Box.AddPoint( PointLS );
}
EtVector3 DiffBox, SumBox;
DiffBox = Box.Max - Box.Min;
SumBox = Box.Max + Box.Min;
EtMatrixScaling( &ScaleMat, 2 / DiffBox.x, 2 / DiffBox.y, 2 / DiffBox.z );
EtMatrixTranslation( &TransMat, -SumBox.x / DiffBox.x, -SumBox.y / DiffBox.y, -SumBox.z / DiffBox.z );
EtMatrixMultiply( &ScaleMat, &ScaleMat, &TransMat );
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &ScaleMat );
}
void CEtLiSPShadowMap::CalcUpVec( EtVector3 &Output )
{
unsigned i;
EtVector3 ViewDir, RightDir;
ViewDir = EtVector3( 0.0f, 0.0f, 0.0f );
for( i = 0; i < m_vecFocusRegion.size(); i++ )
{
EtVector3 Diff;
Diff = m_vecFocusRegion[ i ] - m_CamPos;
ViewDir += Diff;
}
EtVec3Normalize( &ViewDir, &ViewDir );
EtVec3Cross( &RightDir, &ViewDir, &m_LightDir );
EtVec3Normalize( &RightDir, &RightDir );
EtVec3Cross( &Output, &m_LightDir, &RightDir );
EtVec3Normalize( &Output, &Output );
}
void CEtLiSPShadowMap::CalcShadowMat()
{
CalcFocusRegion();
EtVector3 At, UpVec;
At = m_CamPos + m_LightDir * 100.0f;
CalcUpVec( UpVec );
EtMatrixLookAtLH( &m_LightViewMat, &m_CamPos, &At, &UpVec );
EtMatrixIdentity( &m_LightProjMat );
if( m_vecFocusRegion.size() <= 0 )
{
return;
}
EtMatrix ChangeCoordMat;
memset( &ChangeCoordMat, 0, sizeof( EtMatrix ) );
ChangeCoordMat._11 = 1.0f;
ChangeCoordMat._23 = 1.0f;
ChangeCoordMat._32 = -1.0f;
ChangeCoordMat._44 = 1.0f;
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &ChangeCoordMat );
EtVector3 ViewProjDirLS;
EtMatrix ViewProjMatLS, LiSPSMat;
CalcLightSpaceViewProjDir( ViewProjDirLS );
EtMatrixLookAtLH( &ViewProjMatLS, &EtVector3( 0.0f, 0.0f, 0.0f ), &( ViewProjDirLS * 100.0f ), &EtVector3( 0.0f, 1.0f, 0.0f ) );
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &ViewProjMatLS );
CalcLiSPSMat();
RescaleShadowMat();
ChangeCoordMat._23 = -1.0f;
ChangeCoordMat._32 = 1.0f;
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &ChangeCoordMat );
EtMatrixIdentity( &ChangeCoordMat );
ChangeCoordMat._33 = 0.5f;
ChangeCoordMat._43 = 0.5f;
EtMatrixMultiply( &m_LightProjMat, &m_LightProjMat, &ChangeCoordMat );
}
void CEtLiSPShadowMap::BeginShadow()
{
GetEtDevice()->SetRenderTarget( m_hShadowMap->GetSurfaceLevel() );
GetEtDevice()->SetDepthStencilSurface( m_hShadowMapDepth->GetDepthBuffer() );
GetEtDevice()->ClearBuffer( 0xffffffff, 1.0f, 0 );
GetEtDevice()->SetCullMode( CULL_CW );
}
void CEtLiSPShadowMap::EndShadow()
{
GetEtDevice()->RestoreRenderTarget();
GetEtDevice()->RestoreDepthStencil();
GetEtDevice()->SetCullMode( CULL_CCW );
}
/*void CreateLiSPSahdowMap( ShadowQuality Quality )
{
SAFE_DELETE( g_pEtShadowMap );
g_pEtShadowMap = new CEtLiSPShadowMap();
g_pEtShadowMap->Initialize( Quality );
}*/