Files
UnrealEngine/Engine/Plugins/Editor/ProxyLODPlugin/Source/ProxyLOD/Private/ProxyLODMeshConvertUtils.cpp
2025-05-18 13:04:45 +08:00

602 lines
22 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ProxyLODMeshConvertUtils.h"
#include "ProxyLODMeshUtilities.h"
#include "StaticMeshOperations.h"
static void ResetStaticMeshDescription(FMeshDescription& MeshDecription)
{
MeshDecription.Empty();
FStaticMeshAttributes Attributes(MeshDecription);
Attributes.Register();
}
// Convert QuadMesh to Triangles by splitting
void ProxyLOD::MixedPolyMeshToRawMesh(const FMixedPolyMesh& SimpleMesh, FMeshDescription& DstRawMesh)
{
TRACE_CPUPROFILER_EVENT_SCOPE(ProxyLOD::MixedPolyMeshToRawMesh)
ResetStaticMeshDescription(DstRawMesh);
FStaticMeshAttributes Attributes(DstRawMesh);
TVertexAttributesRef<FVector3f> VertexPositions = Attributes.GetVertexPositions();
TEdgeAttributesRef<bool> EdgeHardnesses = Attributes.GetEdgeHardnesses();
TPolygonGroupAttributesRef<FName> PolygonGroupImportedMaterialSlotNames = Attributes.GetPolygonGroupMaterialSlotNames();
TVertexInstanceAttributesRef<FVector3f> VertexInstanceNormals = Attributes.GetVertexInstanceNormals();
TVertexInstanceAttributesRef<FVector3f> VertexInstanceTangents = Attributes.GetVertexInstanceTangents();
TVertexInstanceAttributesRef<float> VertexInstanceBinormalSigns = Attributes.GetVertexInstanceBinormalSigns();
TVertexInstanceAttributesRef<FVector4f> VertexInstanceColors = Attributes.GetVertexInstanceColors();
TVertexInstanceAttributesRef<FVector2f> VertexInstanceUVs = Attributes.GetVertexInstanceUVs();
// Splitting a quad doesn't introduce any new verts.
const uint32 DstNumVerts = SimpleMesh.Points.size();
const uint32 NumQuads = SimpleMesh.Quads.size();
// Each quad becomes 2 triangles.
const uint32 DstNumTris = 2 * NumQuads + SimpleMesh.Triangles.size();
// Each Triangle has 3 corners
const uint32 DstNumIndexes = 3 * DstNumTris;
if (VertexInstanceUVs.GetNumChannels() < 1)
{
VertexInstanceUVs.SetNumChannels(1);
}
FPolygonGroupID PolygonGroupID = INDEX_NONE;
if (DstRawMesh.PolygonGroups().Num() == 0)
{
PolygonGroupID = DstRawMesh.CreatePolygonGroup();
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = FName(*FString::Printf(TEXT("ProxyLOD_Material_%d"), FMath::Rand()));
}
else
{
PolygonGroupID = DstRawMesh.PolygonGroups().GetFirstValidID();
}
// Copy the vertices over
TMap<int32, FVertexID> VertexIDMap;
VertexIDMap.Reserve(DstNumVerts);
{
for (uint32 i = 0, I = DstNumVerts; i < I; ++i)
{
const openvdb::Vec3s& Vertex = SimpleMesh.Points[i];
const FVertexID NewVertexID = DstRawMesh.CreateVertex();
VertexPositions[NewVertexID] = FVector3f(Vertex[0], Vertex[1], Vertex[2]);
VertexIDMap.Add(i, NewVertexID);
}
}
// Connectivity:
auto CreateTriangle = [&DstRawMesh, PolygonGroupID, &VertexInstanceNormals, &VertexInstanceTangents, &VertexInstanceBinormalSigns, &VertexInstanceColors, &VertexInstanceUVs, &EdgeHardnesses](FVertexID TriangleIndex[3])
{
TArray<FVertexInstanceID> VertexInstanceIDs;
VertexInstanceIDs.SetNum(3);
for (int32 Corner = 0; Corner < 3; ++Corner)
{
VertexInstanceIDs[Corner] = DstRawMesh.CreateVertexInstance(TriangleIndex[Corner]);
VertexInstanceTangents[VertexInstanceIDs[Corner]] = FVector3f(1, 0, 0);
VertexInstanceNormals[VertexInstanceIDs[Corner]] = FVector3f(0, 0, 1);
VertexInstanceBinormalSigns[VertexInstanceIDs[Corner]] = GetBasisDeterminantSign((FVector)VertexInstanceTangents[VertexInstanceIDs[Corner]].GetSafeNormal(),
(FVector)(VertexInstanceNormals[VertexInstanceIDs[Corner]] ^ VertexInstanceTangents[VertexInstanceIDs[Corner]]).GetSafeNormal(),
(FVector)VertexInstanceNormals[VertexInstanceIDs[Corner]].GetSafeNormal());
VertexInstanceColors[VertexInstanceIDs[Corner]] = FVector4f(0.0f);
VertexInstanceUVs.Set(VertexInstanceIDs[Corner], 0, FVector2f(0.0f, 0.0f));
}
// Insert a polygon into the mesh
DstRawMesh.CreatePolygon(PolygonGroupID, VertexInstanceIDs);
};
{
for (uint32 q = 0, Q = NumQuads; q < Q; ++q)
{
const openvdb::Vec4I& Quad = SimpleMesh.Quads[q];
// add as two triangles to raw mesh
bool bClockWiseTriangle = true;
#if (PROXYLOD_CLOCKWISE_TRIANGLES != 1)
bClockWiseTriangle = false;
#endif
FVertexID VertexIndexes[3];
VertexIndexes[0] = VertexIDMap[Quad[0]];
VertexIndexes[1] = bClockWiseTriangle ? VertexIDMap[Quad[1]] : VertexIDMap[Quad[3]];
VertexIndexes[2] = VertexIDMap[Quad[2]];
CreateTriangle(VertexIndexes);
VertexIndexes[0] = VertexIDMap[Quad[2]];
VertexIndexes[1] = bClockWiseTriangle ? VertexIDMap[Quad[3]] : VertexIDMap[Quad[1]];
VertexIndexes[2] = VertexIDMap[Quad[0]];
CreateTriangle(VertexIndexes);
}
// add the SimpleMesh triangles.
uint32 IndexStop = SimpleMesh.Triangles.size();
for (uint32 t = 0, T = IndexStop; t < T; ++t)
{
const openvdb::Vec3I& Tri = SimpleMesh.Triangles[t];
bool bClockWiseTriangle = true;
#if (PROXYLOD_CLOCKWISE_TRIANGLES != 1)
bClockWiseTriangle = false;
#endif
FVertexID VertexIndexes[3];
VertexIndexes[0] = bClockWiseTriangle ? VertexIDMap[Tri[0]] : VertexIDMap[Tri[2]];
VertexIndexes[1] = VertexIDMap[Tri[1]];
VertexIndexes[2] = bClockWiseTriangle ? VertexIDMap[Tri[2]] : VertexIDMap[Tri[0]];
CreateTriangle(VertexIndexes);
}
}
}
void ProxyLOD::AOSMeshToRawMesh(const FAOSMesh& AOSMesh, FMeshDescription& OutRawMesh)
{
ResetStaticMeshDescription(OutRawMesh);
FStaticMeshAttributes Attributes(OutRawMesh);
TVertexAttributesRef<FVector3f> VertexPositions = Attributes.GetVertexPositions();
TEdgeAttributesRef<bool> EdgeHardnesses = Attributes.GetEdgeHardnesses();
TPolygonGroupAttributesRef<FName> PolygonGroupImportedMaterialSlotNames = Attributes.GetPolygonGroupMaterialSlotNames();
TVertexInstanceAttributesRef<FVector3f> VertexInstanceNormals = Attributes.GetVertexInstanceNormals();
TVertexInstanceAttributesRef<FVector3f> VertexInstanceTangents = Attributes.GetVertexInstanceTangents();
TVertexInstanceAttributesRef<float> VertexInstanceBinormalSigns = Attributes.GetVertexInstanceBinormalSigns();
TVertexInstanceAttributesRef<FVector4f> VertexInstanceColors = Attributes.GetVertexInstanceColors();
TVertexInstanceAttributesRef<FVector2f> VertexInstanceUVs = Attributes.GetVertexInstanceUVs();
const uint32 DstNumPositions = AOSMesh.GetNumVertexes();
const uint32 DstNumIndexes = AOSMesh.GetNumIndexes();
if (VertexInstanceUVs.GetNumChannels() < 1)
{
VertexInstanceUVs.SetNumChannels(1);
}
FPolygonGroupID PolygonGroupID = INDEX_NONE;
if (OutRawMesh.PolygonGroups().Num() == 0)
{
PolygonGroupID = OutRawMesh.CreatePolygonGroup();
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = FName(*FString::Printf(TEXT("ProxyLOD_Material_%d"), FMath::Rand()));
}
else
{
PolygonGroupID = OutRawMesh.PolygonGroups().GetFirstValidID();
}
checkSlow(DstNumIndexes % 3 == 0);
// Copy the vertices over
TMap<int32, FVertexID> VertexIDMap;
VertexIDMap.Reserve(DstNumPositions);
{
const auto& AOSVertexes = AOSMesh.Vertexes;
for (uint32 i = 0, I = DstNumPositions; i < I; ++i)
{
const FVector3f& Position = AOSVertexes[i].GetPos();
const FVertexID NewVertexID = OutRawMesh.CreateVertex();
VertexPositions[NewVertexID] = Position;
VertexIDMap.Add(i, NewVertexID);
}
checkSlow(VertexPositions.GetNumElements() == DstNumPositions);
}
const uint32* AOSIndexes = AOSMesh.Indexes;
// Connectivity:
auto CreateTriangle = [&OutRawMesh, PolygonGroupID, &VertexInstanceNormals, &VertexInstanceTangents, &VertexInstanceBinormalSigns, &VertexInstanceColors, &VertexInstanceUVs, &EdgeHardnesses](const FVertexID TriangleIndex[3], const FVector3f Normals[3])
{
TArray<FVertexInstanceID> VertexInstanceIDs;
VertexInstanceIDs.SetNum(3);
for (int32 Corner = 0; Corner < 3; ++Corner)
{
VertexInstanceIDs[Corner] = OutRawMesh.CreateVertexInstance(TriangleIndex[Corner]);
VertexInstanceTangents[VertexInstanceIDs[Corner]] = FVector3f(1, 0, 0);
VertexInstanceNormals[VertexInstanceIDs[Corner]] = Normals[Corner];
VertexInstanceBinormalSigns[VertexInstanceIDs[Corner]] = GetBasisDeterminantSign((FVector)VertexInstanceTangents[VertexInstanceIDs[Corner]].GetSafeNormal(),
(FVector)(VertexInstanceNormals[VertexInstanceIDs[Corner]] ^ VertexInstanceTangents[VertexInstanceIDs[Corner]]).GetSafeNormal(),
(FVector)VertexInstanceNormals[VertexInstanceIDs[Corner]].GetSafeNormal());
VertexInstanceColors[VertexInstanceIDs[Corner]] = FVector4f(1.0f);
VertexInstanceUVs.Set(VertexInstanceIDs[Corner], 0, FVector2f(0.0f, 0.0f));
}
// Insert a polygon into the mesh
OutRawMesh.CreatePolygon(PolygonGroupID, VertexInstanceIDs);
};
{
uint32 IndexStop = DstNumIndexes/3;
for (uint32 t = 0, T = IndexStop; t < T; ++t)
{
FVertexID VertexIndexes[3];
FVector3f Normals[3];
for (int32 Corner = 0; Corner < 3; ++Corner)
{
VertexIndexes[Corner] = VertexIDMap[AOSIndexes[(t*3) + Corner]];
const auto& AOSVertex = AOSMesh.Vertexes[AOSIndexes[(t*3) + Corner]];
Normals[Corner] = AOSVertex.Normal;
}
CreateTriangle(VertexIndexes, Normals);
}
}
}
void ProxyLOD::VertexDataMeshToRawMesh(const FVertexDataMesh& SrcVertexDataMesh, FMeshDescription& OutRawMesh)
{
ResetStaticMeshDescription(OutRawMesh);
FStaticMeshAttributes Attributes(OutRawMesh);
TVertexAttributesRef<FVector3f> VertexPositions = Attributes.GetVertexPositions();
TEdgeAttributesRef<bool> EdgeHardnesses = Attributes.GetEdgeHardnesses();
TPolygonGroupAttributesRef<FName> PolygonGroupImportedMaterialSlotNames = Attributes.GetPolygonGroupMaterialSlotNames();
TVertexInstanceAttributesRef<FVector3f> VertexInstanceNormals = Attributes.GetVertexInstanceNormals();
TVertexInstanceAttributesRef<FVector3f> VertexInstanceTangents = Attributes.GetVertexInstanceTangents();
TVertexInstanceAttributesRef<float> VertexInstanceBinormalSigns = Attributes.GetVertexInstanceBinormalSigns();
TVertexInstanceAttributesRef<FVector4f> VertexInstanceColors = Attributes.GetVertexInstanceColors();
TVertexInstanceAttributesRef<FVector2f> VertexInstanceUVs = Attributes.GetVertexInstanceUVs();
const uint32 DstNumPositions = SrcVertexDataMesh.Points.Num();
const uint32 DstNumIndexes = SrcVertexDataMesh.Indices.Num();
const uint32 SrcNumTriangles = DstNumIndexes / 3;
FPolygonGroupID PolygonGroupID = INDEX_NONE;
if (OutRawMesh.PolygonGroups().Num() == 0)
{
PolygonGroupID = OutRawMesh.CreatePolygonGroup();
PolygonGroupImportedMaterialSlotNames[PolygonGroupID] = FName(*FString::Printf(TEXT("ProxyLOD_Material_%d"), FMath::Rand()));
}
else
{
PolygonGroupID = OutRawMesh.PolygonGroups().GetFirstValidID();
}
checkSlow(DstNumIndexes % 3 == 0);
// Copy the vertices over
TMap<int32, FVertexID> VertexIDMap;
VertexIDMap.Reserve(DstNumPositions);
{
const TArray<FVector3f>& SrcPositions = SrcVertexDataMesh.Points;
for (uint32 i = 0, I = DstNumPositions; i < I; ++i)
{
const FVector3f& Position = SrcPositions[i];
const FVertexID NewVertexID = OutRawMesh.CreateVertex();
VertexPositions[NewVertexID] = Position;
VertexIDMap.Add(i, NewVertexID);
}
checkSlow(VertexPositions.GetNumElements() == DstNumPositions);
}
const bool bSrcHasTangentSpace = SrcVertexDataMesh.Tangent.Num() != 0 && SrcVertexDataMesh.BiTangent.Num() != 0 && SrcVertexDataMesh.Normal.Num() != 0;
// Connectivity:
auto CreateTriangle = [&OutRawMesh, &SrcVertexDataMesh, bSrcHasTangentSpace, &VertexIDMap, PolygonGroupID, &VertexInstanceNormals, &VertexInstanceTangents, &VertexInstanceBinormalSigns, &VertexInstanceColors, &VertexInstanceUVs, &EdgeHardnesses](const uint32 TriangleIndices[3])
{
int32 TriangleIndex = TriangleIndices[0] / 3;
FVertexID VertexIndexes[3];
TArray<FVertexInstanceID> VertexInstanceIDs;
VertexInstanceIDs.SetNum(3);
for (int32 Corner = 0; Corner < 3; ++Corner)
{
int32 SrcIndex = SrcVertexDataMesh.Indices[TriangleIndices[Corner]];
VertexIndexes[Corner] = VertexIDMap[SrcIndex];
VertexInstanceIDs[Corner] = OutRawMesh.CreateVertexInstance(VertexIndexes[Corner]);
//Tangents
if (bSrcHasTangentSpace)
{
FVector3f Tangent = SrcVertexDataMesh.Tangent[SrcIndex];
FVector3f BiTangent = SrcVertexDataMesh.BiTangent[SrcIndex];
FVector3f Normal = SrcVertexDataMesh.Normal[SrcIndex];
VertexInstanceTangents[VertexInstanceIDs[Corner]] = Tangent;
VertexInstanceBinormalSigns[VertexInstanceIDs[Corner]] = GetBasisDeterminantSign((FVector)Tangent, (FVector)BiTangent, (FVector)Normal);
VertexInstanceNormals[VertexInstanceIDs[Corner]] = Normal;
}
else
{
VertexInstanceTangents[VertexInstanceIDs[Corner]] = FVector3f(1, 0, 0);
VertexInstanceNormals[VertexInstanceIDs[Corner]] = FVector3f(0, 0, 1);
VertexInstanceBinormalSigns[VertexInstanceIDs[Corner]] = GetBasisDeterminantSign((FVector)VertexInstanceTangents[VertexInstanceIDs[Corner]].GetSafeNormal(),
(FVector)(VertexInstanceNormals[VertexInstanceIDs[Corner]] ^ VertexInstanceTangents[VertexInstanceIDs[Corner]]).GetSafeNormal(),
(FVector)VertexInstanceNormals[VertexInstanceIDs[Corner]].GetSafeNormal());
}
//Color
if (SrcVertexDataMesh.FaceColors.Num() == 0)
{
VertexInstanceColors[VertexInstanceIDs[Corner]] = FVector4f(1.0f);
}
else
{
VertexInstanceColors[VertexInstanceIDs[Corner]] = FVector4f(FLinearColor(SrcVertexDataMesh.FaceColors[TriangleIndex]));
}
//UVs
if (SrcVertexDataMesh.UVs.Num() == 0)
{
VertexInstanceUVs.Set(VertexInstanceIDs[Corner], FVector2f(0.0f, 0.0f));
}
else
{
VertexInstanceUVs.Set(VertexInstanceIDs[Corner], SrcVertexDataMesh.UVs[SrcIndex]);
}
}
// Insert a polygon into the mesh
OutRawMesh.CreatePolygon(PolygonGroupID, VertexInstanceIDs);
};
{
uint32 RangeStop = DstNumIndexes / 3;
for (uint32 i = 0, I = RangeStop; i < I; ++i)
{
uint32 SrcIndexes[3];
for (int32 Corner = 0; Corner < 3; ++Corner)
{
SrcIndexes[Corner] = (i * 3) + Corner;
}
CreateTriangle(SrcIndexes);
}
checkSlow(OutRawMesh.VertexInstances().Num() == DstNumIndexes);
}
//Put everybody in the same smoothgroup by default
TArray<uint32> FaceSmoothingMasks;
FaceSmoothingMasks.AddZeroed(SrcNumTriangles);
if (SrcVertexDataMesh.FacePartition.Num() != 0)
{
for (uint32 FaceIndex = 0; FaceIndex < SrcNumTriangles; ++FaceIndex)
{
FaceSmoothingMasks[FaceIndex] = (1 << (SrcVertexDataMesh.FacePartition[FaceIndex] % 32));
}
}
FStaticMeshOperations::ConvertSmoothGroupToHardEdges(FaceSmoothingMasks, OutRawMesh);
}
// Converts a raw mesh to a vertex data mesh. This is potentially has some loss since the
// raw mesh is nominally a per-index data structure and the vertex data mesh is a per-vertex structure.
// In addition, this only transfers the first texture coordinate and ignores material ids and vertex colors.
void ProxyLOD::RawMeshToVertexDataMesh(const FMeshDescription& SrcRawMesh, FVertexDataMesh& DstVertexDataMesh)
{
FStaticMeshConstAttributes Attributes(SrcRawMesh);
TVertexAttributesConstRef<FVector3f> VertexPositions = Attributes.GetVertexPositions();
TVertexInstanceAttributesConstRef<FVector3f> VertexInstanceNormals = Attributes.GetVertexInstanceNormals();
TVertexInstanceAttributesConstRef<FVector3f> VertexInstanceTangents = Attributes.GetVertexInstanceTangents();
TVertexInstanceAttributesConstRef<float> VertexInstanceBinormalSigns = Attributes.GetVertexInstanceBinormalSigns();
TVertexInstanceAttributesConstRef<FVector2f> VertexInstanceUVs = Attributes.GetVertexInstanceUVs();
const uint32 DstNumPositions = SrcRawMesh.Vertices().Num();
uint32 DstNumIndexes = SrcRawMesh.Triangles().Num() * 3;
// Copy the vertices over
TMap<FVertexID, uint32> VertexIDToDstVertexIndex;
VertexIDToDstVertexIndex.Reserve(SrcRawMesh.Vertices().Num());
{
// Allocate the space for the verts in the VertexDataMesh
ResizeArray(DstVertexDataMesh.Points, DstNumPositions);
uint32 VertexCount = 0;
for (const FVertexID& VertexID : SrcRawMesh.Vertices().GetElementIDs())
{
DstVertexDataMesh.Points[VertexCount] = VertexPositions[VertexID];
VertexIDToDstVertexIndex.Add(VertexID, VertexCount);
VertexCount++;
}
}
// Connectivity:
uint32 VertexInstanceCount = 0;
TArray<uint32>& DstIndices = DstVertexDataMesh.Indices;
ResizeArray(DstIndices, DstNumIndexes);
TArray<FVector3f>& DstTangentArray = DstVertexDataMesh.Tangent;
ResizeArray(DstTangentArray, DstNumPositions);
TArray<FVector3f>& DstBiTangentArray = DstVertexDataMesh.BiTangent;
ResizeArray(DstBiTangentArray, DstNumPositions);
TArray<FVector3f>& DstNormalArray = DstVertexDataMesh.Normal;
ResizeArray(DstNormalArray, DstNumPositions);
TArray<FVector2f>& DstUVs = DstVertexDataMesh.UVs;
ResizeArray(DstUVs, DstNumPositions);
//Iterate all triangle and add the indices
for (const FTriangleID TriangleID : SrcRawMesh.Triangles().GetElementIDs())
{
for (int32 Corner = 0; Corner < 3; ++Corner)
{
const FVertexInstanceID& VertexInstanceID = SrcRawMesh.GetTriangleVertexInstance(TriangleID, Corner);
DstIndices[VertexInstanceCount] = VertexIDToDstVertexIndex[SrcRawMesh.GetVertexInstanceVertex(VertexInstanceID)];
// Copy the tangent space:
// NB: The tangent space is stored per-index in the raw mesh, but only per-vertex in the vertex data mesh.
// We assume that the raw mesh per-index data is really duplicated per-vertex data!
DstTangentArray[DstIndices[VertexInstanceCount]] = VertexInstanceTangents[VertexInstanceID];
DstBiTangentArray[DstIndices[VertexInstanceCount]] = FVector3f::CrossProduct(VertexInstanceNormals[VertexInstanceID], VertexInstanceTangents[VertexInstanceID]).GetSafeNormal() * VertexInstanceBinormalSigns[VertexInstanceID];
DstNormalArray[DstIndices[VertexInstanceCount]] = VertexInstanceNormals[VertexInstanceID];
// Copy the UVs:
// NB: The UVs is stored per-index in the raw mesh, but only per-vertex in the vertex data mesh.
// We assume that the raw mesh per-index data is really duplicated per-vertex data!
if (VertexInstanceUVs.GetNumChannels() == 0)
{
DstUVs[DstIndices[VertexInstanceCount]] = FVector2f(0.0f, 0.0f);
}
else
{
DstUVs[DstIndices[VertexInstanceCount]] = VertexInstanceUVs.Get(VertexInstanceID, 0);
}
VertexInstanceCount++;
}
}
int32 NumTriangles = VertexInstanceCount / 3;
TArray<uint32> FaceSmoothingMasks;
FaceSmoothingMasks.AddZeroed(NumTriangles);
FStaticMeshOperations::ConvertHardEdgesToSmoothGroup(SrcRawMesh, FaceSmoothingMasks);
TArray<uint32>& DstFacePartition = DstVertexDataMesh.FacePartition;
ResizeArray(DstFacePartition, NumTriangles);
for (int32 FaceIndex = 0; FaceIndex < NumTriangles; ++FaceIndex)
{
DstFacePartition[FaceIndex] = 0;
for (int32 BitIndex = 0; BitIndex < 32; ++BitIndex)
{
uint32 BitMask = FMath::Pow(2.f, BitIndex);
DstFacePartition[FaceIndex] += ((FaceSmoothingMasks[FaceIndex] & BitMask) > 0);
}
}
}
template <typename AOSVertexType>
static void CopyIndexAndPos(const TAOSMesh<AOSVertexType>& AOSMesh, FVertexDataMesh& VertexDataMesh)
{
const uint32 DstNumPositions = AOSMesh.GetNumVertexes();
const uint32 DstNumIndexes = AOSMesh.GetNumIndexes();
checkSlow(DstNumIndexes % 3 == 0);
TArray<uint32>& WedgeIndices = VertexDataMesh.Indices;
ResizeArray(VertexDataMesh.Points, DstNumPositions);
ResizeArray(WedgeIndices, DstNumIndexes);
// Copy the vertices over
{
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumPositions),
[&VertexDataMesh, &AOSMesh](const ProxyLOD::FUIntRange& Range)
{
FVector3f* Points = VertexDataMesh.Points.GetData();
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
{
const FVector3f& Position = AOSMesh.Vertexes[i].GetPos();
Points[i] = Position;
}
}
);
}
// Connectivity
{
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumIndexes),
[&AOSMesh, &WedgeIndices](const ProxyLOD::FUIntRange& Range)
{
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
{
WedgeIndices[i] = AOSMesh.Indexes[i];
}
}
);
checkSlow(WedgeIndices.Num() == DstNumIndexes);
}
}
template <typename AOSVertexType>
static void CopyNormals(const TAOSMesh<AOSVertexType>& AOSMesh, FVertexDataMesh& VertexDataMesh)
{
// Copy the tangent space attributes.
const uint32 DstNumPositions = AOSMesh.GetNumVertexes();
checkSlow(AOSMesh.GetNumIndexes() % 3 == 0);
TArray<FVector3f>& NormalArray = VertexDataMesh.Normal;
ResizeArray(NormalArray, DstNumPositions);
// Transfer the normal
{
ProxyLOD::Parallel_For(ProxyLOD::FUIntRange(0, DstNumPositions),
[&AOSMesh, &NormalArray](const ProxyLOD::FUIntRange& Range)
{
for (uint32 i = Range.begin(), I = Range.end(); i < I; ++i)
{
const auto& AOSVertex = AOSMesh.Vertexes[i];
NormalArray[i] = AOSVertex.Normal;
}
}
);
}
}
// Populate a VertexDataMesh with the information in the Array of Structs mesh.
template <typename AOSVertexType>
static void AOSMeshToVertexDataMesh(const TAOSMesh<AOSVertexType>& AOSMesh, FVertexDataMesh& VertexDataMesh)
{
TRACE_CPUPROFILER_EVENT_SCOPE(AOSMeshToVertexDataMesh)
// Copy the topology and geometry of the mesh
CopyIndexAndPos(AOSMesh, VertexDataMesh);
// adds t = (1,0,0) bt = (0, 1, 0) n = (0, 0, 1)
ProxyLOD::AddDefaultTangentSpace(VertexDataMesh);
// Copy the tangent space attributes.
CopyNormals(AOSMesh, VertexDataMesh);
}
// The posistion only specialization only adds a default tangent space
template <>
void AOSMeshToVertexDataMesh<FPositionOnlyVertex>(const TAOSMesh<FPositionOnlyVertex>& AOSMesh, FVertexDataMesh& VertexDataMesh)
{
// Copy the topology and geometry of the mesh
CopyIndexAndPos(AOSMesh, VertexDataMesh);
// adds t = (1,0,0) bt = (0, 1, 0) n = (0, 0, 1)
ProxyLOD::AddDefaultTangentSpace(VertexDataMesh);
}
void ProxyLOD::ConvertMesh(const FAOSMesh& InMesh, FVertexDataMesh& OutMesh)
{
AOSMeshToVertexDataMesh(InMesh, OutMesh);
}
void ProxyLOD::ConvertMesh(const FAOSMesh& InMesh, FMeshDescription& OutMesh)
{
AOSMeshToRawMesh(InMesh, OutMesh);
}
void ProxyLOD::ConvertMesh(const FVertexDataMesh& InMesh, FMeshDescription& OutMesh)
{
VertexDataMeshToRawMesh(InMesh, OutMesh);
}
void ProxyLOD::ConvertMesh(const FMeshDescription& InMesh, FVertexDataMesh& OutMesh)
{
RawMeshToVertexDataMesh(InMesh, OutMesh);
}