Files
UnrealEngine/Engine/Plugins/Mutable/Source/MutableRuntime/Private/MuR/OpMeshExtractLayoutBlock.h
2025-05-18 13:04:45 +08:00

264 lines
8.9 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "MuR/MeshPrivate.h"
#include "MuR/Platform.h"
#include "MuR/OpMeshRemove.h"
namespace mu
{
inline void MeshExtractFromVertices( const FMesh* Source,
FMesh* Result,
const TArray<int32>& OldToNew,
const TArray<int32>& NewToOld )
{
int32 ResultVertices = NewToOld.Num();
// Assemble the new vertex buffer
Result->GetVertexBuffers().SetElementCount(ResultVertices);
for (int32 BufferIndex = 0; BufferIndex < Result->GetVertexBuffers().GetBufferCount(); ++BufferIndex)
{
const uint8* pSourceData = Source->GetVertexBuffers().GetBufferData(BufferIndex);
uint8* pDest = Result->GetVertexBuffers().GetBufferData(BufferIndex);
int32 Size = Result->GetVertexBuffers().GetElementSize(BufferIndex);
for (int32 NewIndex = 0; NewIndex < ResultVertices; ++NewIndex)
{
int32 OldIndex = NewToOld[NewIndex];
FMemory::Memcpy(pDest, pSourceData + Size*OldIndex, Size);
pDest += Size;
}
}
// If the vertices are explicit or relative, the above operation will already handle them correctly
// Otherwise, create a relative vertex ID buffer if necessary
Result->MeshIDPrefix = Source->MeshIDPrefix;
if (Source->AreVertexIdsImplicit()
&&
// If we extract everything, we can keep the ids implicit.
ResultVertices!=Source->GetVertexCount())
{
// Add a new buffer
int32 NewBuffer = Result->VertexBuffers.GetBufferCount();
Result->VertexBuffers.SetBufferCount(NewBuffer + 1);
EMeshBufferSemantic Semantic = EMeshBufferSemantic::VertexIndex;
int32 SemanticIndex = 0;
EMeshBufferFormat Format = EMeshBufferFormat::UInt32;
int32 Components = 1;
int32 Offset = 0;
Result->VertexBuffers.SetBuffer(NewBuffer, sizeof(uint32), 1, &Semantic, &SemanticIndex, &Format, &Components, &Offset);
uint32* pIdData = reinterpret_cast<uint32*>(Result->VertexBuffers.GetBufferData(NewBuffer));
for (int32 NewIndex = 0; NewIndex < ResultVertices; ++NewIndex)
{
uint32 OldIndex = NewToOld[NewIndex];
(*pIdData++) = OldIndex;
}
}
// Assemble the new index buffers
TBitArray<> UsedSourceFaces;
UsedSourceFaces.SetNum(Source->GetFaceCount(), false);
UntypedMeshBufferIteratorConst itIndex(Source->GetIndexBuffers(), EMeshBufferSemantic::VertexIndex);
UntypedMeshBufferIterator itResultIndex(Result->GetIndexBuffers(), EMeshBufferSemantic::VertexIndex);
int32 IndexCount = 0;
if (itIndex.GetFormat() == EMeshBufferFormat::UInt32)
{
const uint32* pIndices = reinterpret_cast<const uint32*>(itIndex.ptr());
uint32* pDestIndices = reinterpret_cast<uint32*>(itResultIndex.ptr());
for (int32 i = 0; i < Source->GetIndexCount()/3; ++i)
{
if (OldToNew[pIndices[i*3 + 0]] >= 0 && OldToNew[pIndices[i*3 + 1]] >= 0 && OldToNew[pIndices[i*3 + 2]] >= 0)
{
UsedSourceFaces[i] = true;
// Clamp in case triangles go across blocks
pDestIndices[IndexCount++] = FMath::Max(0, OldToNew[pIndices[i*3 + 0]]);
pDestIndices[IndexCount++] = FMath::Max(0, OldToNew[pIndices[i*3 + 1]]);
pDestIndices[IndexCount++] = FMath::Max(0, OldToNew[pIndices[i*3 + 2]]);
}
}
}
else if (itIndex.GetFormat() == EMeshBufferFormat::UInt16)
{
const uint16* pIndices = reinterpret_cast<const uint16*>(itIndex.ptr());
uint16* pDestIndices = reinterpret_cast<uint16*>(itResultIndex.ptr());
for (int32 i = 0; i < Source->GetIndexCount()/3; ++i)
{
if (OldToNew[pIndices[i*3 + 0]] >= 0 && OldToNew[pIndices[i*3 + 1]] >= 0 && OldToNew[pIndices[i*3 + 2]] >= 0)
{
UsedSourceFaces[i] = true;
// Clamp in case triangles go across blocks
pDestIndices[IndexCount++] = (uint16)FMath::Max(0, OldToNew[pIndices[i*3 + 0]]);
pDestIndices[IndexCount++] = (uint16)FMath::Max(0, OldToNew[pIndices[i*3 + 1]]);
pDestIndices[IndexCount++] = (uint16)FMath::Max(0, OldToNew[pIndices[i*3 + 2]]);
}
}
}
else
{
check(false);
}
Result->GetIndexBuffers().SetElementCount(IndexCount);
const int32 NumOriginalVerts = OldToNew.Num();
TBitArray<> UsedVertices;
UsedVertices.SetNum(NumOriginalVerts, false);
for (int32 I = 0; I < NumOriginalVerts; ++I)
{
UsedVertices[I] = OldToNew[I] >= 0;
}
MeshRemoveRecreateSurface(Result, UsedVertices, UsedSourceFaces);
}
/** Extract all vertices that have a layout block from the passed list on the given channel. */
inline void MeshExtractLayoutBlock(FMesh* Result, const FMesh* Source,
uint32 LayoutIndex,
uint16 BlockCount,
const uint64* BlockIds, bool& bOutSuccess)
{
check(Source);
bOutSuccess = true;
// TODO: Optimise
Result->CopyFrom(*Source);
UntypedMeshBufferIteratorConst itBlocks(Source->GetVertexBuffers(), EMeshBufferSemantic::LayoutBlock, LayoutIndex);
if (itBlocks.GetFormat() != EMeshBufferFormat::None)
{
int32 ResultVertices = 0;
TArray<int32> OldToNew;
OldToNew.Init(-1, Source->GetVertexCount());
TArray<int32> NewToOld;
NewToOld.Reserve(Source->GetVertexCount());
if (itBlocks.GetFormat() == EMeshBufferFormat::UInt16)
{
const uint16* pBlocks = reinterpret_cast<const uint16*>(itBlocks.ptr());
for ( int32 i=0; i<Source->GetVertexCount(); ++i )
{
uint64 VertexBlockRelative = pBlocks[i];
uint64 VertexBlockId = (uint64(Source->MeshIDPrefix) << 32) | VertexBlockRelative;
bool bFound = false;
for (int32 j = 0; j < BlockCount; ++j)
{
if (VertexBlockId == BlockIds[j])
{
bFound = true;
break;
}
}
if (bFound)
{
OldToNew[i] = ResultVertices++;
NewToOld.Add(i);
}
}
}
else if (itBlocks.GetFormat() == EMeshBufferFormat::UInt64)
{
const uint64* pBlocks = reinterpret_cast<const uint64*>(itBlocks.ptr());
for (int32 i = 0; i < Source->GetVertexCount(); ++i)
{
uint64 VertexBlockId = pBlocks[i];
bool bFound = false;
for (int32 j = 0; j < BlockCount; ++j)
{
if (VertexBlockId == BlockIds[j])
{
bFound = true;
break;
}
}
if (bFound)
{
OldToNew[i] = ResultVertices++;
NewToOld.Add(i);
}
}
}
else
{
check( false );
}
MeshExtractFromVertices(Source, Result, OldToNew, NewToOld);
}
}
/** Extract all vertices that have a valid layout block on the given channel. */
inline void MeshExtractLayoutBlock(FMesh* Result, const FMesh* Source, uint32 LayoutIndex, bool& bOutSuccess)
{
check(Source);
bOutSuccess = true;
// TODO: Optimise
Result->CopyFrom(*Source);
UntypedMeshBufferIteratorConst itBlocks(Source->GetVertexBuffers(), EMeshBufferSemantic::LayoutBlock, LayoutIndex);
if (itBlocks.GetFormat() != EMeshBufferFormat::None)
{
int32 ResultVertices = 0;
TArray<int32> OldToNew;
OldToNew.Init(-1, Source->GetVertexCount());
TArray<int32> NewToOld;
NewToOld.Reserve(Source->GetVertexCount());
if (itBlocks.GetFormat() == EMeshBufferFormat::UInt16)
{
const uint16* pBlocks = reinterpret_cast<const uint16*>(itBlocks.ptr());
for (int32 i = 0; i < Source->GetVertexCount(); ++i)
{
uint16 VertexBlockRelative = pBlocks[i];
bool bFound = VertexBlockRelative != std::numeric_limits<uint16>::max();
if (bFound)
{
OldToNew[i] = ResultVertices++;
NewToOld.Add(i);
}
}
}
else if (itBlocks.GetFormat() == EMeshBufferFormat::UInt64)
{
const uint64* pBlocks = reinterpret_cast<const uint64*>(itBlocks.ptr());
for (int32 i = 0; i < Source->GetVertexCount(); ++i)
{
uint64 VertexBlockId = pBlocks[i];
bool bFound = VertexBlockId != std::numeric_limits<uint64>::max();
if (bFound)
{
OldToNew[i] = ResultVertices++;
NewToOld.Add(i);
}
}
}
else
{
check(false);
}
MeshExtractFromVertices(Source, Result, OldToNew, NewToOld);
}
}
}