// Copyright Epic Games, Inc. All Rights Reserved. #include "MeshDescription.h" #include "Algo/Copy.h" #include "MeshAttributes.h" #include "Misc/SecureHash.h" #include "Serialization/BulkData.h" #include "Serialization/EditorBulkDataReader.h" #include "Serialization/EditorBulkDataWriter.h" #include "Serialization/LargeMemoryWriter.h" #include "Serialization/MemoryReader.h" #include "Serialization/MemoryWriter.h" #include "Serialization/NameAsStringProxyArchive.h" #include "UObject/EnterpriseObjectVersion.h" #include "UObject/UE5MainStreamObjectVersion.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(MeshDescription) #if WITH_EDITORONLY_DATA #include "DerivedDataBuildVersion.h" #endif #if WITH_EDITOR #include "Misc/ScopeRWLock.h" #endif FName FMeshDescription::VerticesName("Vertices"); FName FMeshDescription::VertexInstancesName("VertexInstances"); FName FMeshDescription::UVsName("UVs"); FName FMeshDescription::EdgesName("Edges"); FName FMeshDescription::TrianglesName("Triangles"); FName FMeshDescription::PolygonsName("Polygons"); FName FMeshDescription::PolygonGroupsName("PolygonGroups"); FMeshDescription::FMeshDescription() { Initialize(); } FMeshDescription::FMeshDescription(const FMeshDescription& Other) { Elements = Other.Elements; Cache(); } FMeshDescription& FMeshDescription::operator=(const FMeshDescription& Other) { if (this != &Other) { Elements = Other.Elements; Cache(); } return *this; } void FMeshDescription::Initialize() { // Register the basic mesh element types VertexElements = Elements.Emplace(VerticesName).Get(); VertexInstanceElements = Elements.Emplace(VertexInstancesName).Get(); UVElements = Elements.Emplace(UVsName).Get(); EdgeElements = Elements.Emplace(EdgesName).Get(); TriangleElements = Elements.Emplace(TrianglesName).Get(); PolygonElements = Elements.Emplace(PolygonsName).Get(); PolygonGroupElements = Elements.Emplace(PolygonGroupsName).Get(); // Now register topology-based attributes // Register vertex reference for vertex instances VertexInstanceVertices = VertexInstanceElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::VertexInstance::VertexIndex, 1, EMeshAttributeFlags::Mandatory); // Register vertex references for edges EdgeVertices = EdgeElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Edge::VertexIndex, 1, EMeshAttributeFlags::Mandatory); // Register vertex instance and polygon references for triangles TriangleVertexInstances = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::VertexInstanceIndex, 1, EMeshAttributeFlags::Mandatory); TrianglePolygons = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::PolygonIndex, 1, EMeshAttributeFlags::Mandatory); TrianglePolygonGroups = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::PolygonGroupIndex, 1, EMeshAttributeFlags::Mandatory); // Register UV references for triangles TriangleUVs = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::UVIndex, 0, EMeshAttributeFlags::Mandatory); // Register vertex and edge references for triangles; these are transient references which are generated at load time TriangleVertices = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::VertexIndex, 1, EMeshAttributeFlags::Mandatory | EMeshAttributeFlags::Transient); TriangleEdges = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::EdgeIndex, 1, EMeshAttributeFlags::Mandatory | EMeshAttributeFlags::Transient); // Register polygon group reference for polygons PolygonPolygonGroups = PolygonElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Polygon::PolygonGroupIndex, 1, EMeshAttributeFlags::Mandatory); // Minimal requirement is that vertices have a Position attribute VertexPositions = VertexElements->Get().GetAttributes().RegisterAttribute(MeshAttribute::Vertex::Position, 1, FVector3f::ZeroVector, EMeshAttributeFlags::Lerpable | EMeshAttributeFlags::Mandatory); // Register UVCoordinates attribute for UVs UVElements->Get().GetAttributes().RegisterAttribute(MeshAttribute::UV::UVCoordinate, 1, FVector2f::ZeroVector, EMeshAttributeFlags::Lerpable | EMeshAttributeFlags::Mandatory); // Associate indexers with element types and their referencing attributes InitializeIndexers(); } void FMeshDescription::InitializeIndexers() { // Vertices may typically have 6 vertex instances from the triangles which include them VertexToVertexInstances.SetInitialNumReferences(6); VertexToVertexInstances.Set(VertexElements, VertexInstanceElements, MeshAttribute::VertexInstance::VertexIndex); // Vertices may typically have 6 edges from the triangles which include them VertexToEdges.SetInitialNumReferences(6); VertexToEdges.Set(VertexElements, EdgeElements, MeshAttribute::Edge::VertexIndex); // @todo: VertexToTriangles? VertexInstanceToTriangles.Set(VertexInstanceElements, TriangleElements, MeshAttribute::Triangle::VertexInstanceIndex); // Assume most edges will have either 1 or 2 triangles EdgeToTriangles.SetInitialNumReferences(2); EdgeToTriangles.Set(EdgeElements, TriangleElements, MeshAttribute::Triangle::EdgeIndex); // UVs may typically be used by 6 adjacent triangles UVToTriangles.SetInitialNumReferences(6); UVToTriangles.Set(UVElements, TriangleElements, MeshAttribute::Triangle::UVIndex); // Assume most polygons are composed of only 1 triangle PolygonToTriangles.SetInitialNumReferences(1); PolygonToTriangles.Set(PolygonElements, TriangleElements, MeshAttribute::Triangle::PolygonIndex); // Polygon group indexers are a little different; in general there will be many back references and few keys, so set not to use chunks. PolygonGroupToTriangles.SetUnchunked(); PolygonGroupToPolygons.SetUnchunked(); PolygonGroupToTriangles.SetInitialNumReferences(256); PolygonGroupToPolygons.SetInitialNumReferences(256); PolygonGroupToTriangles.Set(PolygonGroupElements, TriangleElements, MeshAttribute::Triangle::PolygonGroupIndex); PolygonGroupToPolygons.Set(PolygonGroupElements, PolygonElements, MeshAttribute::Polygon::PolygonGroupIndex); } void FMeshDescription::Cache() { // Get pointers to element containers VertexElements = Elements.Find(VerticesName)->Get(); VertexInstanceElements = Elements.Find(VertexInstancesName)->Get(); UVElements = Elements.Find(UVsName)->Get(); EdgeElements = Elements.Find(EdgesName)->Get(); TriangleElements = Elements.Find(TrianglesName)->Get(); PolygonElements = Elements.Find(PolygonsName)->Get(); PolygonGroupElements = Elements.Find(PolygonGroupsName)->Get(); // Register required transient attributes TriangleVertices = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::VertexIndex, 1, EMeshAttributeFlags::Mandatory | EMeshAttributeFlags::Transient); TriangleEdges = TriangleElements->Get().GetAttributes().RegisterIndexAttribute(MeshAttribute::Triangle::EdgeIndex, 1, EMeshAttributeFlags::Mandatory | EMeshAttributeFlags::Transient); // Cache fundamental attribute arrays VertexInstanceVertices = VertexInstanceElements->Get().GetAttributes().GetAttributesRef(MeshAttribute::VertexInstance::VertexIndex); EdgeVertices = EdgeElements->Get().GetAttributes().GetAttributesRef>(MeshAttribute::Edge::VertexIndex); TriangleVertexInstances = TriangleElements->Get().GetAttributes().GetAttributesRef>(MeshAttribute::Triangle::VertexInstanceIndex); TrianglePolygons = TriangleElements->Get().GetAttributes().GetAttributesRef(MeshAttribute::Triangle::PolygonIndex); TrianglePolygonGroups = TriangleElements->Get().GetAttributes().GetAttributesRef(MeshAttribute::Triangle::PolygonGroupIndex); TriangleUVs = TriangleElements->Get().GetAttributes().GetAttributesRef>(MeshAttribute::Triangle::UVIndex); PolygonPolygonGroups = PolygonElements->Get().GetAttributes().GetAttributesRef(MeshAttribute::Polygon::PolygonGroupIndex); VertexPositions = VertexElements->Get().GetAttributes().GetAttributesRef(MeshAttribute::Vertex::Position); // Associate indexers with element types and their referencing attributes InitializeIndexers(); } void FMeshDescription::Serialize(FArchive& BaseAr) { FNameAsStringProxyArchive Ar(BaseAr); Ar.UsingCustomVersion(FReleaseObjectVersion::GUID); Ar.UsingCustomVersion(FEditorObjectVersion::GUID); Ar.UsingCustomVersion(FUE5MainStreamObjectVersion::GUID); if (Ar.IsLoading() && Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { UE_LOG(LogLoad, Warning, TEXT("Deprecated serialization format")); } if (Ar.IsLoading() && Ar.CustomVer(FReleaseObjectVersion::GUID) != FReleaseObjectVersion::MeshDescriptionNewFormat && Ar.CustomVer(FUE5MainStreamObjectVersion::GUID) < FUE5MainStreamObjectVersion::MeshDescriptionNewFormat) { // Serialize the old format data and transform it into the new format mesh element map SerializeLegacy(Ar); } else { Ar << Elements; // After loading elements, we need to re-cache mesh element and attribute arrays if (Ar.IsLoading()) { // Ensure there's a UV element container if (Elements.Find(UVsName) == nullptr) { UE_LOG(LogLoad, Warning, TEXT("Couldn't find UV element container in mesh - adding an empty one")); UVElements = Elements.Emplace(UVsName).Get(); } Cache(); for (FTriangleID TriangleID : TriangleElements->Get().GetElementIDs()) { for (int32 I = 0; I < 3; I++) { FVertexInstanceID VertexInstanceID = TriangleVertexInstances[TriangleID][I]; TriangleVertices[TriangleID][I] = VertexInstanceVertices[VertexInstanceID]; VertexInstanceToTriangles.AddReferenceToKey(VertexInstanceID, TriangleID); } for (int32 I = 0; I < 3; I++) { FEdgeID EdgeID = GetVertexPairEdge(TriangleVertices[TriangleID][I], TriangleVertices[TriangleID][(I+1) % 3]); TriangleEdges[TriangleID][I] = EdgeID; EdgeToTriangles.AddReferenceToKey(EdgeID, TriangleID); } } RebuildIndexers(); } } } struct FMeshVertex_Legacy { TArray VertexInstanceIDs; TArray ConnectedEdgeIDs; friend FArchive& operator<<(FArchive& Ar, FMeshVertex_Legacy& Vertex) { check(Ar.IsLoading()); if (Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { Ar << Vertex.VertexInstanceIDs; Ar << Vertex.ConnectedEdgeIDs; } return Ar; } }; struct FMeshVertexInstance_Legacy { FVertexID VertexID; TArray ConnectedTriangles; friend FArchive& operator<<(FArchive& Ar, FMeshVertexInstance_Legacy& VertexInstance) { check(Ar.IsLoading()); Ar << VertexInstance.VertexID; if (Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { TArray ConnectedPolygons_DISCARD; Ar << ConnectedPolygons_DISCARD; } return Ar; } }; struct FMeshEdge_Legacy { FVertexID VertexIDs[2]; TArray ConnectedTriangles; friend FArchive& operator<<(FArchive& Ar, FMeshEdge_Legacy& Edge) { check(Ar.IsLoading()); Ar << Edge.VertexIDs[0]; Ar << Edge.VertexIDs[1]; if (Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { TArray ConnectedPolygons_DISCARD; Ar << ConnectedPolygons_DISCARD; } return Ar; } }; struct FMeshTriangle_Legacy { FVertexInstanceID VertexInstanceIDs[3]; FPolygonID PolygonID; friend FArchive& operator<<(FArchive& Ar, FMeshTriangle_Legacy& Triangle) { check(Ar.IsLoading()); Ar << Triangle.VertexInstanceIDs[0]; Ar << Triangle.VertexInstanceIDs[1]; Ar << Triangle.VertexInstanceIDs[2]; if (Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { Ar << Triangle.PolygonID; } return Ar; } }; struct FMeshPolygon_Legacy { TArray VertexInstanceIDs; TArray TriangleIDs; FPolygonGroupID PolygonGroupID; friend FArchive& operator<<(FArchive& Ar, FMeshPolygon_Legacy& Polygon) { check(Ar.IsLoading()); Ar << Polygon.VertexInstanceIDs; if (Ar.CustomVer(FEditorObjectVersion::GUID) < FEditorObjectVersion::MeshDescriptionRemovedHoles) { TArray> Empty; Ar << Empty; } if (Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { TArray Triangles_DISCARD; Ar << Triangles_DISCARD; } Ar << Polygon.PolygonGroupID; return Ar; } }; struct FMeshPolygonGroup_Legacy { TArray Polygons; friend FArchive& operator<<(FArchive& Ar, FMeshPolygonGroup_Legacy& PolygonGroup) { check(Ar.IsLoading()); if (Ar.CustomVer(FReleaseObjectVersion::GUID) < FReleaseObjectVersion::MeshDescriptionNewSerialization) { Ar << PolygonGroup.Polygons; } return Ar; } }; template struct FFixAttributesSizeHelper { explicit FFixAttributesSizeHelper(int32 InExpectedNum) : ExpectedNum(InExpectedNum), bAllDefault(true) {} template void operator()(const FName AttributeName, TMeshAttributesRef> AttributeArrayRef) { // Not expecting arrays in legacy attributes check(false); } template void operator()(const FName AttributeName, TMeshAttributesRef> AttributeArrayRef) { // Not expecting arrays in legacy attributes check(false); } void operator()(const FName AttributeName, TMeshAttributesRef AttributeArrayRef) { // Not expecting FTransform in legacy attributes check(false); } template void operator()(const FName AttributeName, TMeshAttributesRef AttributeArrayRef) { if (bAllDefault) { for (int32 Channel = 0; Channel < AttributeArrayRef.GetNumChannels(); Channel++) { for (int32 Index = ExpectedNum; Index < AttributeArrayRef.GetNumElements(); Index++) { if (AttributeArrayRef.Get(T(Index), Channel) != AttributeArrayRef.GetDefaultValue()) { bAllDefault = false; return; } } } } } int32 ExpectedNum; bool bAllDefault; }; template void FixAttributesSize(int32 ExpectedNum, TAttributesSet& AttributesSet) { // Ensure that the attribute set is the same size as the mesh element array they describe // If there are extra elements, and they are not set to trivial defaults, this is an error. FFixAttributesSizeHelper Helper(ExpectedNum); AttributesSet.ForEach(Helper); check(Helper.bAllDefault); // If this fires, something is very wrong with the legacy asset AttributesSet.SetNumElements(ExpectedNum); } void FMeshDescription::SerializeLegacy(FArchive& Ar) { TMeshElementArray VertexArray; TMeshElementArray VertexInstanceArray; TMeshElementArray EdgeArray; TMeshElementArray TriangleArray; TMeshElementArray PolygonArray; TMeshElementArray PolygonGroupArray; TAttributesSet VertexAttributesSet; TAttributesSet VertexInstanceAttributesSet; TAttributesSet EdgeAttributesSet; TAttributesSet TriangleAttributesSet; TAttributesSet PolygonAttributesSet; TAttributesSet PolygonGroupAttributesSet; Ar << VertexArray; Ar << VertexInstanceArray; Ar << EdgeArray; Ar << PolygonArray; Ar << PolygonGroupArray; Ar << VertexAttributesSet; Ar << VertexInstanceAttributesSet; Ar << EdgeAttributesSet; Ar << PolygonAttributesSet; Ar << PolygonGroupAttributesSet; FixAttributesSize(VertexArray.GetArraySize(), VertexAttributesSet); FixAttributesSize(VertexInstanceArray.GetArraySize(), VertexInstanceAttributesSet); FixAttributesSize(EdgeArray.GetArraySize(), EdgeAttributesSet); FixAttributesSize(PolygonArray.GetArraySize(), PolygonAttributesSet); FixAttributesSize(PolygonGroupArray.GetArraySize(), PolygonGroupAttributesSet); // Serialize new triangle arrays since version MeshDescriptionTriangles if (Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { Ar << TriangleArray; Ar << TriangleAttributesSet; FixAttributesSize(TriangleArray.GetArraySize(), TriangleAttributesSet); } // Convert the old style element arrays into the new format // Completely reinitialize the mesh elements map as it is not being directly serialized into. Initialize(); for (FVertexID VertexID : VertexArray.GetElementIDs()) { VertexElements->Get().Insert(VertexID); } for (FVertexInstanceID VertexInstanceID : VertexInstanceArray.GetElementIDs()) { VertexInstanceElements->Get().Insert(VertexInstanceID); FVertexID VertexID = VertexInstanceArray[VertexInstanceID].VertexID; VertexInstanceVertices[VertexInstanceID] = VertexID; VertexToVertexInstances.AddReferenceToKey(VertexID, VertexInstanceID); } for (FEdgeID EdgeID : EdgeArray.GetElementIDs()) { EdgeElements->Get().Insert(EdgeID); FVertexID VertexID0 = EdgeArray[EdgeID].VertexIDs[0]; FVertexID VertexID1 = EdgeArray[EdgeID].VertexIDs[1]; EdgeVertices[EdgeID][0] = VertexID0; EdgeVertices[EdgeID][1] = VertexID1; VertexToEdges.AddReferenceToKey(VertexID0, EdgeID); VertexToEdges.AddReferenceToKey(VertexID1, EdgeID); } for (FPolygonGroupID PolygonGroupID : PolygonGroupArray.GetElementIDs()) { PolygonGroupElements->Get().Insert(PolygonGroupID); } for (FPolygonID PolygonID : PolygonArray.GetElementIDs()) { PolygonElements->Get().Insert(PolygonID); FPolygonGroupID PolygonGroupID = PolygonArray[PolygonID].PolygonGroupID; PolygonPolygonGroups[PolygonID] = PolygonGroupID; PolygonGroupToPolygons.AddReferenceToKey(PolygonGroupID, PolygonID); // If the asset is pre-triangles, we generate triangles here from the polygon if (Ar.CustomVer(FEditorObjectVersion::GUID) < FEditorObjectVersion::MeshDescriptionTriangles) { check(PolygonArray[PolygonID].VertexInstanceIDs.Num() >= 3); CreatePolygonTriangles(PolygonID, PolygonArray[PolygonID].VertexInstanceIDs); } } // Only do this if there were actually triangles in the asset if (Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { for (FTriangleID TriangleID : TriangleArray.GetElementIDs()) { TriangleElements->Get().Insert(TriangleID); FPolygonID PolygonID = TriangleArray[TriangleID].PolygonID; FPolygonGroupID PolygonGroupID = PolygonArray[PolygonID].PolygonGroupID; TrianglePolygons[TriangleID] = PolygonID; TrianglePolygonGroups[TriangleID] = PolygonGroupID; PolygonToTriangles.AddReferenceToKey(PolygonID, TriangleID); PolygonGroupToTriangles.AddReferenceToKey(PolygonGroupID, TriangleID); for (int32 I = 0; I < 3; I++) { FVertexInstanceID VertexInstanceID = TriangleArray[TriangleID].VertexInstanceIDs[I]; TriangleVertexInstances[TriangleID][I] = VertexInstanceID; TriangleVertices[TriangleID][I] = VertexInstanceVertices[VertexInstanceID]; VertexInstanceToTriangles.AddReferenceToKey(VertexInstanceID, TriangleID); } for (int32 I = 0; I < 3; I++) { FEdgeID EdgeID = GetVertexPairEdge(TriangleVertices[TriangleID][I], TriangleVertices[TriangleID][(I+1) % 3]); TriangleEdges[TriangleID][I] = EdgeID; EdgeToTriangles.AddReferenceToKey(EdgeID, TriangleID); } } } // Unregister the position attribute from the vertex elements, as it will come from the legacy data instead. VertexElements->Get().GetAttributes().UnregisterAttribute(MeshAttribute::Vertex::Position); // Add the legacy mesh attributes into the new containers VertexElements->Get().GetAttributes().AppendAttributesFrom(VertexAttributesSet); VertexInstanceElements->Get().GetAttributes().AppendAttributesFrom(VertexInstanceAttributesSet); EdgeElements->Get().GetAttributes().AppendAttributesFrom(EdgeAttributesSet); PolygonElements->Get().GetAttributes().AppendAttributesFrom(PolygonAttributesSet); PolygonGroupElements->Get().GetAttributes().AppendAttributesFrom(PolygonGroupAttributesSet); if (Ar.CustomVer(FEditorObjectVersion::GUID) >= FEditorObjectVersion::MeshDescriptionTriangles) { TriangleElements->Get().GetAttributes().AppendAttributesFrom(TriangleAttributesSet); } Cache(); BuildIndexers(); } void FMeshDescription::ResetIndexers() { VertexToVertexInstances.Reset(); VertexToEdges.Reset(); VertexInstanceToTriangles.Reset(); EdgeToTriangles.Reset(); UVToTriangles.Reset(); PolygonToTriangles.Reset(); PolygonGroupToTriangles.Reset(); PolygonGroupToPolygons.Reset(); } void FMeshDescription::BuildIndexers() { VertexToVertexInstances.Build(); VertexToEdges.Build(); VertexInstanceToTriangles.Build(); EdgeToTriangles.Build(); UVToTriangles.Build(); PolygonToTriangles.Build(); PolygonGroupToTriangles.Build(); PolygonGroupToPolygons.Build(); } void FMeshDescription::RebuildIndexers() { VertexToVertexInstances.ForceRebuild(); VertexToEdges.ForceRebuild(); VertexInstanceToTriangles.ForceRebuild(); EdgeToTriangles.ForceRebuild(); UVToTriangles.ForceRebuild(); PolygonToTriangles.ForceRebuild(); PolygonGroupToTriangles.ForceRebuild(); PolygonGroupToPolygons.ForceRebuild(); } void FMeshDescription::Empty() { for (TPair& ElementsItem: Elements) { ElementsItem.Value.Get()->Reset(); } ResetIndexers(); } bool FMeshDescription::IsEmpty() const { for (const TPair& ElementsItem: Elements) { if (!ElementsItem.Value.Get()->IsEmpty()) { return false; } } return true; } bool FMeshDescription::NeedsCompact() const { return ( VertexElements->Get().GetArraySize() != VertexElements->Get().Num() || VertexInstanceElements->Get().GetArraySize() != VertexInstanceElements->Get().Num() || EdgeElements->Get().GetArraySize() != EdgeElements->Get().Num() || TriangleElements->Get().GetArraySize() != TriangleElements->Get().Num() || PolygonElements->Get().GetArraySize() != PolygonElements->Get().Num() || PolygonGroupElements->Get().GetArraySize() != PolygonGroupElements->Get().Num() ); } void FMeshDescription::Compact(FElementIDRemappings& OutRemappings) { VertexElements->Get().Compact(OutRemappings.NewVertexIndexLookup); VertexInstanceElements->Get().Compact(OutRemappings.NewVertexInstanceIndexLookup); EdgeElements->Get().Compact(OutRemappings.NewEdgeIndexLookup); TriangleElements->Get().Compact(OutRemappings.NewTriangleIndexLookup); PolygonElements->Get().Compact(OutRemappings.NewPolygonIndexLookup); PolygonGroupElements->Get().Compact(OutRemappings.NewPolygonGroupIndexLookup); FixUpElementIDs(OutRemappings); } void FMeshDescription::Remap(const FElementIDRemappings& Remappings) { VertexElements->Get().Remap(Remappings.NewVertexIndexLookup); VertexInstanceElements->Get().Remap(Remappings.NewVertexInstanceIndexLookup); EdgeElements->Get().Remap(Remappings.NewEdgeIndexLookup); TriangleElements->Get().Remap(Remappings.NewTriangleIndexLookup); PolygonElements->Get().Remap(Remappings.NewPolygonIndexLookup); PolygonGroupElements->Get().Remap(Remappings.NewPolygonGroupIndexLookup); FixUpElementIDs(Remappings); } void FMeshDescription::FixUpElementIDs(const FElementIDRemappings& Remappings) { // Fix up vertex index references in vertex instance array for (const FVertexInstanceID VertexInstanceID : VertexInstanceElements->Get().GetElementIDs()) { VertexInstanceVertices[VertexInstanceID] = Remappings.GetRemappedVertexID(VertexInstanceVertices[VertexInstanceID]); } for (const FEdgeID EdgeID : EdgeElements->Get().GetElementIDs()) { // Fix up vertex index references in Edges array for (int32 Index = 0; Index < 2; Index++) { EdgeVertices[EdgeID][Index] = Remappings.GetRemappedVertexID(EdgeVertices[EdgeID][Index]); } } for (const FTriangleID TriangleID : TriangleElements->Get().GetElementIDs()) { // Fix up vertex instance references in Triangle for (int32 Index = 0; Index < 3; Index++) { TriangleVertexInstances[TriangleID][Index] = Remappings.GetRemappedVertexInstanceID(TriangleVertexInstances[TriangleID][Index]); TriangleEdges[TriangleID][Index] = Remappings.GetRemappedEdgeID(TriangleEdges[TriangleID][Index]); TriangleVertices[TriangleID][Index] = Remappings.GetRemappedVertexID(TriangleVertices[TriangleID][Index]); } TrianglePolygons[TriangleID] = Remappings.GetRemappedPolygonID(TrianglePolygons[TriangleID]); TrianglePolygonGroups[TriangleID] = Remappings.GetRemappedPolygonGroupID(TrianglePolygonGroups[TriangleID]); } for (const FPolygonID PolygonID : PolygonElements->Get().GetElementIDs()) { PolygonPolygonGroups[PolygonID] = Remappings.GetRemappedPolygonGroupID(PolygonPolygonGroups[PolygonID]); } RebuildIndexers(); } void FMeshDescription::CreateVertexInstance_Internal(const FVertexInstanceID VertexInstanceID, const FVertexID VertexID) { VertexInstanceVertices[VertexInstanceID] = VertexID; VertexToVertexInstances.AddReferenceToKey(VertexID, VertexInstanceID); } template