/** * Constructs a raw mesh from legacy render data. */ static void BuildRawMeshFromRenderData( FRawMesh& OutRawMesh, struct FMeshBuildSettings& OutBuildSettings, FLegacyStaticMeshRenderData& RenderData, const TCHAR* MeshName ) { FStaticMeshTriangle* RawTriangles = (FStaticMeshTriangle*)RenderData.RawTriangles.Lock(LOCK_READ_ONLY); bool bBuiltFromRawTriangles = BuildRawMeshFromRawTriangles( OutRawMesh, OutBuildSettings, RawTriangles, RenderData.RawTriangles.GetElementCount(), MeshName ); RenderData.RawTriangles.Unlock(); if (bBuiltFromRawTriangles) { return; } OutRawMesh.Empty(); FIndexArrayView Indices = RenderData.IndexBuffer.GetArrayView(); int32 NumVertices = RenderData.PositionVertexBuffer.GetNumVertices(); int32 NumTriangles = Indices.Num() / 3; int32 NumWedges = NumTriangles * 3; // Copy vertex positions. { OutRawMesh.VertexPositions.AddUninitialized(NumVertices); for (int32 i = 0; i < NumVertices; ++i) { OutRawMesh.VertexPositions[i] = RenderData.PositionVertexBuffer.VertexPosition(i); } } // Copy per-wedge texture coordinates. for (uint32 TexCoordIndex = 0; TexCoordIndex < RenderData.VertexBuffer.GetNumTexCoords(); ++TexCoordIndex) { OutRawMesh.WedgeTexCoords[TexCoordIndex].AddUninitialized(NumWedges); for (int32 i = 0; i < NumWedges; ++i) { uint32 VertIndex = Indices[i]; OutRawMesh.WedgeTexCoords[TexCoordIndex][i] = RenderData.VertexBuffer.GetVertexUV(VertIndex, TexCoordIndex); } } // Copy per-wedge colors if they exist. if (RenderData.ColorVertexBuffer.GetNumVertices() > 0) { OutRawMesh.WedgeColors.AddUninitialized(NumWedges); for (int32 i = 0; i < NumWedges; ++i) { uint32 VertIndex = Indices[i]; OutRawMesh.WedgeColors[i] = RenderData.ColorVertexBuffer.VertexColor(VertIndex); } } // Copy per-wedge tangents. { OutRawMesh.WedgeTangentX.AddUninitialized(NumWedges); OutRawMesh.WedgeTangentY.AddUninitialized(NumWedges); OutRawMesh.WedgeTangentZ.AddUninitialized(NumWedges); for (int32 i = 0; i < NumWedges; ++i) { uint32 VertIndex = Indices[i]; OutRawMesh.WedgeTangentX[i] = RenderData.VertexBuffer.VertexTangentX(VertIndex); OutRawMesh.WedgeTangentY[i] = RenderData.VertexBuffer.VertexTangentY(VertIndex); OutRawMesh.WedgeTangentZ[i] = RenderData.VertexBuffer.VertexTangentZ(VertIndex); } } // Copy per-face information. { OutRawMesh.FaceMaterialIndices.AddZeroed(NumTriangles); OutRawMesh.FaceSmoothingMasks.AddZeroed(NumTriangles); OutRawMesh.WedgeIndices.AddZeroed(NumWedges); for (int32 SectionIndex = 0; SectionIndex < RenderData.Elements.Num(); ++SectionIndex) { const FLegacyStaticMeshElement& Section = RenderData.Elements[SectionIndex]; int32 FirstFace = Section.FirstIndex / 3; int32 LastFace = FirstFace + Section.NumTriangles; for (int32 i = FirstFace; i < LastFace; ++i) { OutRawMesh.FaceMaterialIndices[i] = Section.MaterialIndex; // Smoothing group information has been lost but is already baked in to the tangent basis. for (int32 j = 0; j < 3; ++j) { OutRawMesh.WedgeIndices[i * 3 + j] = Indices[i * 3 + j]; } } } } check(OutRawMesh.IsValid()); OutBuildSettings.bRecomputeNormals = false; OutBuildSettings.bRecomputeTangents = false; OutBuildSettings.bRemoveDegenerates = false; OutBuildSettings.bUseFullPrecisionUVs = RenderData.VertexBuffer.GetUseFullPrecisionUVs(); }
/** * Constructs a raw mesh from legacy raw triangles. */ static bool BuildRawMeshFromRawTriangles( FRawMesh& OutRawMesh, FMeshBuildSettings& OutBuildSettings, struct FStaticMeshTriangle* RawTriangles, int32 NumTriangles, const TCHAR* MeshName ) { int32 NumWedges = NumTriangles * 3; OutRawMesh.Empty(); OutRawMesh.FaceMaterialIndices.Empty(NumTriangles); OutRawMesh.FaceSmoothingMasks.Empty(NumWedges); OutRawMesh.VertexPositions.Empty(NumWedges); OutRawMesh.WedgeIndices.Empty(NumWedges); int32 NumTexCoords = 0; bool bHaveNormals = false; bool bHaveTangents = false; bool bHaveColors = false; bool bCorruptFlags = false; bool bCorruptNormals = false; bool bCorruptTangents = false; bool bCorruptPositions = false; for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex) { FStaticMeshTriangle* Tri = RawTriangles + TriIndex; OutRawMesh.FaceMaterialIndices.Add(Tri->MaterialIndex); OutRawMesh.FaceSmoothingMasks.Add(Tri->SmoothingMask); bCorruptFlags |= (RawTriangles[0].bExplicitNormals & 0xFFFFFFFE) != 0 || (RawTriangles[0].bOverrideTangentBasis & 0xFFFFFFFE) != 0; for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex) { FVector Position = Tri->Vertices[CornerIndex]; OutRawMesh.WedgeIndices.Add(OutRawMesh.VertexPositions.Add(Position)); NumTexCoords = FMath::Max(NumTexCoords, Tri->NumUVs); bHaveNormals |= Tri->TangentZ[CornerIndex] != FVector::ZeroVector; bHaveTangents |= (Tri->TangentX[CornerIndex] != FVector::ZeroVector && Tri->TangentY[CornerIndex] != FVector::ZeroVector); bHaveColors |= Tri->Colors[CornerIndex] != FColor::White; bCorruptPositions |= Position.ContainsNaN(); bCorruptTangents |= Tri->TangentX[CornerIndex].ContainsNaN() || Tri->TangentY[CornerIndex].ContainsNaN(); bCorruptNormals |= Tri->TangentZ[CornerIndex].ContainsNaN(); } } bool bTooManyTexCoords = NumTexCoords > 8; NumTexCoords = FMath::Min(NumTexCoords, 8); // FStaticMeshTriangle has at most 8 texture coordinates. NumTexCoords = FMath::Min<int32>(NumTexCoords, MAX_MESH_TEXTURE_COORDS); for (int32 TexCoordIndex = 0; TexCoordIndex < FMath::Max(1, NumTexCoords); ++TexCoordIndex) { OutRawMesh.WedgeTexCoords[TexCoordIndex].AddZeroed(NumTriangles * 3); } for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex) { FStaticMeshTriangle* Tri = RawTriangles + TriIndex; for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex) { for (int32 TexCoordIndex = 0; TexCoordIndex < NumTexCoords; ++TexCoordIndex) { FVector2D UV = TexCoordIndex < Tri->NumUVs ? Tri->UVs[CornerIndex][TexCoordIndex] : FVector2D(0.0f,0.0f); OutRawMesh.WedgeTexCoords[TexCoordIndex][TriIndex * 3 + CornerIndex] = UV; } } } if (bHaveNormals && !bCorruptNormals) { OutRawMesh.WedgeTangentZ.AddZeroed(NumTriangles * 3); for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex) { if (RawTriangles[TriIndex].bExplicitNormals || RawTriangles[TriIndex].bOverrideTangentBasis) { for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex) { OutRawMesh.WedgeTangentZ[TriIndex * 3 + CornerIndex] = RawTriangles[TriIndex].TangentZ[CornerIndex]; } } } } if (bHaveTangents && !bCorruptTangents) { OutRawMesh.WedgeTangentX.AddZeroed(NumTriangles * 3); OutRawMesh.WedgeTangentY.AddZeroed(NumTriangles * 3); for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex) { if (RawTriangles[TriIndex].bOverrideTangentBasis) { for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex) { OutRawMesh.WedgeTangentX[TriIndex * 3 + CornerIndex] = RawTriangles[TriIndex].TangentX[CornerIndex]; OutRawMesh.WedgeTangentY[TriIndex * 3 + CornerIndex] = RawTriangles[TriIndex].TangentY[CornerIndex]; } } } } if (bHaveColors) { OutRawMesh.WedgeColors.AddUninitialized(NumTriangles * 3); for (int32 TriIndex = 0; TriIndex < NumTriangles; ++TriIndex) { for (int32 CornerIndex = 0; CornerIndex < 3; ++CornerIndex) { OutRawMesh.WedgeColors[TriIndex * 3 + CornerIndex] = RawTriangles[TriIndex].Colors[CornerIndex]; } } } if (bCorruptPositions || bCorruptFlags || bCorruptNormals || bCorruptTangents || bTooManyTexCoords) { UE_LOG(LogStaticMesh,Verbose,TEXT("Legacy raw triangles CORRUPT (%s%s%s%s%s) for %s"), bCorruptPositions ? TEXT("NaN positions,") : TEXT(""), bCorruptFlags ? TEXT("flags,") : TEXT(""), bCorruptNormals ? TEXT("NaN normals,") : TEXT(""), bCorruptTangents ? TEXT("NaN tangents,") : TEXT(""), bTooManyTexCoords ? TEXT(">8 texcoords") : TEXT(""), MeshName ); } if (bCorruptPositions) { OutRawMesh = FRawMesh(); } OutBuildSettings.bRecomputeTangents = !bHaveTangents || bCorruptTangents; OutBuildSettings.bRecomputeNormals = !bHaveNormals || bCorruptNormals; return !(bCorruptPositions || bCorruptFlags || bTooManyTexCoords) && OutRawMesh.IsValid(); }