// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "StaticMeshResources.h" #include "Materials/MaterialInstance.h" #include "MaterialUtilities.h" #include "StaticMeshAttributes.h" typedef TPair MeshLODPair; typedef TPair SectionRemapPair; typedef TPair MaterialRemapPair; struct FSectionInfo; /** Structure representing a mesh and lod index */ struct MESHMERGEUTILITIES_API FMeshLODKey { public: FMeshLODKey(int32 MeshIndex, int32 LODIndex, UStaticMesh* InMesh = nullptr) { CombinedKey = ((LODIndex & 0xffff) << 16) | (MeshIndex & 0xffff); Mesh = InMesh; VertexColorHash = 0; } explicit FMeshLODKey(uint32 InCombinedKey) { CombinedKey = InCombinedKey; Mesh = nullptr; VertexColorHash = 0; } UStaticMesh* GetMesh() const { return Mesh; } int32 GetMeshIndex() const { return (CombinedKey & 0x0000ffff); } int32 GetLODIndex() const { return (CombinedKey & 0xffff0000) >> 16; } uint32 GetVertexColorHash() const { return VertexColorHash; } void SetVertexColorHash(uint32 InVertexColorHash) { VertexColorHash = InVertexColorHash; } inline bool operator==(const FMeshLODKey& Other) const { return CombinedKey == Other.CombinedKey; } inline friend uint32 GetTypeHash(const FMeshLODKey& Item) { return Item.CombinedKey; } protected: uint32 CombinedKey; UStaticMesh* Mesh; uint32 VertexColorHash; }; /** This helps identify materials that can be collapsed because of equivalence */ struct MESHMERGEUTILITIES_API FMaterialKey { FMaterialKey(const UMaterialInterface* InMaterial) : Material(InMaterial) { } inline bool operator==(const FMaterialKey& Other) const { // Perform an optional custom comparison if we are trying to collapse material instances const UMaterialInstance* MaterialInstance0 = Cast(Material); const UMaterialInstance* MaterialInstance1 = Cast(Other.Material); if(MaterialInstance0 && MaterialInstance1) { return MaterialInstance0->Equivalent(MaterialInstance1); } else { return Material == Other.Material; } } const UMaterialInterface* Material; }; /** Typedefs to allow for some nicer looking loops */ typedef TMap::TConstIterator TConstRawMeshIterator; typedef TMap::TIterator TRawMeshIterator; typedef TArray::TConstIterator TConstLODIndexIterator; /** Used to keep track of in-flight data while meshes are merged and their corresponding materials baked down */ class MESHMERGEUTILITIES_API FMeshMergeDataTracker { public: FMeshMergeDataTracker(); /** Looks at all available raw mesh data and processes it to populate some flags */ void ProcessRawMeshes(); /** Adding a mapping between the index for an original mesh section index and the mesh section it will be indexed to in the final mesh */ void AddSectionRemapping(int32 MeshIndex, int32 LODIndex, int32 OriginalIndex, int32 UniqueIndex); /** Retrieves the MeshLOD keys from which the original sections are mapped to the unique section index */ void GetMeshLODsMappedToUniqueSection(int32 UniqueIndex, TArray& InOutMeshLODs); /** Retrieves all section mappings for the MeshLOD key*/ void GetMappingsForMeshLOD(FMeshLODKey Key, TArray& InOutMappings); /** Adds or retrieves raw mesh data for the mesh and LOD index */ FMeshDescription& AddAndRetrieveRawMesh(int32 MeshIndex, int32 LODIndex, UStaticMesh* InMesh); /** Removes raw mesh entry for the given mesh and LOD index */ void RemoveRawMesh(int32 MeshIndex, int32 LODIndex); /** Retrieves Raw Mesh ptr for the given mesh and LOD index */ FMeshDescription* GetRawMeshPtr(int32 MeshIndex, int32 LODIndex); /** Retrieves Raw Mesh ptr for the given MeshLOD key */ FMeshDescription* GetRawMeshPtr(FMeshLODKey Key); /** Tries to retrieve a FMeshDescription and returns the LOD index it found an entry for */ FMeshDescription* FindRawMeshAndLODIndex(int32 MeshIndex, int32& OutLODIndex); /** Tries to retrieve a FMeshDescription for the given mesh and LOD index, if it can't it will try to find an entry for each LOD levle below InOutDesiredLODIndex */ FMeshDescription* TryFindRawMeshForLOD(int32 MeshIndex, int32& InOutDesiredLODIndex); /** Returns a const key/value iterator for the FMeshDescription entries */ TConstRawMeshIterator GetConstRawMeshIterator() const; /** Returns a non-const key/value iterator for the FMeshDescription entries */ TRawMeshIterator GetRawMeshIterator(); /** Adds a record of what channel lightmap data is stored at */ void AddLightmapChannelRecord(int32 MeshIndex, int32 LODIndex, int32 LightmapChannelIndex); /** Adds (unique) section to stored data */ int32 AddSection(const FSectionInfo& SectionInfo); /** Returns the number of unique sections */ int32 NumberOfUniqueSections() const; /** Returns the material used by the unique section */ UMaterialInterface* GetMaterialForSectionIndex(int32 SectionIndex); /** Returns the unique section instance */ const FSectionInfo& GetSection(int32 SectionIndex) const; /** Clears out unique section to be replaced with the baked material one */ void AddBakedMaterialSection(const FSectionInfo& SectionInfo); /** Add a material slot name for a unique material instance. */ void AddMaterialSlotName(UMaterialInterface *MaterialInterface, FName MaterialSlotName); /** Get the material slot name from a unique material instance. */ FName GetMaterialSlotName(UMaterialInterface *MaterialInterface) const; /** Adds a LOD index which will be part of the final merged mesh */ void AddLODIndex(int32 LODIndex); /** Retrieves number of LODs part of the final merged mesh */ int32 GetNumLODsForMergedMesh() const; /** Iterates over LOD indices for mesh */ TConstLODIndexIterator GetLODIndexIterator() const; /** Add number of lightmap pixels used for one of the Meshes */ void AddLightMapPixels(int32 Pixels); /** Returns the texture dimension required to distribute all of the lightmap pixels */ int32 GetLightMapDimension() const; /** Returns whether or not any raw mesh entry contains vertex colors for the specified LOD index */ bool DoesLODContainVertexColors(int32 LODIndex) const; /** Returns whether or not any raw mesh entry contains vertex colors for any LOD index */ bool DoesAnyLODContainVertexColors() const; /** Returns whether or not any raw mesh entry contains texture coordinates for the specified UV channel and LOD index */ bool DoesUVChannelContainData(int32 UVChannel, int32 LODIndex) const; /** Returns whether or not any raw mesh entry contains texture coordinates for the specified UV channel and any LOD index */ bool DoesUVChannelContainData(int32 UVChannel) const; /** Returns whether or not the raw mesh entry for the given MeshLOD key requires unique UVs for baking out its material(s) */ bool DoesMeshLODRequireUniqueUVs(FMeshLODKey Key); /** Returns the first available UV channel across all raw mesh entries, which will be a good fit for the lightmap UV index in the final mesh */ int32 GetAvailableLightMapUVChannel() const; void AddComponentToWedgeMapping(int32 MeshIndex, int32 LODIndex, uint32 WedgeIndex); uint32 GetComponentToWedgeMappng(int32 MeshIndex, int32 LODIndex) const; double GetTextureSizeFromTargetTexelDensity(float InTargetTexelDensity) const; protected: // Mesh / LOD index, RawMesh TMap RawMeshLODs; // Mesh / LOD index, lightmap channel TMap LightmapChannelLODs; // Whether a key requires unique UVs TArray RequiresUniqueUVs; //Use this map to recycle the material slot name TMap MaterialInterfaceToMaterialSlotName; /** Flags for UV and vertex color usage */ bool bWithVertexColors[MAX_STATIC_MESH_LODS]; bool bOcuppiedUVChannels[MAX_STATIC_MESH_LODS][MAX_MESH_TEXTURE_COORDS_MD]; /** First available UV channel across all RawMesh entries */ int32 AvailableLightMapUVChannel; int32 SummedLightMapPixels; /** Remapping pairs for each mesh and LOD index combination */ TMultiMap UniqueSectionIndexPerLOD; /** Maps from each unique section index to all the RawMesh entries which contain an original section that's mapped to it */ TMultiMap UniqueSectionToMeshLOD; /** All LOD indices which should be populated in the final merged mesh */ TArray LODIndices; /** Unique set of sections in mesh */ TArray UniqueSections; TMap ComponentToWedgeOffsets; };