/** Build the shadow volume for this mesh */ void CGeoChunk::BuildShadowVolume(CMDXModel *model,const AnimInfo& animInfo, ShadowVolume * pShadowVolume, LightParams* pLight, D3DXMATRIX* mxWorld) { CMaterial* mat = model->materialMap.materials[materialID<0 ? 0 : materialID]; CalcGroupMatrix(model); bool bCanCastShadow = false; // we will only cast shadows from chunks that does not contain blending or additive layers int numLayers = (int)mat->layers.size(); for(int l=0;l<numLayers;l++) { float alpha=mat->getFrameAlpha(animInfo.currentFrame,l); if(alpha < myEPSILON) continue; else { if(myEPSILON == 0.0f) alpha = 1.0f; } if(AnimAlphas[vertexGroups[triangles[0]]] < myEPSILON) { continue; } //(0:none;1:transparent;2:blend;3:additive) if((mat->layers[l]->filterMode == 1) || (mat->layers[l]->filterMode == 0)) { bCanCastShadow = true; break; } } if(!bCanCastShadow) return; /** build shadow volume based on this geochunk */ // TODO: light's direction relative to the object. // here we assume the light is a directional light. D3DXVECTOR3 vLight = pLight->Direction; float fRange = pLight->Range; vLight = -vLight; /// transform the local matrices to global matrices. for(int k=0; k<numGroups; k++) matrixes[k] *= (*mxWorld); // Allocate a temporary edge list hash_set <EdgeHash, hash_compare_edge> m_edgeTable; DWORD dwNumFaces = numTriangles; DWORD dwNumEdges = 0; D3DXVECTOR3 * pVertices = NULL; DWORD dwNumVertices = 0; int nUseCap = model->m_nUseShadowCap | ((pShadowVolume->m_shadowMethod == ShadowVolume::SHADOW_Z_FAIL)?1:0); if(nUseCap>0) { pShadowVolume->ReserveNewBlock(&pVertices, numTriangles*3); } // For each face for( DWORD i=0; i<dwNumFaces; i++ ) { WORD wFace0 = triangles[3*i+0]; WORD wFace1 = triangles[3*i+1]; WORD wFace2 = triangles[3*i+2]; D3DXVECTOR3 v0 = vertices[wFace0]; D3DXVECTOR3 v1 = vertices[wFace1]; D3DXVECTOR3 v2 = vertices[wFace2]; // transform the vertices so that they are in world coordicate system. D3DXVec3TransformCoord(&v0,&v0,&matrixes[vertexGroups[wFace0]]); D3DXVec3TransformCoord(&v1,&v1,&matrixes[vertexGroups[wFace1]]); D3DXVec3TransformCoord(&v2,&v2,&matrixes[vertexGroups[wFace2]]); // Transform vertices or transform light? // we use vertice transform, it may be more accurate to use light transform D3DXVECTOR3 vCross1(v2-v1); D3DXVECTOR3 vCross2(v1-v0); D3DXVECTOR3 vNormal; D3DXVec3Cross( &vNormal, &vCross1, &vCross2 ); if( D3DXVec3Dot( &vNormal, &vLight ) >= 0.0f ) { CEdgeBuilder::AddEdge( m_edgeTable, dwNumEdges, wFace0, wFace1 ); CEdgeBuilder::AddEdge( m_edgeTable, dwNumEdges, wFace1, wFace2 ); CEdgeBuilder::AddEdge( m_edgeTable, dwNumEdges, wFace2, wFace0 ); if(nUseCap>0) { pVertices[dwNumVertices++] = v0; pVertices[dwNumVertices++] = v2; pVertices[dwNumVertices++] = v1; } } } if(nUseCap>0) { // commit shadow volume front cap vertices pShadowVolume->CommitBlock(dwNumVertices); dwNumVertices = 0; pVertices = NULL; } /** build shadow volume for the edge array Interestingly, the extrusion of geometries for point light sources and infinite directional light sources are different. see below. */ if(pLight->bIsDirectional) { /** infinite directional light sources would extrude all silhouette edges to a single point at infinity. */ pShadowVolume->ReserveNewBlock(&pVertices, dwNumEdges*3); D3DXVECTOR3 v3 = D3DXVECTOR3(mxWorld->_41, mxWorld->_42, mxWorld->_43) + pLight->Direction * pLight->Range; hash_set <EdgeHash, hash_compare_edge>::iterator itCurCP, itEndCP = m_edgeTable.end(); // first shutdown all connections for( itCurCP = m_edgeTable.begin(); itCurCP != itEndCP; ++ itCurCP) { int index1 = (*itCurCP).m_v0; int index2 = (*itCurCP).m_v1; D3DXVECTOR3 v1 = vertices[index1]; D3DXVECTOR3 v2 = vertices[index2]; // transform the vertices so that they are in world coordicate system. D3DXVec3TransformCoord(&v1,&v1,&matrixes[vertexGroups[index1]]); D3DXVec3TransformCoord(&v2,&v2,&matrixes[vertexGroups[index2]]); // Add a quad (two triangles) to the vertex list pVertices[dwNumVertices++] = v1; pVertices[dwNumVertices++] = v2; pVertices[dwNumVertices++] = v3; } pShadowVolume->CommitBlock(dwNumVertices); } #ifdef POINTLIGHT_SUPPORT else // TODO: for point light, the listed method is not correct { /** Point light sources would extrude the silhouette edges exactly point for point */ pShadowVolume->ReserveNewBlock(&pVertices, dwNumEdges*6); for( i=0; i<dwNumEdges; i++ ) { int index1 = pEdges[2*i+0]; int index2 = pEdges[2*i+1]; D3DXVECTOR3 v1 = vertices[index1]; D3DXVECTOR3 v2 = vertices[index2]; // transform the vertices so that they are in world coordicate system. D3DXVec3TransformCoord(&v1,&v1,&matrixes[vertexGroups[index1]]); D3DXVec3TransformCoord(&v2,&v2,&matrixes[vertexGroups[index2]]); D3DXVECTOR3 v3 = v1 - vLight*fRange; D3DXVECTOR3 v4 = v2 - vLight*fRange; // Add a quad (two triangles) to the vertex list pVertices[dwNumVertices++] = v1; pVertices[dwNumVertices++] = v2; pVertices[dwNumVertices++] = v3; pVertices[dwNumVertices++] = v2; pVertices[dwNumVertices++] = v4; pVertices[dwNumVertices++] = v3; } pShadowVolume->CommitBlock(dwNumVertices); } #endif }
void CGeoChunk::Render(CMDXModel *model,const AnimInfo& animInfo) { LPDIRECT3DDEVICE9 pd3dDevice = CGlobals::GetRenderDevice(); CMaterial* mat = model->materialMap.materials[materialID<0 ? 0 : materialID]; CalcGroupMatrix(model); int numLayers = (int)mat->layers.size(); for(int l=0;l<numLayers;l++) { // LiXizhi: turn off light except for the last layer // Is it a rule for all mdx models? //if(l<mat->numLayers-1) // pd3dDevice->SetRenderState(D3DRS_LIGHTING,FALSE); //else // pd3dDevice->SetRenderState(D3DRS_LIGHTING,TRUE); float alpha=mat->getFrameAlpha(animInfo.currentFrame,l); if(alpha < myEPSILON) continue; else { if(myEPSILON == 0.0f) alpha = 1.0f; } if(AnimAlphas[vertexGroups[triangles[0]]] < myEPSILON) { continue; } LPDIRECT3DTEXTURE9 pTexture=model->texture.GetBindTexture(mat->layers[l]->textureID); // TODO: handle team glow here. // <see blp.cpp: LoadBlp for more information on replaceable bitmap> // replaceable bitmap are shared bitmaps. However, I do not use shared bitmap in Paraengine. // so in the ReplaceIDWithName(), The teamcolor and glow are simply set to NULL texture. //if(model->texture.bitmaps[mat->layers[l].textureID].replaceableID == 1) // ! team glow //{ // //} BOOL bHasTexture; if(pTexture==0) bHasTexture = false; else bHasTexture = true; pd3dDevice->SetTexture(0, pTexture); //(0:none;1:transparent;2:blend;3:additive) if(mat->layers[l]->filterMode == 1) // transparent { pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); pd3dDevice->SetRenderState(D3DRS_ALPHAREF, (DWORD)0x0000000BE); pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER); pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE ); }else if(mat->layers[l]->filterMode == 2) // blend { pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); }else // additive if(mat->layers[l]->filterMode == 3 ) { pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ONE); pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE); pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, FALSE ); } else { pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); pd3dDevice->SetRenderState( D3DRS_ZWRITEENABLE, TRUE ); } /* * fill vertex buffer with new data and draw it */ // the color of the model when no texture is specified; D3DXCOLOR colorModel = *(model->GetModelColor()); my_vertex* vb_vertices; int nNumLockedVertice; int nNumFinishedVertice = 0; DynamicVertexBufferEntity* pBufEntity = CGlobals::GetAssetManager()->GetDynamicBuffer(DVB_XYZ_TEX1_NORM_DIF); do { if( (nNumLockedVertice = pBufEntity->Lock((numTriangles*3 - nNumFinishedVertice), (void**)(&vb_vertices))) > 0) { int nLockedNum = nNumLockedVertice/3; int index; for(int i=0;i<nLockedNum;++i) { for(int k=0; k<3; ++k) { int nVB = 3*i+k; int n = nNumFinishedVertice+nVB; int v0=triangles[n]; index = vertexGroups[v0]; D3DXVec3TransformCoord(&vb_vertices[nVB].v,&vertices[v0],&matrixes[index]); D3DXVec3TransformNormal(&vb_vertices[nVB].n,&normals[v0],&matrixes[index]); vb_vertices[nVB].tu = uvs[v0].x; vb_vertices[nVB].tv = uvs[v0].y; vb_vertices[nVB].colour = (bHasTexture==FALSE ? colorModel : D3DCOLOR_COLORVALUE(1.0f,1.0f, 1.0f, 1.0f)); } } pBufEntity->Unlock(); DirectXPerf::DrawPrimitive( pd3dDevice, DirectXPerf::DRAW_PERF_TRIANGLES_MESH, D3DPT_TRIANGLELIST,pBufEntity->m_dwBase,nLockedNum); if((numTriangles*3 - nNumFinishedVertice) > nNumLockedVertice) { nNumFinishedVertice += nNumLockedVertice; } else break; } else break; }while(1); } }