Files
UnrealEngineUWP/Engine/Source/Developer/MeshMergeUtilities/Private/MeshMergeDataTracker.cpp
Richard TalbotWatkin 51d4cb3f66 Fully deprecated old MeshDescription APIs.
Prepared direct attribute access for deprecation, preferring use of APIs to access static mesh attributes.
Fixed recently merged Enterprise code to comply with new APIs.
Changed all tools to use triangle-centric iteration where possible.
Added new MeshAttributeArray APIs for querying attribute flags, and added a new Mandatory flag.
Various bug fixes.
#rb Alexis.Matte

[CL 13873755 by Richard TalbotWatkin in ue5-main branch]
2020-07-16 08:23:15 -04:00

306 lines
9.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MeshMergeDataTracker.h"
#include "MeshMergeHelpers.h"
#include "Misc/Crc.h"
#include "Engine/StaticMesh.h"
#include "StaticMeshAttributes.h"
FMeshMergeDataTracker::FMeshMergeDataTracker()
: AvailableLightMapUVChannel(INDEX_NONE), SummedLightMapPixels(0)
{
FMemory::Memzero(bWithVertexColors);
FMemory::Memzero(bOcuppiedUVChannels);
}
FMeshDescription& FMeshMergeDataTracker::AddAndRetrieveRawMesh(int32 MeshIndex, int32 LODIndex, UStaticMesh* InMesh)
{
checkf(!RawMeshLODs.Contains(FMeshLODKey(MeshIndex, LODIndex, InMesh)), TEXT("Raw Mesh already added for this key"));
FMeshDescription& MeshDescription = RawMeshLODs.Add(FMeshLODKey(MeshIndex, LODIndex, InMesh));
FStaticMeshAttributes(MeshDescription).Register();
return MeshDescription;
}
void FMeshMergeDataTracker::RemoveRawMesh(int32 MeshIndex, int32 LODIndex)
{
checkf(RawMeshLODs.Contains(FMeshLODKey(MeshIndex, LODIndex)), TEXT("No Raw Mesh for this key"));
RawMeshLODs.Remove(FMeshLODKey(MeshIndex, LODIndex));
}
TConstRawMeshIterator FMeshMergeDataTracker::GetConstRawMeshIterator() const
{
return RawMeshLODs.CreateConstIterator();
}
TRawMeshIterator FMeshMergeDataTracker::GetRawMeshIterator()
{
return RawMeshLODs.CreateIterator();
}
void FMeshMergeDataTracker::AddLightmapChannelRecord(int32 MeshIndex, int32 LODIndex, int32 LightmapChannelIndex)
{
LightmapChannelLODs.Add(FMeshLODKey(MeshIndex, LODIndex), LightmapChannelIndex);
}
int32 FMeshMergeDataTracker::AddSection(const FSectionInfo& SectionInfo)
{
return UniqueSections.AddUnique(SectionInfo);
}
int32 FMeshMergeDataTracker::NumberOfUniqueSections() const
{
return UniqueSections.Num();
}
UMaterialInterface* FMeshMergeDataTracker::GetMaterialForSectionIndex(int32 SectionIndex)
{
checkf(UniqueSections.IsValidIndex(SectionIndex), TEXT("Invalid section index for stored data"));
return UniqueSections[SectionIndex].Material;
}
const FSectionInfo& FMeshMergeDataTracker::GetSection(int32 SectionIndex) const
{
checkf(UniqueSections.IsValidIndex(SectionIndex), TEXT("Invalid section index for stored data"));
return UniqueSections[SectionIndex];
}
void FMeshMergeDataTracker::AddBakedMaterialSection(const FSectionInfo& SectionInfo)
{
UniqueSections.Empty(1);
UniqueSections.AddUnique(SectionInfo);
}
void FMeshMergeDataTracker::AddMaterialSlotName(UMaterialInterface *MaterialInterface, FName MaterialSlotName)
{
FName *FindMaterialSlotName = MaterialInterfaceToMaterialSlotName.Find(MaterialInterface);
//If there is a material use by more then one slot, only the first slot name occurrence will be use. (selection order)
if (FindMaterialSlotName == nullptr)
{
MaterialInterfaceToMaterialSlotName.Add(MaterialInterface, MaterialSlotName);
}
}
FName FMeshMergeDataTracker::GetMaterialSlotName(UMaterialInterface *MaterialInterface) const
{
const FName *MaterialSlotName = MaterialInterfaceToMaterialSlotName.Find(MaterialInterface);
return MaterialSlotName == nullptr ? NAME_None : *MaterialSlotName;
}
void FMeshMergeDataTracker::AddLODIndex(int32 LODIndex)
{
LODIndices.AddUnique(LODIndex);
}
int32 FMeshMergeDataTracker::GetNumLODsForMergedMesh() const
{
return LODIndices.Num();
}
TConstLODIndexIterator FMeshMergeDataTracker::GetLODIndexIterator() const
{
return LODIndices.CreateConstIterator();
}
void FMeshMergeDataTracker::AddLightMapPixels(int32 Dimension)
{
SummedLightMapPixels += FMath::Max(Dimension, 0);
}
int32 FMeshMergeDataTracker::GetLightMapDimension() const
{
return FMath::CeilToInt(FMath::Sqrt(SummedLightMapPixels));
}
bool FMeshMergeDataTracker::DoesLODContainVertexColors(int32 LODIndex) const
{
checkf(FMath::IsWithinInclusive(LODIndex, 0, MAX_STATIC_MESH_LODS - 1), TEXT("Invalid LOD index"));
return bWithVertexColors[LODIndex];
}
bool FMeshMergeDataTracker::DoesAnyLODContainVertexColors() const
{
for(int32 LODIndex = 0; LODIndex < MAX_STATIC_MESH_LODS; ++LODIndex)
{
if(bWithVertexColors[LODIndex])
{
return true;
}
}
return false;
}
bool FMeshMergeDataTracker::DoesUVChannelContainData(int32 UVChannel, int32 LODIndex) const
{
checkf(FMath::IsWithinInclusive(LODIndex, 0, MAX_STATIC_MESH_LODS - 1), TEXT("Invalid LOD index"));
checkf(FMath::IsWithinInclusive(UVChannel, 0, MAX_MESH_TEXTURE_COORDS_MD - 1), TEXT("Invalid UV channel index"));
return bOcuppiedUVChannels[LODIndex][UVChannel];
}
bool FMeshMergeDataTracker::DoesUVChannelContainData(int32 UVChannel) const
{
checkf(FMath::IsWithinInclusive(UVChannel, 0, MAX_MESH_TEXTURE_COORDS_MD - 1), TEXT("Invalid UV channel index"));
for(int32 LODIndex = 0; LODIndex < MAX_STATIC_MESH_LODS; LODIndex++)
{
if(bOcuppiedUVChannels[LODIndex][UVChannel])
{
return true;
}
}
return false;
}
bool FMeshMergeDataTracker::DoesMeshLODRequireUniqueUVs(FMeshLODKey Key)
{
// if we have vertex color, we require unique UVs
return RequiresUniqueUVs.Contains(Key);
}
int32 FMeshMergeDataTracker::GetAvailableLightMapUVChannel() const
{
return AvailableLightMapUVChannel;
}
void FMeshMergeDataTracker::AddComponentToWedgeMapping(int32 MeshIndex, int32 LODIndex, uint32 WedgeIndex)
{
ComponentToWedgeOffsets.Add(FMeshLODKey(MeshIndex, LODIndex), WedgeIndex);
}
uint32 FMeshMergeDataTracker::GetComponentToWedgeMappng(int32 MeshIndex, int32 LODIndex) const
{
const uint32* MappingPtr = ComponentToWedgeOffsets.Find(FMeshLODKey(MeshIndex, LODIndex));
return MappingPtr ? *MappingPtr : INDEX_NONE;
}
FMeshDescription* FMeshMergeDataTracker::GetRawMeshPtr(int32 MeshIndex, int32 LODIndex)
{
return RawMeshLODs.Find(FMeshLODKey(MeshIndex, LODIndex));
}
FMeshDescription* FMeshMergeDataTracker::GetRawMeshPtr(FMeshLODKey Key)
{
return RawMeshLODs.Find(Key);
}
FMeshDescription* FMeshMergeDataTracker::FindRawMeshAndLODIndex(int32 MeshIndex, int32& OutLODIndex)
{
FMeshDescription* FoundMeshPtr = nullptr;
OutLODIndex = INDEX_NONE;
for (TPair<FMeshLODKey, FMeshDescription>& Pair : RawMeshLODs)
{
if (Pair.Key.GetMeshIndex() == MeshIndex)
{
FoundMeshPtr = &Pair.Value;
OutLODIndex = Pair.Key.GetLODIndex();
break;
}
}
return FoundMeshPtr;
}
FMeshDescription* FMeshMergeDataTracker::TryFindRawMeshForLOD(int32 MeshIndex, int32& InOutDesiredLODIndex)
{
FMeshDescription* FoundMeshPtr = RawMeshLODs.Find(FMeshLODKey(MeshIndex, InOutDesiredLODIndex));
int32 SearchIndex = InOutDesiredLODIndex - 1;
while (FoundMeshPtr == nullptr && SearchIndex >= 0)
{
for (TPair<FMeshLODKey, FMeshDescription>& Pair : RawMeshLODs)
{
if (Pair.Key.GetMeshIndex() == MeshIndex && Pair.Key.GetLODIndex() == SearchIndex)
{
FoundMeshPtr = &Pair.Value;
InOutDesiredLODIndex = SearchIndex;
break;
}
}
--SearchIndex;
}
return FoundMeshPtr;
}
void FMeshMergeDataTracker::AddSectionRemapping(int32 MeshIndex, int32 LODIndex, int32 OriginalIndex, int32 UniqueIndex)
{
UniqueSectionIndexPerLOD.Add(FMeshLODKey(MeshIndex, LODIndex), SectionRemapPair(OriginalIndex, UniqueIndex));
UniqueSectionToMeshLOD.Add(UniqueIndex, FMeshLODKey(MeshIndex, LODIndex));
}
void FMeshMergeDataTracker::GetMeshLODsMappedToUniqueSection(int32 UniqueIndex, TArray<FMeshLODKey>& InOutMeshLODs)
{
UniqueSectionToMeshLOD.MultiFind(UniqueIndex, InOutMeshLODs);
}
void FMeshMergeDataTracker::GetMappingsForMeshLOD(FMeshLODKey Key, TArray<SectionRemapPair>& InOutMappings)
{
UniqueSectionIndexPerLOD.MultiFind(Key, InOutMappings);
}
void FMeshMergeDataTracker::ProcessRawMeshes()
{
bool bPotentialLightmapUVChannels[MAX_MESH_TEXTURE_COORDS_MD];
FMemory::Memset(bPotentialLightmapUVChannels, 1);
bool bPotentialLODLightmapUVChannels[MAX_STATIC_MESH_LODS][MAX_MESH_TEXTURE_COORDS_MD];
FMemory::Memset(bPotentialLODLightmapUVChannels, 1);
// Retrieve information in regards to occupied UV channels whether or not a mesh contains vertex colors, and if
for (TPair<FMeshLODKey, FMeshDescription>& MeshPair : RawMeshLODs)
{
FMeshLODKey& Key = MeshPair.Key;
const int32 LODIndex = Key.GetLODIndex();
const FMeshDescription& RawMesh = MeshPair.Value;
FStaticMeshConstAttributes Attributes(RawMesh);
TVertexInstanceAttributesConstRef<FVector4> VertexInstanceColors = Attributes.GetVertexInstanceColors();
TVertexInstanceAttributesConstRef<FVector2D> VertexInstanceUVs = Attributes.GetVertexInstanceUVs();
// hash vertex color buffer so we can see if instances have unique vertex data
if(VertexInstanceColors.GetNumElements() > 0)
{
Key.SetVertexColorHash(RawMesh.VertexInstanceAttributes().GetHash(MeshAttribute::VertexInstance::Color));
}
const int32 LightmapChannelIdx = LightmapChannelLODs.FindRef(Key);
bool bNeedsVertexData = false;
if (VertexInstanceUVs.GetNumElements() > 0)
{
for (int32 ChannelIndex = 0; ChannelIndex < FMath::Min(VertexInstanceUVs.GetNumChannels(), (int32)MAX_MESH_TEXTURE_COORDS_MD); ++ChannelIndex)
{
bOcuppiedUVChannels[LODIndex][ChannelIndex] = true;
bPotentialLODLightmapUVChannels[LODIndex][ChannelIndex] = (ChannelIndex == LightmapChannelIdx);
const bool bWrappingUVs = FMeshMergeHelpers::CheckWrappingUVs(RawMesh, ChannelIndex);
if (bWrappingUVs)
{
bNeedsVertexData = true;
}
}
}
// Merge available lightmap slots from LODs into one set, so we can assess later what slots are available
for (int32 ChannelIdx = 1; ChannelIdx < MAX_MESH_TEXTURE_COORDS_MD; ++ChannelIdx)
{
bPotentialLightmapUVChannels[ChannelIdx] &= bPotentialLODLightmapUVChannels[LODIndex][ChannelIdx];
}
if (bNeedsVertexData)
{
RequiresUniqueUVs.Add(Key);
}
bWithVertexColors[LODIndex] |= VertexInstanceColors.GetNumElements() != 0;
}
// Look for an available lightmap slot we can use in the merged set
// We start at channel 1 as merged meshes always use texcoord 0 for their expected mapping channel, so we cant use it;
AvailableLightMapUVChannel = INDEX_NONE;
for (int32 ChannelIdx = 1; ChannelIdx < MAX_MESH_TEXTURE_COORDS_MD; ++ChannelIdx)
{
if(bPotentialLightmapUVChannels[ChannelIdx])
{
AvailableLightMapUVChannel = ChannelIdx;
break;
}
}
}