/** * Creates a FStaticMeshRenderData from a D3DXMesh * @param DestMesh Destination mesh to extract to * @param NumUVs Number of UVs * @param Elements Elements array * @return Boolean representing success or failure */ bool ConvertD3DXMeshToRawMesh( TRefCountPtr<ID3DXMesh>& D3DMesh, FRawMesh& DestMesh, int32 NumUVs ) { // Extract simplified data to LOD FUtilVertex* D3DVertices; uint16* D3DIndices; ::DWORD * D3DAttributes; D3DMesh->LockVertexBuffer(D3DLOCK_READONLY,(LPVOID*)&D3DVertices); D3DMesh->LockIndexBuffer(D3DLOCK_READONLY,(LPVOID*)&D3DIndices); D3DMesh->LockAttributeBuffer(D3DLOCK_READONLY,&D3DAttributes); int32 NumFaces = D3DMesh->GetNumFaces(); int32 NumWedges = NumFaces * 3; DestMesh.FaceMaterialIndices.Init(NumFaces); DestMesh.FaceSmoothingMasks.Init(NumFaces); DestMesh.VertexPositions.Init(NumWedges); DestMesh.WedgeIndices.Init(NumWedges); DestMesh.WedgeColors.Init(NumWedges); DestMesh.WedgeTangentX.Init(NumWedges); DestMesh.WedgeTangentY.Init(NumWedges); DestMesh.WedgeTangentZ.Init(NumWedges); for (int32 UVIndex = 0; UVIndex < NumUVs; ++UVIndex) { DestMesh.WedgeTexCoords[UVIndex].Init(NumWedges); } for(int32 I=0;I<NumFaces;I++) { // Copy smoothing mask and index from any vertex into this triangle DestMesh.FaceSmoothingMasks[I] = D3DVertices[D3DIndices[I*3+0]].SmoothingMask; DestMesh.FaceMaterialIndices[I] = D3DAttributes[I]; for(int UVs=0;UVs<NumUVs;UVs++) { DestMesh.WedgeTexCoords[UVs][I*3+0] = D3DVertices[D3DIndices[I*3+0]].UVs[UVs]; DestMesh.WedgeTexCoords[UVs][I*3+1] = D3DVertices[D3DIndices[I*3+1]].UVs[UVs]; DestMesh.WedgeTexCoords[UVs][I*3+2] = D3DVertices[D3DIndices[I*3+2]].UVs[UVs]; } for(int32 K=0;K<3;K++) { DestMesh.WedgeIndices[I*3+K] = I*3+K; DestMesh.VertexPositions[I*3+K] = D3DVertices[D3DIndices[I*3+K]].Position; DestMesh.WedgeColors[I*3+K] = D3DVertices[D3DIndices[I*3+K]].Color; DestMesh.WedgeTangentX[I*3+K] = D3DVertices[D3DIndices[I*3+K]].TangentX; DestMesh.WedgeTangentY[I*3+K] = D3DVertices[D3DIndices[I*3+K]].TangentY; DestMesh.WedgeTangentZ[I*3+K] = D3DVertices[D3DIndices[I*3+K]].TangentZ; } } D3DMesh->UnlockIndexBuffer(); D3DMesh->UnlockVertexBuffer(); D3DMesh->UnlockAttributeBuffer(); return true; }
/** Merges a set of D3DXMeshes. */ static void MergeD3DXMeshes( IDirect3DDevice9* Device, TRefCountPtr<ID3DXMesh>& OutMesh,TArray<int32>& OutBaseFaceIndex,const TArray<ID3DXMesh*>& Meshes) { TArray<D3DVERTEXELEMENT9> VertexElements; GetD3D9MeshVertexDeclarations(VertexElements); // Count the number of faces and vertices in the input meshes. int32 NumFaces = 0; int32 NumVertices = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { NumFaces += Meshes[MeshIndex]->GetNumFaces(); NumVertices += Meshes[MeshIndex]->GetNumVertices(); } // Create mesh for source data VERIFYD3D9RESULT(D3DXCreateMesh( NumFaces, NumVertices, D3DXMESH_SYSTEMMEM, (D3DVERTEXELEMENT9*)VertexElements.GetData(), Device, OutMesh.GetInitReference() ) ); // Fill D3DXMesh FUtilVertex* ResultVertices; uint16* ResultIndices; ::DWORD * ResultAttributes; OutMesh->LockVertexBuffer(0,(LPVOID*)&ResultVertices); OutMesh->LockIndexBuffer(0,(LPVOID*)&ResultIndices); OutMesh->LockAttributeBuffer(0, &ResultAttributes); int32 BaseVertexIndex = 0; int32 BaseFaceIndex = 0; for(int32 MeshIndex = 0;MeshIndex < Meshes.Num();MeshIndex++) { ID3DXMesh* Mesh = Meshes[MeshIndex]; FUtilVertex* Vertices; uint16* Indices; ::DWORD * Attributes; Mesh->LockVertexBuffer(0,(LPVOID*)&Vertices); Mesh->LockIndexBuffer(0,(LPVOID*)&Indices); Mesh->LockAttributeBuffer(0, &Attributes); for(uint32 FaceIndex = 0;FaceIndex < Mesh->GetNumFaces();FaceIndex++) { for(uint32 VertexIndex = 0;VertexIndex < 3;VertexIndex++) { *ResultIndices++ = BaseVertexIndex + *Indices++; } } OutBaseFaceIndex.Add(BaseFaceIndex); BaseFaceIndex += Mesh->GetNumFaces(); FMemory::Memcpy(ResultVertices,Vertices,Mesh->GetNumVertices() * sizeof(FUtilVertex)); ResultVertices += Mesh->GetNumVertices(); BaseVertexIndex += Mesh->GetNumVertices(); FMemory::Memcpy(ResultAttributes,Attributes,Mesh->GetNumFaces() * sizeof(uint32)); ResultAttributes += Mesh->GetNumFaces(); Mesh->UnlockIndexBuffer(); Mesh->UnlockVertexBuffer(); Mesh->UnlockAttributeBuffer(); } OutMesh->UnlockIndexBuffer(); OutMesh->UnlockVertexBuffer(); OutMesh->UnlockAttributeBuffer(); }
/** * Creates a D3DXMESH from a FStaticMeshRenderData * @param Triangles The triangles to create the mesh from. * @param bRemoveDegenerateTriangles True if degenerate triangles should be removed * @param OutD3DMesh Mesh to create * @return Boolean representing success or failure */ bool ConvertRawMeshToD3DXMesh( IDirect3DDevice9* Device, FRawMesh& RawMesh, const bool bRemoveDegenerateTriangles, TRefCountPtr<ID3DXMesh>& OutD3DMesh ) { TArray<D3DVERTEXELEMENT9> VertexElements; GetD3D9MeshVertexDeclarations(VertexElements); TArray<FUtilVertex> Vertices; TArray<uint16> Indices; TArray<uint32> Attributes; int32 NumWedges = RawMesh.WedgeIndices.Num(); int32 NumTriangles = NumWedges / 3; int32 NumUVs = 0; for (; NumUVs < 8; ++NumUVs) { if (RawMesh.WedgeTexCoords[NumUVs].Num() != RawMesh.WedgeIndices.Num()) { break; } } bool bHaveColors = RawMesh.WedgeColors.Num() == NumWedges; bool bHaveNormals = RawMesh.WedgeTangentZ.Num() == NumWedges; bool bHaveTangents = bHaveNormals && RawMesh.WedgeTangentX.Num() == NumWedges && RawMesh.WedgeTangentY.Num() == NumWedges; for(int32 TriangleIndex = 0;TriangleIndex < NumTriangles;TriangleIndex++) { bool bTriangleIsDegenerate = false; if( bRemoveDegenerateTriangles ) { // Detect if the triangle is degenerate. for(int32 EdgeIndex = 0;EdgeIndex < 3;EdgeIndex++) { const int32 Wedge0 = TriangleIndex * 3 + EdgeIndex; const int32 Wedge1 = TriangleIndex * 3 + ((EdgeIndex + 1) % 3); if((RawMesh.GetWedgePosition(Wedge0) - RawMesh.GetWedgePosition(Wedge1)).IsNearlyZero(THRESH_POINTS_ARE_SAME * 4.0f)) { bTriangleIsDegenerate = true; break; } } } if(!bTriangleIsDegenerate) { Attributes.Add(RawMesh.FaceMaterialIndices[TriangleIndex]); for(int32 J=0;J<3;J++) { FUtilVertex* Vertex = new(Vertices) FUtilVertex; FMemory::Memzero(Vertex,sizeof(FUtilVertex)); int32 WedgeIndex = TriangleIndex * 3 + J; Vertex->Position = RawMesh.GetWedgePosition(WedgeIndex); if (bHaveColors) { Vertex->Color = RawMesh.WedgeColors[WedgeIndex]; } else { Vertex->Color = FColor::White; } //store the smoothing mask per vertex since there is only one per-face attribute that is already being used (materialIndex) Vertex->SmoothingMask = RawMesh.FaceSmoothingMasks[TriangleIndex]; if (bHaveTangents) { Vertex->TangentX = RawMesh.WedgeTangentX[WedgeIndex]; Vertex->TangentY = RawMesh.WedgeTangentY[WedgeIndex]; } if (bHaveNormals) { Vertex->TangentZ = RawMesh.WedgeTangentZ[WedgeIndex]; } for(int32 UVIndex = 0; UVIndex < NumUVs; UVIndex++) { Vertex->UVs[UVIndex] = RawMesh.WedgeTexCoords[UVIndex][WedgeIndex]; } Indices.Add(Vertices.Num() - 1); } } } // This code uses the raw triangles. Needs welding, etc. const int32 NumFaces = Indices.Num() / 3; const int32 NumVertices = NumFaces*3; check(Attributes.Num() == NumFaces); check(NumFaces * 3 == Indices.Num()); // Create mesh for source data if (FAILED(D3DXCreateMesh(NumFaces,NumVertices,D3DXMESH_SYSTEMMEM,(D3DVERTEXELEMENT9 *)VertexElements.GetData(),Device,OutD3DMesh.GetInitReference()) ) ) { UE_LOG(LogD3D9MeshUtils, Warning, TEXT("D3DXCreateMesh() Failed!")); return false; } // Fill D3DMesh mesh FUtilVertex* D3DVertices; uint16* D3DIndices; ::DWORD * D3DAttributes; OutD3DMesh->LockVertexBuffer(0,(LPVOID*)&D3DVertices); OutD3DMesh->LockIndexBuffer(0,(LPVOID*)&D3DIndices); OutD3DMesh->LockAttributeBuffer(0, &D3DAttributes); FMemory::Memcpy(D3DVertices,Vertices.GetTypedData(),Vertices.Num() * sizeof(FUtilVertex)); FMemory::Memcpy(D3DIndices,Indices.GetTypedData(),Indices.Num() * sizeof(uint16)); FMemory::Memcpy(D3DAttributes,Attributes.GetTypedData(),Attributes.Num() * sizeof(uint32)); OutD3DMesh->UnlockIndexBuffer(); OutD3DMesh->UnlockVertexBuffer(); OutD3DMesh->UnlockAttributeBuffer(); return true; }