HRESULT CShadow::Create( LPDIRECT3DDEVICE9 pd3dDevice, LPD3DXMESH pMesh )
{
BASEMESHVERTEX* pVertices;
WORD* pIndices;
EdgeMap edgeMap; //sharing edges
EdgeMap::iterator edgeMapIter;
DWORD dwNumSavedEdges = 0L; // No of coplanar edges optimized
DWORD dwI;
ShadowVertices shadowVerticesVector; //存放网格预处理之后,添加了退化四边形后的顶点数组
ShadowIndices shadowIndicesVector; //同上,索引数组
// Copy pointer to d3d device
if ( pd3dDevice )
m_pd3dDevice = pd3dDevice;
else
return E_FAIL;
// Lock the geometry buffers
pMesh->LockVertexBuffer( D3DLOCK_READONLY, (VOID**)&pVertices );
pMesh->LockIndexBuffer( D3DLOCK_READONLY, (VOID**)&pIndices );
DWORD dwNumSourceVertices = pMesh->GetNumVertices();
DWORD dwNumFaces = pMesh->GetNumFaces();
// Step thru all faces
for ( DWORD faceIndex=0; faceIndex<dwNumFaces; faceIndex++ )
{
WORD wIndex0 = pIndices[3*faceIndex+0];
WORD wIndex1 = pIndices[3*faceIndex+1];
WORD wIndex2 = pIndices[3*faceIndex+2];
D3DXVECTOR3 v0 = pVertices[wIndex0].p;
D3DXVECTOR3 v1 = pVertices[wIndex1].p;
D3DXVECTOR3 v2 = pVertices[wIndex2].p;
// Compute face normal
D3DXVECTOR3 faceNormal;
D3DXVec3Cross( &faceNormal, &( v2 - v0 ), &( v1 - v0 ) );
D3DXVec3Normalize( &faceNormal, &faceNormal );
// Create shadow mesh vertices for current face
SHADOWMESHVERTEX shadowVertices[3];
for ( DWORD vertIndex = 0; vertIndex < 3; vertIndex++ )
{
shadowVertices[vertIndex].p = pVertices[pIndices[3*faceIndex+vertIndex]].p;
// There was a time when a typo (.p instead of .n) caused me 6 hours...
shadowVertices[vertIndex].n = faceNormal;
}
// Search edgeMap for a possible partner edge to the current edge
// e.g. Equivalent positions
EdgePositions edgePositions[3];
EdgeData sharedEdgesData[3];
EdgePositions edgeToFind;
BOOL edgeFound[3];
BOOL quadRequired[3];
//检查当前面的每一边,是否为共享边,如果是,检查法线是否平行,不平行的才需要插入退化四边形
for ( DWORD edgeIndex = 0; edgeIndex < 3; edgeIndex++ )
{
edgePositions[edgeIndex].p0 = shadowVertices[edgeIndex].p;
edgePositions[edgeIndex].p1 = shadowVertices[( edgeIndex + 1 ) % 3].p;
// Find shared edge with reverse vertices
edgeToFind.p0 = edgePositions[edgeIndex].p1;
edgeToFind.p1 = edgePositions[edgeIndex].p0;
edgeMapIter = edgeMap.find( edgeToFind );
// Did we find it?
if ( edgeMapIter != edgeMap.end() ) // Found!
{
edgeFound[edgeIndex] = TRUE;
sharedEdgesData[edgeIndex] = edgeMapIter->second;
edgeMap.erase( edgeMapIter );
// We can optimize away coplanar shared edges. e.g. their normals are
// almost parallel
if ( ( D3DXVec3Dot( &faceNormal, &sharedEdgesData[edgeIndex].n0 ) ) <
MERGE_COS_ANGLE_PROXIMITY )
{
quadRequired[edgeIndex] = TRUE;
}
else
{
quadRequired[edgeIndex] = FALSE;
dwNumSavedEdges++;
}
}
else // New
{
edgeFound[edgeIndex] = FALSE;
}
}
// Selected index of vertices
//如果当前边是共享边,已经被优化(不需要加入退化四边形),直接将它的顶点和索引数据放入shadowVerticesVector shadowIndicesVector
//如果当前边不是共享边(新发现的),或者需要加入退化四边形,添加新的顶点和索引数据
WORD index[3];
for ( DWORD vertIndex=0; vertIndex<3; vertIndex++ )
{
// Vertex creation
DWORD edgeIndex0 = vertIndex; // 0, 1, 2
DWORD edgeIndex1 = ( vertIndex + 2 ) % 3; // 2, 0, 1
// We check whether the current edge had been optimized away
// If it is, we just need to copy the index from the shared edge since
// the current vertex is gone
if ( ( edgeFound[edgeIndex0] ) && ( !quadRequired[edgeIndex0] ) )
{
index[vertIndex] = sharedEdgesData[edgeIndex0].i1;
}
else if ( ( edgeFound[edgeIndex1] ) && ( !quadRequired[edgeIndex1] ) )
{
index[vertIndex] = sharedEdgesData[edgeIndex1].i0;
}
else // No optimization, new vertex OR degenerate quad required
{
// Current size = index
index[vertIndex] = (WORD)shadowVerticesVector.size();
// Store current vertex
shadowVerticesVector.push_back( shadowVertices[vertIndex] );
}
// Index creation
shadowIndicesVector.push_back( index[vertIndex] );
}
// Time to create the degenerate quads
for ( DWORD edgeIndex = 0; edgeIndex < 3; edgeIndex++ )
{
EdgeData edgeData;
edgeData.i0 = index[edgeIndex]; // 0, 1, 2
edgeData.i1 = index[( edgeIndex + 1 ) % 3]; // 1, 2, 0
edgeData.n0 = faceNormal;
if ( edgeFound[edgeIndex] ) // Shared edge found
{
// Handle 3 cases: Insert full quad, insert left side tri or insert
// right side tri
// If current edge had NOT been optimized away
if ( ( sharedEdgesData[edgeIndex].i0 != edgeData.i1 ) &&
( sharedEdgesData[edgeIndex].i1 != edgeData.i0 ) )
{
shadowIndicesVector.push_back( edgeData.i1 );
shadowIndicesVector.push_back( edgeData.i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i1 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i0 );
shadowIndicesVector.push_back( edgeData.i0 );
}
else if ( sharedEdgesData[edgeIndex].i1 != edgeData.i0 )
{
shadowIndicesVector.push_back( edgeData.i1 );
shadowIndicesVector.push_back( edgeData.i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i1 );
}
else if( sharedEdgesData[edgeIndex].i0 != edgeData.i1 )
{
shadowIndicesVector.push_back( edgeData.i1 );
shadowIndicesVector.push_back( edgeData.i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i0 );
}
// All other cases meant that the current edge had been optimized away
// and only the shared edge is left. The shared edge is left alone with
// additional degenerate triangles added
}
else // New edge
{
edgeMap[edgePositions[edgeIndex]] = edgeData;
}
}
}
// Gather some stats
m_dwVertexBufferSize = (DWORD)shadowVerticesVector.size();
m_dwIndexBufferSize = (DWORD)shadowIndicesVector.size();
// ********** Create vertex and index buffers **********
// Create index buffer
if ( FAILED( m_pd3dDevice->CreateIndexBuffer( m_dwIndexBufferSize *
sizeof( WORD ), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED,
&m_pIndexBuffer, NULL ) ) )
{
OutputDebugString( "Index buffer creation failed!\n" );
return E_FAIL;
}
// Lock index buffer
WORD* pLockedIndexBuffer;
m_pIndexBuffer->Lock( 0, m_dwIndexBufferSize * sizeof( WORD ),
(VOID**)&pLockedIndexBuffer, 0 );
// Fill locked index buffer with data
IndexIter indexIter;
for ( indexIter = shadowIndicesVector.begin(), dwI = 0;
indexIter != shadowIndicesVector.end(); ++indexIter, dwI++ )
{
pLockedIndexBuffer[dwI] = (WORD)*indexIter;
}
m_pIndexBuffer->Unlock();
// Create vertex buffer
if ( FAILED( m_pd3dDevice->CreateVertexBuffer( m_dwVertexBufferSize *
sizeof( SHADOWMESHVERTEX ), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED,
&m_pVertexBuffer, NULL ) ) )
{
OutputDebugString( "Vertex buffer creation failed!\n" );
return E_FAIL;
}
// Lock vertex buffer
SHADOWMESHVERTEX* pLockedVertexBuffer;
VertexIter vertexIter;
m_pVertexBuffer->Lock( 0, m_dwVertexBufferSize * sizeof( SHADOWMESHVERTEX ),
(VOID**)&pLockedVertexBuffer, 0 );
// Fill locked vertex buffer with data
for ( vertexIter=shadowVerticesVector.begin(), dwI=0;
vertexIter != shadowVerticesVector.end(); ++vertexIter, dwI++ )
{
pLockedVertexBuffer[dwI] = *vertexIter;
}
{
BASEMESHVERTEX* pVertices;
WORD* pIndices;
EdgeMap edgeMap; //sharing edges
EdgeMap::iterator edgeMapIter;
DWORD dwNumSavedEdges = 0L; // No of coplanar edges optimized
DWORD dwI;
ShadowVertices shadowVerticesVector; //存放网格预处理之后,添加了退化四边形后的顶点数组
ShadowIndices shadowIndicesVector; //同上,索引数组
// Copy pointer to d3d device
if ( pd3dDevice )
m_pd3dDevice = pd3dDevice;
else
return E_FAIL;
// Lock the geometry buffers
pMesh->LockVertexBuffer( D3DLOCK_READONLY, (VOID**)&pVertices );
pMesh->LockIndexBuffer( D3DLOCK_READONLY, (VOID**)&pIndices );
DWORD dwNumSourceVertices = pMesh->GetNumVertices();
DWORD dwNumFaces = pMesh->GetNumFaces();
// Step thru all faces
for ( DWORD faceIndex=0; faceIndex<dwNumFaces; faceIndex++ )
{
WORD wIndex0 = pIndices[3*faceIndex+0];
WORD wIndex1 = pIndices[3*faceIndex+1];
WORD wIndex2 = pIndices[3*faceIndex+2];
D3DXVECTOR3 v0 = pVertices[wIndex0].p;
D3DXVECTOR3 v1 = pVertices[wIndex1].p;
D3DXVECTOR3 v2 = pVertices[wIndex2].p;
// Compute face normal
D3DXVECTOR3 faceNormal;
D3DXVec3Cross( &faceNormal, &( v2 - v0 ), &( v1 - v0 ) );
D3DXVec3Normalize( &faceNormal, &faceNormal );
// Create shadow mesh vertices for current face
SHADOWMESHVERTEX shadowVertices[3];
for ( DWORD vertIndex = 0; vertIndex < 3; vertIndex++ )
{
shadowVertices[vertIndex].p = pVertices[pIndices[3*faceIndex+vertIndex]].p;
// There was a time when a typo (.p instead of .n) caused me 6 hours...
shadowVertices[vertIndex].n = faceNormal;
}
// Search edgeMap for a possible partner edge to the current edge
// e.g. Equivalent positions
EdgePositions edgePositions[3];
EdgeData sharedEdgesData[3];
EdgePositions edgeToFind;
BOOL edgeFound[3];
BOOL quadRequired[3];
//检查当前面的每一边,是否为共享边,如果是,检查法线是否平行,不平行的才需要插入退化四边形
for ( DWORD edgeIndex = 0; edgeIndex < 3; edgeIndex++ )
{
edgePositions[edgeIndex].p0 = shadowVertices[edgeIndex].p;
edgePositions[edgeIndex].p1 = shadowVertices[( edgeIndex + 1 ) % 3].p;
// Find shared edge with reverse vertices
edgeToFind.p0 = edgePositions[edgeIndex].p1;
edgeToFind.p1 = edgePositions[edgeIndex].p0;
edgeMapIter = edgeMap.find( edgeToFind );
// Did we find it?
if ( edgeMapIter != edgeMap.end() ) // Found!
{
edgeFound[edgeIndex] = TRUE;
sharedEdgesData[edgeIndex] = edgeMapIter->second;
edgeMap.erase( edgeMapIter );
// We can optimize away coplanar shared edges. e.g. their normals are
// almost parallel
if ( ( D3DXVec3Dot( &faceNormal, &sharedEdgesData[edgeIndex].n0 ) ) <
MERGE_COS_ANGLE_PROXIMITY )
{
quadRequired[edgeIndex] = TRUE;
}
else
{
quadRequired[edgeIndex] = FALSE;
dwNumSavedEdges++;
}
}
else // New
{
edgeFound[edgeIndex] = FALSE;
}
}
// Selected index of vertices
//如果当前边是共享边,已经被优化(不需要加入退化四边形),直接将它的顶点和索引数据放入shadowVerticesVector shadowIndicesVector
//如果当前边不是共享边(新发现的),或者需要加入退化四边形,添加新的顶点和索引数据
WORD index[3];
for ( DWORD vertIndex=0; vertIndex<3; vertIndex++ )
{
// Vertex creation
DWORD edgeIndex0 = vertIndex; // 0, 1, 2
DWORD edgeIndex1 = ( vertIndex + 2 ) % 3; // 2, 0, 1
// We check whether the current edge had been optimized away
// If it is, we just need to copy the index from the shared edge since
// the current vertex is gone
if ( ( edgeFound[edgeIndex0] ) && ( !quadRequired[edgeIndex0] ) )
{
index[vertIndex] = sharedEdgesData[edgeIndex0].i1;
}
else if ( ( edgeFound[edgeIndex1] ) && ( !quadRequired[edgeIndex1] ) )
{
index[vertIndex] = sharedEdgesData[edgeIndex1].i0;
}
else // No optimization, new vertex OR degenerate quad required
{
// Current size = index
index[vertIndex] = (WORD)shadowVerticesVector.size();
// Store current vertex
shadowVerticesVector.push_back( shadowVertices[vertIndex] );
}
// Index creation
shadowIndicesVector.push_back( index[vertIndex] );
}
// Time to create the degenerate quads
for ( DWORD edgeIndex = 0; edgeIndex < 3; edgeIndex++ )
{
EdgeData edgeData;
edgeData.i0 = index[edgeIndex]; // 0, 1, 2
edgeData.i1 = index[( edgeIndex + 1 ) % 3]; // 1, 2, 0
edgeData.n0 = faceNormal;
if ( edgeFound[edgeIndex] ) // Shared edge found
{
// Handle 3 cases: Insert full quad, insert left side tri or insert
// right side tri
// If current edge had NOT been optimized away
if ( ( sharedEdgesData[edgeIndex].i0 != edgeData.i1 ) &&
( sharedEdgesData[edgeIndex].i1 != edgeData.i0 ) )
{
shadowIndicesVector.push_back( edgeData.i1 );
shadowIndicesVector.push_back( edgeData.i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i1 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i0 );
shadowIndicesVector.push_back( edgeData.i0 );
}
else if ( sharedEdgesData[edgeIndex].i1 != edgeData.i0 )
{
shadowIndicesVector.push_back( edgeData.i1 );
shadowIndicesVector.push_back( edgeData.i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i1 );
}
else if( sharedEdgesData[edgeIndex].i0 != edgeData.i1 )
{
shadowIndicesVector.push_back( edgeData.i1 );
shadowIndicesVector.push_back( edgeData.i0 );
shadowIndicesVector.push_back( sharedEdgesData[edgeIndex].i0 );
}
// All other cases meant that the current edge had been optimized away
// and only the shared edge is left. The shared edge is left alone with
// additional degenerate triangles added
}
else // New edge
{
edgeMap[edgePositions[edgeIndex]] = edgeData;
}
}
}
// Gather some stats
m_dwVertexBufferSize = (DWORD)shadowVerticesVector.size();
m_dwIndexBufferSize = (DWORD)shadowIndicesVector.size();
// ********** Create vertex and index buffers **********
// Create index buffer
if ( FAILED( m_pd3dDevice->CreateIndexBuffer( m_dwIndexBufferSize *
sizeof( WORD ), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED,
&m_pIndexBuffer, NULL ) ) )
{
OutputDebugString( "Index buffer creation failed!\n" );
return E_FAIL;
}
// Lock index buffer
WORD* pLockedIndexBuffer;
m_pIndexBuffer->Lock( 0, m_dwIndexBufferSize * sizeof( WORD ),
(VOID**)&pLockedIndexBuffer, 0 );
// Fill locked index buffer with data
IndexIter indexIter;
for ( indexIter = shadowIndicesVector.begin(), dwI = 0;
indexIter != shadowIndicesVector.end(); ++indexIter, dwI++ )
{
pLockedIndexBuffer[dwI] = (WORD)*indexIter;
}
m_pIndexBuffer->Unlock();
// Create vertex buffer
if ( FAILED( m_pd3dDevice->CreateVertexBuffer( m_dwVertexBufferSize *
sizeof( SHADOWMESHVERTEX ), D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED,
&m_pVertexBuffer, NULL ) ) )
{
OutputDebugString( "Vertex buffer creation failed!\n" );
return E_FAIL;
}
// Lock vertex buffer
SHADOWMESHVERTEX* pLockedVertexBuffer;
VertexIter vertexIter;
m_pVertexBuffer->Lock( 0, m_dwVertexBufferSize * sizeof( SHADOWMESHVERTEX ),
(VOID**)&pLockedVertexBuffer, 0 );
// Fill locked vertex buffer with data
for ( vertexIter=shadowVerticesVector.begin(), dwI=0;
vertexIter != shadowVerticesVector.end(); ++vertexIter, dwI++ )
{
pLockedVertexBuffer[dwI] = *vertexIter;
}
m_pVertexBuffer->Unlock();
}