DragonNest/Common/EternityEngine/EtInstancingMng.cpp

334 lines
9.6 KiB
C++
Raw Normal View History

2024-12-19 09:48:26 +08:00
#include "StdAfx.h"
#include "EtInstancingMng.h"
#include "EtOptionController.h"
#include "EtMRTMng.h"
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
#define MAX_INSTANCING_COUNT 1024
bool NormalRenderInstancingSort( SRenderStackElement *Element1, SRenderStackElement *Element2 )
{
if( Element1->renderPriority != Element2->renderPriority )
{
if( Element1->renderPriority < Element2->renderPriority )
return true;
else
return false;
}
#ifdef PRE_FIX_MATERIAL_DUMP
else if( Element1->hMaterial && Element2->hMaterial && Element1->hMaterial != Element2->hMaterial )
#else
else if( Element1->hMaterial != Element2->hMaterial )
#endif
{
int nRef1, nRef2;
nRef1 = Element1->hMaterial->GetRefCount();
nRef2 = Element2->hMaterial->GetRefCount();
if( nRef1 > nRef2 )
{
return true;
}
else if (nRef1 < nRef2 )
{
return false;
}
else
{
return Element1->hMaterial.GetIndex() > Element2->hMaterial.GetIndex();
}
}
else if( Element1->nTechniqueIndex != Element2->nTechniqueIndex )
{
if( Element1->nTechniqueIndex < Element2->nTechniqueIndex )
{
return true;
}
else
{
return false;
}
}
else if( Element1->pRenderSubMesh != Element2->pRenderSubMesh )
{
if( Element1->pRenderSubMesh < Element2->pRenderSubMesh )
{
return true;
}
else
{
return false;
}
}
else if( Element1->fDirLightAttenuation != Element2->fDirLightAttenuation )
{
if( Element1->fDirLightAttenuation < Element2->fDirLightAttenuation )
{
return true;
}
else
{
return false;
}
}
else
{
if( Element1->fDist < Element2->fDist )
{
return true;
}
else
{
return false;
}
}
}
CEtInstancingMng::CEtInstancingMng()
{
m_bInit = false;
m_bEnable = false;
m_pWorldViewMatVB = NULL;
memset(m_nVertexDecl, 0, sizeof(m_nVertexDecl));
}
CEtInstancingMng::~CEtInstancingMng()
{
SAFE_RELEASE( m_pWorldViewMatVB );
SAFE_RELEASE_SPTR( m_hMaterial );
SAFE_RELEASE_SPTR( m_hSourceMaterial );
}
void CEtInstancingMng::Enable( bool bEnable )
{
if( bEnable ) {
int nVSVersion = ( GetEtDevice()->GetVSVersion() & 0xffff ) >> 8;
int nPSVersion = ( GetEtDevice()->GetPSVersion() & 0xffff ) >> 8;
if( ( nVSVersion < 3 ) || ( nPSVersion < 3 ) ) { // <20><><EFBFBD>̴<EFBFBD> 3.0 <20>̻󿡼<CCBB><F3BFA1BC><EFBFBD> <20>ν<EFBFBD><CEBD>Ͻ<EFBFBD><CFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ȴ<EFBFBD>..
m_bEnable = false;
OutputDebug("Gpu does not support instancing.\n");
}
else {
m_bEnable = true;
/*OutputDebug("Instancing Enable\n");*/
}
}
else {
m_bEnable = false;
/*OutputDebug("Instancing Disable\n");*/
}
}
void CEtInstancingMng::Initialize()
{
if( m_bInit ) {
return;
}
m_pWorldViewMatVB = GetEtDevice()->CreateVertexBuffer( sizeof(EtMatrix) * MAX_INSTANCING_COUNT, 0 );
D3DVERTEXELEMENT9 VertexElement0[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{1, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 },
{2, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{3, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
{3, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
{3, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
{3, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
D3DDECL_END() };
D3DVERTEXELEMENT9 VertexElement1[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{1, 0, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
{2, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
{2, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
{2, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
{2, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
D3DDECL_END() };
D3DVERTEXELEMENT9 VertexElement2[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
{1, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1 },
{1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2 },
{1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3 },
{1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4 },
D3DDECL_END() };
m_nVertexDecl[ 0 ] = GetEtDevice()->CreateVertexDeclaration( VertexElement0 );
m_nVertexDecl[ 1 ] = GetEtDevice()->CreateVertexDeclaration( VertexElement1 );
m_nVertexDecl[ 2 ] = GetEtDevice()->CreateVertexDeclaration( VertexElement2 );
m_hMaterial = LoadResource( "DiffuseInstancing.fx", RT_SHADER );
m_hSourceMaterial = LoadResource( "Diffuse.fx", RT_SHADER);
m_bInit = true;
}
void CEtInstancingMng::ClassifyBlock( std::vector< SRenderStackElement* > &vecBlock, std::vector< SRenderStackElement* > &vecInstancingBlock )
{
if( !m_bEnable || vecBlock.empty() || !CEtCamera::GetActiveCamera() ) {
return;
}
Initialize();
std::sort( vecBlock.begin(), vecBlock.end(), NormalRenderInstancingSort );
int i ;
ASSERT( vecInstancingBlock.empty() );
int nDup = 0;
for( i = 0; i< ( int )vecBlock.size()-1; i++)
{
SRenderStackElement *pBlock = vecBlock[ i ];
SRenderStackElement *pNextBlock = vecBlock[ i + 1 ];
int nLight = 0;
for( nLight = 0; nLight < MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT; nLight++) {
if( pBlock->pInfluenceLight[ nLight ] == NULL && pNextBlock->pInfluenceLight[ nLight ] == NULL ) {
nLight = MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT;
break;
}
if( pBlock->pInfluenceLight[ nLight ] != pNextBlock->pInfluenceLight[ nLight ] ) {
break;
}
}
bool bSameLight = ( nLight == MAX_POINT_LIGHT_COUNT + MAX_SPOT_LIGHT_COUNT );
if( bSameLight &&
pBlock->hMaterial == m_hSourceMaterial &&
pBlock->nSaveMatIndex == -1 &&
pBlock->pRenderMeshStream == NULL &&
pBlock->pRenderSubMesh == pNextBlock->pRenderSubMesh &&
pBlock->fDirLightAttenuation == pNextBlock->fDirLightAttenuation &&
pBlock->nTechniqueIndex == pNextBlock->nTechniqueIndex ) {
nDup++;
vecInstancingBlock.push_back( pBlock );
bool bLastElement = (i == vecBlock.size() - 2);
if( bLastElement ) {
pNextBlock->bLastElement = true;
vecInstancingBlock.push_back( pNextBlock );
vecBlock.erase( vecBlock.begin() + i );
}
vecBlock.erase( vecBlock.begin() + i );
i--;
}
else {
if( nDup != 0 ) {
vecBlock[i]->bLastElement = true;
vecInstancingBlock.push_back( vecBlock[i] );
vecBlock.erase( vecBlock.begin() + i );
i--;
}
nDup = 0;
}
}
if( vecInstancingBlock.empty() ) {
return;
}
ASSERT( vecInstancingBlock.size() <= MAX_INSTANCING_COUNT );
EtMatrix *pLockedPtr = NULL;
m_pWorldViewMatVB->Lock( 0, sizeof(EtMatrix)*(int)vecInstancingBlock.size(), (void**)&pLockedPtr, 0);
int nSize = (int)vecInstancingBlock.size();
for( i = 0; i < nSize; i++) {
EtMatrixMultiply( &pLockedPtr[ i ], &vecInstancingBlock[ i ]->WorldMat, CEtCamera::GetActiveCamera()->GetViewMat() );
}
m_pWorldViewMatVB->Unlock();
}
void CEtInstancingMng::RenderDepth( std::vector< SRenderStackElement* > &vecBlock )
{
if( !m_bEnable || vecBlock.empty() ) {
return;
}
if( !CEtRenderStack::IsDepthRender() ) {
return;
}
Initialize();
int i, nPasses;
int nDup = 0;
int nStartIndex = 0;
EtMatrix IdentMat;
EtMatrixIdentity( &IdentMat );
CEtMRTMng::GetInstance().BeginDepthTarget();
for( i = 0; i < ( int )vecBlock.size(); i++ )
{
nDup++;
SRenderStackElement *pCurBlock = vecBlock[ i ];
if( !pCurBlock->bLastElement ) {
continue;
}
ASSERT( pCurBlock->nBakeDepthIndex == DT_NORMAL || pCurBlock->nBakeDepthIndex == DT_OPAQUE || pCurBlock->nBakeDepthIndex == DT_VOLUME );
int nTechnique = (pCurBlock->nBakeDepthIndex == DT_OPAQUE ) ? 2 : 1;
m_hMaterial->SetTechnique( nTechnique );
m_hMaterial->BeginEffect( nPasses );
m_hMaterial->BeginPass( 0 );
m_hMaterial->SetGlobalParams();
m_hMaterial->SetWorldMatParams( &IdentMat, &IdentMat );
if( pCurBlock->pvecCustomParam ) {
m_hMaterial->SetCustomParamList( *pCurBlock->pvecCustomParam );
}
m_hMaterial->CommitChanges();
pCurBlock->pRenderSubMesh->GetMeshStream()->DrawInstancing( m_nVertexDecl[ nTechnique ] , m_pWorldViewMatVB, nStartIndex, nDup );
nStartIndex += nDup;
nDup = 0;
m_hMaterial->EndPass();
m_hMaterial->EndEffect();
}
CEtMRTMng::GetInstance().EndDepthTarget();
}
void CEtInstancingMng::Render( std::vector< SRenderStackElement* > &vecBlock )
{
if( !m_bEnable || vecBlock.empty() ) {
return;
}
Initialize();
int i, nPasses;
EtMatrix IdentMat;
EtMatrixIdentity( &IdentMat );
m_hMaterial->SetTechnique( 0 );
m_hMaterial->BeginEffect( nPasses );
m_hMaterial->BeginPass( 0 );
m_hMaterial->SetGlobalParams();
int nDup = 0;
int nStartIndex = 0;
for( i = 0; i< ( int )vecBlock.size(); i++) {
nDup++;
SRenderStackElement *pCurBlock = vecBlock[ i ];
if( !pCurBlock->bLastElement ) {
continue;
}
CEtLight::SetInfluenceLight( pCurBlock->pInfluenceLight );
CEtLight::SetDirLightAttenuation( pCurBlock->fDirLightAttenuation );
m_hMaterial->SetWorldMatParams( &IdentMat, &IdentMat );
if( pCurBlock->pvecCustomParam ) {
m_hMaterial->SetCustomParamList( *pCurBlock->pvecCustomParam );
}
m_hMaterial->CommitChanges();
pCurBlock->pRenderSubMesh->GetMeshStream()->DrawInstancing( m_nVertexDecl[ 0 ], m_pWorldViewMatVB, nStartIndex, nDup );
nStartIndex += nDup;
nDup = 0;
}
m_hMaterial->EndPass();
m_hMaterial->EndEffect();
vecBlock.clear();
}