// Copyright Epic Games, Inc. All Rights Reserved. #include "MeshDescription.h" #include "MeshAttributes.h" #include "Algo/Copy.h" #include "Misc/SecureHash.h" #include "Serialization/BulkDataReader.h" #include "Serialization/BulkDataWriter.h" #include "UObject/EnterpriseObjectVersion.h" void UDEPRECATED_MeshDescription::Serialize(FArchive& Ar) { Super::Serialize(Ar); if (!HasAnyFlags(RF_ClassDefaultObject)) { UE_LOG(LogLoad, Error, TEXT( "UMeshDescription about to be deprecated - please resave %s"), *GetPathName()); } // Discard the contents FMeshDescription MeshDescription; Ar << MeshDescription; } FMeshDescription::FMeshDescription() { // Minimal requirement is that vertices have a Position attribute VertexAttributesSet.RegisterAttribute(MeshAttribute::Vertex::Position, 1, FVector::ZeroVector, EMeshAttributeFlags::Lerpable); } void FMeshDescription::Serialize(FArchive& Ar) { Ar.UsingCustomVersion(FReleaseObjectVersion::GUID); Ar.UsingCustomVersion(FEditorObjectVersion::GUID); if (Ar.IsLoading() && Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { UE_LOG(LogLoad, Warning, TEXT("Deprecated serialization format")); } Ar << VertexArray; Ar << VertexInstanceArray; Ar << EdgeArray; Ar << PolygonArray; Ar << PolygonGroupArray; Ar << VertexAttributesSet; Ar << VertexInstanceAttributesSet; Ar << EdgeAttributesSet; Ar << PolygonAttributesSet; Ar << PolygonGroupAttributesSet; // Serialize new triangle arrays since version MeshDescriptionTriangles if (!Ar.IsLoading() || Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { Ar << TriangleArray; Ar << TriangleAttributesSet; } if (Ar.IsLoading() && Ar.CustomVer(FReleaseObjectVersion::GUID) >= FReleaseObjectVersion::MeshDescriptionNewSerialization) { // Populate vertex instance IDs for vertices for (const FVertexInstanceID VertexInstanceID : VertexInstanceArray.GetElementIDs()) { const FVertexID VertexID = GetVertexInstanceVertex(VertexInstanceID); VertexArray[VertexID].VertexInstanceIDs.Add(VertexInstanceID); } // Populate edge IDs for vertices for (const FEdgeID EdgeID : EdgeArray.GetElementIDs()) { const FVertexID VertexID0 = GetEdgeVertex(EdgeID, 0); const FVertexID VertexID1 = GetEdgeVertex(EdgeID, 1); VertexArray[VertexID0].ConnectedEdgeIDs.Add(EdgeID); VertexArray[VertexID1].ConnectedEdgeIDs.Add(EdgeID); } if (Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { // Make reverse connection from polygons to triangles for (const FTriangleID TriangleID : TriangleArray.GetElementIDs()) { const FPolygonID PolygonID = TriangleArray[TriangleID].PolygonID; PolygonArray[PolygonID].TriangleIDs.Add(TriangleID); } } // Populate polygon IDs for vertex instances, edges and polygon groups for (const FPolygonID PolygonID : PolygonArray.GetElementIDs()) { if (Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { // If the polygon has no contour serialized, copy it over from the triangle if (PolygonArray[PolygonID].VertexInstanceIDs.Num() == 0) { check(PolygonArray[PolygonID].TriangleIDs.Num() == 1); const FTriangleID TriangleID = PolygonArray[PolygonID].TriangleIDs[0]; for (int32 Index = 0; Index < 3; Index++) { PolygonArray[PolygonID].VertexInstanceIDs.Add(TriangleArray[TriangleID].GetVertexInstanceID(Index)); } } } const FPolygonGroupID PolygonGroupID = PolygonArray[PolygonID].PolygonGroupID; PolygonGroupArray[PolygonGroupID].Polygons.Add(PolygonID); } } if (Ar.IsLoading()) { if (Ar.CustomVer(FEditorObjectVersion::GUID) < FEditorObjectVersion::MeshDescriptionTriangles) { TriangleArray.Reset(); // If we didn't serialize triangles, generate them from the polygon contour for (const FPolygonID PolygonID : PolygonArray.GetElementIDs()) { check(PolygonArray[PolygonID].TriangleIDs.Num() == 0); ComputePolygonTriangulation(PolygonID); } } else { // Otherwise connect existing triangles to vertex instances and edges for (const FTriangleID TriangleID : TriangleArray.GetElementIDs()) { for (int32 Index = 0; Index < 3; ++Index) { const FVertexInstanceID VertexInstanceID = GetTriangleVertexInstance(TriangleID, Index); const FVertexInstanceID NextVertexInstanceID = GetTriangleVertexInstance(TriangleID, (Index + 1 == 3) ? 0 : Index + 1); const FVertexID VertexID0 = GetVertexInstanceVertex(VertexInstanceID); const FVertexID VertexID1 = GetVertexInstanceVertex(NextVertexInstanceID); FEdgeID EdgeID = GetVertexPairEdge(VertexID0, VertexID1); check(EdgeID != FEdgeID::Invalid); VertexInstanceArray[VertexInstanceID].ConnectedTriangles.Add(TriangleID); EdgeArray[EdgeID].ConnectedTriangles.Add(TriangleID); } } } } } void FMeshDescription::Empty() { VertexArray.Reset(); VertexInstanceArray.Reset(); EdgeArray.Reset(); TriangleArray.Reset(); PolygonArray.Reset(); PolygonGroupArray.Reset(); // Empty all attributes VertexAttributesSet.Initialize(0); VertexInstanceAttributesSet.Initialize(0); EdgeAttributesSet.Initialize(0); TriangleAttributesSet.Initialize(0); PolygonAttributesSet.Initialize(0); PolygonGroupAttributesSet.Initialize(0); } bool FMeshDescription::IsEmpty() const { return VertexArray.GetArraySize() == 0 && VertexInstanceArray.GetArraySize() == 0 && EdgeArray.GetArraySize() == 0 && TriangleArray.GetArraySize() == 0 && PolygonArray.GetArraySize() == 0 && PolygonGroupArray.GetArraySize() == 0; } void FMeshDescription::Compact(FElementIDRemappings& OutRemappings) { VertexArray.Compact(OutRemappings.NewVertexIndexLookup); VertexInstanceArray.Compact(OutRemappings.NewVertexInstanceIndexLookup); EdgeArray.Compact(OutRemappings.NewEdgeIndexLookup); TriangleArray.Compact(OutRemappings.NewTriangleIndexLookup); PolygonArray.Compact(OutRemappings.NewPolygonIndexLookup); PolygonGroupArray.Compact(OutRemappings.NewPolygonGroupIndexLookup); RemapAttributes(OutRemappings); FixUpElementIDs(OutRemappings); } void FMeshDescription::Remap(const FElementIDRemappings& Remappings) { VertexArray.Remap(Remappings.NewVertexIndexLookup); VertexInstanceArray.Remap(Remappings.NewVertexInstanceIndexLookup); EdgeArray.Remap(Remappings.NewEdgeIndexLookup); TriangleArray.Remap(Remappings.NewTriangleIndexLookup); PolygonArray.Remap(Remappings.NewPolygonIndexLookup); PolygonGroupArray.Remap(Remappings.NewPolygonGroupIndexLookup); RemapAttributes(Remappings); FixUpElementIDs(Remappings); } void FMeshDescription::RemapAttributes(const FElementIDRemappings& Remappings) { VertexAttributesSet.Remap(Remappings.NewVertexIndexLookup); VertexInstanceAttributesSet.Remap(Remappings.NewVertexInstanceIndexLookup); EdgeAttributesSet.Remap(Remappings.NewEdgeIndexLookup); TriangleAttributesSet.Remap(Remappings.NewTriangleIndexLookup); PolygonAttributesSet.Remap(Remappings.NewPolygonIndexLookup); PolygonGroupAttributesSet.Remap(Remappings.NewPolygonGroupIndexLookup); } void FMeshDescription::FixUpElementIDs(const FElementIDRemappings& Remappings) { for (const FVertexID VertexID : VertexArray.GetElementIDs()) { FMeshVertex& Vertex = VertexArray[VertexID]; // Fix up vertex instance index references in vertices array for (FVertexInstanceID& VertexInstanceID : Vertex.VertexInstanceIDs) { VertexInstanceID = Remappings.GetRemappedVertexInstanceID(VertexInstanceID); } // Fix up edge index references in the vertex array for (FEdgeID& EdgeID : Vertex.ConnectedEdgeIDs) { EdgeID = Remappings.GetRemappedEdgeID(EdgeID); } } // Fix up vertex index references in vertex instance array for (const FVertexInstanceID VertexInstanceID : VertexInstanceArray.GetElementIDs()) { FMeshVertexInstance& VertexInstance = VertexInstanceArray[VertexInstanceID]; VertexInstance.VertexID = Remappings.GetRemappedVertexID(VertexInstance.VertexID); for (FTriangleID& TriangleID : VertexInstance.ConnectedTriangles) { TriangleID = Remappings.GetRemappedTriangleID(TriangleID); } } for (const FEdgeID EdgeID : EdgeArray.GetElementIDs()) { FMeshEdge& Edge = EdgeArray[EdgeID]; // Fix up vertex index references in Edges array for (int32 Index = 0; Index < 2; Index++) { Edge.VertexIDs[Index] = Remappings.GetRemappedVertexID(Edge.VertexIDs[Index]); } for (FTriangleID& TriangleID : Edge.ConnectedTriangles) { TriangleID = Remappings.GetRemappedTriangleID(TriangleID); } } for (const FTriangleID TriangleID : TriangleArray.GetElementIDs()) { FMeshTriangle& Triangle = TriangleArray[TriangleID]; // Fix up vertex instance references in Triangle for (FVertexInstanceID& VertexInstanceID : Triangle.VertexInstanceIDs) { VertexInstanceID = Remappings.GetRemappedVertexInstanceID(VertexInstanceID); } Triangle.PolygonID = Remappings.GetRemappedPolygonID(Triangle.PolygonID); } for (const FPolygonID PolygonID : PolygonArray.GetElementIDs()) { FMeshPolygon& Polygon = PolygonArray[PolygonID]; // Fix up references to vertex indices in section polygons' contours for (FVertexInstanceID& VertexInstanceID : Polygon.VertexInstanceIDs) { VertexInstanceID = Remappings.GetRemappedVertexInstanceID(VertexInstanceID); } for (FTriangleID& TriangleID : Polygon.TriangleIDs) { TriangleID = Remappings.GetRemappedTriangleID(TriangleID); } Polygon.PolygonGroupID = Remappings.GetRemappedPolygonGroupID(Polygon.PolygonGroupID); } for (const FPolygonGroupID PolygonGroupID : PolygonGroupArray.GetElementIDs()) { FMeshPolygonGroup& PolygonGroup = PolygonGroupArray[PolygonGroupID]; for (FPolygonID& Polygon : PolygonGroup.Polygons) { Polygon = Remappings.GetRemappedPolygonID(Polygon); } } } void FMeshDescription::CreateVertexInstance_Internal(const FVertexInstanceID VertexInstanceID, const FVertexID VertexID) { VertexInstanceArray[VertexInstanceID].VertexID = VertexID; check(!VertexArray[VertexID].VertexInstanceIDs.Contains(VertexInstanceID)); VertexArray[VertexID].VertexInstanceIDs.Add(VertexInstanceID); VertexInstanceAttributesSet.Insert(VertexInstanceID); } template