DragonNest/Common/EternityEngine/EtLiSPShadowMap.cpp
Cussrro 47f7895977 Revert "修复编码问题"
This reverts commit 9e69c01767.
2024-12-21 10:04:04 +08:00

544 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 );
}*/