// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Misc/Guid.h" #include "Modules/ModuleInterface.h" #include "Components.h" #include "MeshBuild.h" #include "IMeshMergeUtilities.h" class UMeshComponent; class USkeletalMesh; class UStaticMesh; class UStaticMeshComponent; struct FFlattenMaterial; struct FRawMesh; struct FRawSkinWeight; struct FStaticMeshLODResources; class FSkeletalMeshLODModel; class FSourceMeshDataForDerivedDataTask; typedef FIntPoint FMeshIdAndLOD; struct FFlattenMaterial; struct FReferenceSkeleton; struct FStaticMeshLODResources; class UMeshComponent; class UStaticMesh; struct FBoneVertInfo; namespace SkeletalMeshImportData { struct FMeshFace; struct FMeshWedge; struct FVertInfluence; }; namespace ETangentOptions { enum Type { None = 0, BlendOverlappingNormals = 0x1, IgnoreDegenerateTriangles = 0x2, UseMikkTSpace = 0x4, }; }; struct FSignedDistanceFieldBuildSectionData { EBlendMode BlendMode = BLEND_Opaque; bool bTwoSided = false; bool bAffectDistanceFieldLighting = true; }; struct FMeshDataForDerivedDataTask { const FSourceMeshDataForDerivedDataTask* SourceMeshData; const FStaticMeshLODResources* LODModel; TConstArrayView SectionData; FBoxSphereBounds3f Bounds; }; struct FOverlappingCorners; class IMeshUtilities : public IModuleInterface { public: /** * Calculates (new) non-overlapping UV coordinates for the given Raw Mesh * * @param RawMesh - Raw Mesh to generate UV coordinates for * @param TextureResolution - Texture resolution to take into account while generating the UVs * @param bMergeIdenticalMaterials - Whether faces with identical materials can be treated as one in the resulting set of unique UVs * @param OutTexCoords - New set of UV coordinates * @return bool - whether or not generating the UVs succeeded */ virtual bool GenerateUniqueUVsForStaticMesh(const FRawMesh& RawMesh, int32 TextureResolution, TArray& OutTexCoords) const = 0; virtual bool GenerateUniqueUVsForStaticMesh(const FRawMesh& RawMesh, int32 TextureResolution, bool bMergeIdenticalMaterials, TArray& OutTexCoords) const = 0; public: /** Returns a string uniquely identifying this version of mesh utilities. */ virtual const FString& GetVersionString() const = 0; /** Used to make sure all imported material slot name are unique and non empty. * * @param StaticMesh * @param bForceUniqueSlotName If true, make sure all slot names are unique as well. */ virtual void FixupMaterialSlotNames(UStaticMesh* StaticMesh) const = 0; /** Used to make sure all imported material slot name are unique and non empty. * * @param SkeletalMesh * @param bForceUniqueSlotName If true, make sure all slot names are unique as well. */ virtual void FixupMaterialSlotNames(USkeletalMesh* SkeletalMesh) const = 0; /** * Builds a renderable static mesh using the provided source models and the LOD groups settings. * @returns true if the renderable mesh was built successfully. */ virtual bool BuildStaticMesh( class FStaticMeshRenderData& OutRenderData, UStaticMesh* StaticMesh, const class FStaticMeshLODGroup& LODGroup ) = 0; virtual void BuildStaticMeshVertexAndIndexBuffers( TArray& OutVertices, TArray >& OutPerSectionIndices, TArray& OutWedgeMap, const FRawMesh& RawMesh, const FOverlappingCorners& OverlappingCorners, const TMap& MaterialToSectionMapping, float ComparisonThreshold, FVector3f BuildScale, int32 ImportVersion ) = 0; /** * Builds a static mesh using the provided source models and the LOD groups settings, and replaces * the RawMeshes with the reduced meshes. Does not modify renderable data. * @returns true if the meshes were built successfully. */ virtual bool GenerateStaticMeshLODs( UStaticMesh* StaticMesh, const class FStaticMeshLODGroup& LODGroup ) = 0; /** Builds a signed distance field volume for the given mesh. */ virtual void GenerateSignedDistanceFieldVolumeData( FString MeshName, const FMeshDataForDerivedDataTask& MeshData, float DistanceFieldResolutionScale, bool bGenerateAsIfTwoSided, class FDistanceFieldVolumeData& OutData) = 0; virtual int64_t MemoryForGenerateSignedDistanceFieldVolumeData( const FMeshDataForDerivedDataTask& MeshData, float DistanceFieldResolutionScale ) = 0; UE_DEPRECATED(5.6, "Provide FMeshDataForDerivedDataTask instead.") virtual void GenerateSignedDistanceFieldVolumeData( FString MeshName, const FSourceMeshDataForDerivedDataTask& SourceMeshData, const FStaticMeshLODResources& LODModel, class FQueuedThreadPool& ThreadPool, const TArray& SectionData, const FBoxSphereBounds3f& Bounds, float DistanceFieldResolutionScale, bool bGenerateAsIfTwoSided, class FDistanceFieldVolumeData& OutData) { FMeshDataForDerivedDataTask MeshData; MeshData.SourceMeshData = &SourceMeshData; MeshData.LODModel = &LODModel; MeshData.SectionData = SectionData; MeshData.Bounds = Bounds; GenerateSignedDistanceFieldVolumeData(MeshName, MeshData, DistanceFieldResolutionScale, bGenerateAsIfTwoSided, OutData); } virtual bool GenerateCardRepresentationData( FString MeshName, const FMeshDataForDerivedDataTask& MeshData, const class FDistanceFieldVolumeData* DistanceFieldVolumeData, int32 MaxLumenMeshCards, bool bGenerateAsIfTwoSided, class FCardRepresentationData& OutData) = 0; UE_DEPRECATED(5.6, "Provide FMeshDataForDerivedDataTask instead.") virtual bool GenerateCardRepresentationData( FString MeshName, const FSourceMeshDataForDerivedDataTask& SourceMeshData, const FStaticMeshLODResources& LODModel, class FQueuedThreadPool& ThreadPool, const TArray& SectionData, const FBoxSphereBounds& Bounds, const class FDistanceFieldVolumeData* DistanceFieldVolumeData, int32 MaxLumenMeshCards, bool bGenerateAsIfTwoSided, class FCardRepresentationData& OutData) { FMeshDataForDerivedDataTask MeshData; MeshData.SourceMeshData = &SourceMeshData; MeshData.LODModel = &LODModel; MeshData.SectionData = SectionData; MeshData.Bounds = (FBoxSphereBounds3f)Bounds; return GenerateCardRepresentationData(MeshName, MeshData, DistanceFieldVolumeData, MaxLumenMeshCards, bGenerateAsIfTwoSided, OutData); } /** Helper structure for skeletal mesh import options */ struct MeshBuildOptions { MeshBuildOptions() : BoneInfluenceLimit(0) , bRemoveDegenerateTriangles(false) , bComputeNormals(true) , bComputeTangents(true) , bUseMikkTSpace(false) , bComputeWeightedNormals(false) , bCacheOptimize(true) , TargetPlatform(nullptr) { } int32 BoneInfluenceLimit; bool bRemoveDegenerateTriangles; bool bComputeNormals; bool bComputeTangents; bool bUseMikkTSpace; bool bComputeWeightedNormals; bool bCacheOptimize; FOverlappingThresholds OverlappingThresholds; const class ITargetPlatform* TargetPlatform; void FillOptions(const FSkeletalMeshBuildSettings& SkeletalMeshBuildSettings) { OverlappingThresholds.ThresholdPosition = SkeletalMeshBuildSettings.ThresholdPosition; OverlappingThresholds.ThresholdTangentNormal = SkeletalMeshBuildSettings.ThresholdTangentNormal; OverlappingThresholds.ThresholdUV = SkeletalMeshBuildSettings.ThresholdUV; OverlappingThresholds.MorphThresholdPosition = SkeletalMeshBuildSettings.MorphThresholdPosition; BoneInfluenceLimit = SkeletalMeshBuildSettings.BoneInfluenceLimit; bComputeNormals = SkeletalMeshBuildSettings.bRecomputeNormals; bComputeTangents = SkeletalMeshBuildSettings.bRecomputeTangents; bUseMikkTSpace = SkeletalMeshBuildSettings.bUseMikkTSpace; bComputeWeightedNormals = SkeletalMeshBuildSettings.bComputeWeightedNormals; bRemoveDegenerateTriangles = SkeletalMeshBuildSettings.bRemoveDegenerates; } }; /** * Create all render specific data for a skeletal mesh LOD model * @returns true if the mesh was built successfully. */ virtual bool BuildSkeletalMesh( FSkeletalMeshLODModel& LODModel, const FString& SkeletalMeshName, const FReferenceSkeleton& RefSkeleton, const TArray& Influences, const TArray& Wedges, const TArray& Faces, const TArray& Points, const TArray& PointToOriginalMap, const MeshBuildOptions& BuildOptions = MeshBuildOptions(), TArray * OutWarningMessages = NULL, TArray * OutWarningNames = NULL ) = 0; /** Cache optimize the index buffer. */ virtual void CacheOptimizeIndexBuffer(TArray& Indices) = 0; /** Cache optimize the index buffer. */ virtual void CacheOptimizeIndexBuffer(TArray& Indices) = 0; /** Build adjacency information for the skeletal mesh used for tessellation. */ virtual void BuildSkeletalAdjacencyIndexBuffer( const TArray& VertexBuffer, const uint32 TexCoordCount, const TArray& Indices, TArray& OutPnAenIndices ) = 0; /** * Calculate The tangent, bi normal and normal for the triangle define by the tree SoftSkinVertex. * * @note The function will always fill properly the OutTangents array with 3 FVector. If the triangle is degenerated the OutTangent will contain zeroed vectors. * * @param VertexA - First triangle vertex. * @param VertexB - Second triangle vertex. * @param VertexC - Third triangle vertex. * @param OutTangents - The function allocate the TArray with 3 FVector, to represent the triangle tangent, bi normal and normal. * @param CompareThreshold - The threshold use to compare a tangent vector with zero. */ virtual void CalculateTriangleTangent(const FSoftSkinVertex& VertexA, const FSoftSkinVertex& VertexB, const FSoftSkinVertex& VertexC, TArray& OutTangents, float CompareThreshold) = 0; /** * Calculate the verts associated weighted to each bone of the skeleton. * The vertices returned are in the local space of the bone. * * @param SkeletalMesh The target skeletal mesh. * @param Infos The output array of vertices associated with each bone. * @param bOnlyDominant Controls whether a vertex is added to the info for a bone if it is most controlled by that bone, or if that bone has ANY influence on that vert. */ virtual void CalcBoneVertInfos( USkeletalMesh* SkeletalMesh, TArray& Infos, bool bOnlyDominant) = 0; /** * Convert a set of mesh components in their current pose to a static mesh. * @param InMeshComponents The mesh components we want to convert * @param InRootTransform The transform of the root of the mesh we want to output * @param InPackageName The package name to create the static mesh in. If this is empty then a dialog will be displayed to pick the mesh. * @return a new static mesh (specified by the user) */ virtual UStaticMesh* ConvertMeshesToStaticMesh(const TArray& InMeshComponents, const FTransform& InRootTransform = FTransform::Identity, const FString& InPackageName = FString()) = 0; /** * Calculates UV coordinates bounds for the given Skeletal Mesh * * @param InRawMesh - Skeletal Mesh to calculate the bounds for * @param OutBounds - Out texture bounds (min-max) */ virtual void CalculateTextureCoordinateBoundsForSkeletalMesh(const FSkeletalMeshLODModel& LODModel, TArray& OutBounds) const = 0; /** Calculates (new) non-overlapping UV coordinates for the given Skeletal Mesh * * @param LODModel - Skeletal Mesh to generate UV coordinates for * @param TextureResolution - Texture resolution to take into account while generating the UVs * @param OutTexCoords - New set of UV coordinates * @return bool - whether or not generating the UVs succeeded */ virtual bool GenerateUniqueUVsForSkeletalMesh(const FSkeletalMeshLODModel& LODModel, int32 TextureResolution, TArray& OutTexCoords) const = 0; /** * Remove Bones based on LODInfo setting * * @param SkeletalMesh Mesh that needs bones to be removed * @param LODIndex Desired LOD to remove bones [ 0 based ] * @param BoneNamesToRemove List of bone names to remove * * @return true if success */ virtual bool RemoveBonesFromMesh(USkeletalMesh* SkeletalMesh, int32 LODIndex, const TArray* BoneNamesToRemove) const = 0; /** * Calculates Tangents and Normals for a given set of vertex data * * @param InVertices Vertices that make up the mesh * @param InIndices Indices for the Vertex array * @param InUVs Texture coordinates (per-index based) * @param InSmoothingGroupIndices Smoothing group index (per-face based) * @param InTangentOptions Flags for Tangent calculation * @param OutTangentX Array to hold calculated Tangents * @param OutTangentY Array to hold calculated Bitangents * @param OutNormals Array to hold calculated normals (if already contains normals will use those instead for the tangent calculation) */ virtual void CalculateTangents(const TArray& InVertices, const TArray& InIndices, const TArray& InUVs, const TArray& InSmoothingGroupIndices, const uint32 InTangentOptions, TArray& OutTangentX, TArray& OutTangentY, TArray& OutNormals) const = 0; /** * Calculates MikkTSpace Tangents for a given set of vertex data with normals provided * * @param InVertices Vertices that make up the mesh * @param InIndices Indices for the Vertex array * @param InUVs Texture coordinates (per-index based) * @param InNormals Normals used for the tangent calculation (must be normalized) * @param bIgnoreDegenerateTriangles Flag for MikkTSpace to skip degenerate triangles fix-up path * @param OutTangentX Array to hold calculated Tangents * @param OutTangentY Array to hold calculated Bitangents */ virtual void CalculateMikkTSpaceTangents(const TArray& InVertices, const TArray& InIndices, const TArray& InUVs, const TArray& InNormals, bool bIgnoreDegenerateTriangles, TArray& OutTangentX, TArray& OutTangentY) const = 0; /** * Calculates Normals for a given set of vertex data * * @param InVertices Vertices that make up the mesh * @param InIndices Indices for the Vertex array * @param InUVs Texture coordinates (per-index based) * @param InSmoothingGroupIndices Smoothing group index (per-face based) * @param InTangentOptions Flags for Tangent calculation * @param OutNormals Array to hold calculated normals */ virtual void CalculateNormals(const TArray& InVertices, const TArray& InIndices, const TArray& InUVs, const TArray& InSmoothingGroupIndices, const uint32 InTangentOptions, TArray& OutNormals) const = 0; /** * Calculates the overlapping corners for a given set of vertex data * * @param InVertices Vertices that make up the mesh * @param InIndices Indices for the Vertex array * @param bIgnoreDegenerateTriangles Indicates if we should skip degenerate triangles * @param OutOverlappingCorners Container to hold the overlapping corners. For a vertex, lists all the overlapping vertices. */ virtual void CalculateOverlappingCorners(const TArray& InVertices, const TArray& InIndices, bool bIgnoreDegenerateTriangles, FOverlappingCorners& OutOverlappingCorners) const = 0; virtual void RecomputeTangentsAndNormalsForRawMesh(bool bRecomputeTangents, bool bRecomputeNormals, const FMeshBuildSettings& InBuildSettings, FRawMesh &OutRawMesh) const = 0; virtual void RecomputeTangentsAndNormalsForRawMesh(bool bRecomputeTangents, bool bRecomputeNormals, const FMeshBuildSettings& InBuildSettings, const FOverlappingCorners& InOverlappingCorners, FRawMesh &OutRawMesh) const = 0; virtual void FindOverlappingCorners(FOverlappingCorners& OutOverlappingCorners, const TArray& InVertices, const TArray& InIndices, float ComparisonThreshold) const = 0; /** Used to generate runtime skin weight data from Editor-only data */ virtual void GenerateRuntimeSkinWeightData( const FSkeletalMeshLODModel* ImportedModel, const TArray& InRawSkinWeights, bool bInUseHighPrecisionWeights, struct FRuntimeSkinWeightProfileData& InOutSkinWeightOverrideData) const = 0; /* * This function create the import data using the LODModel. You can call this function if you load an asset that was not re-import since the build refactor and the chunking is more agressive than the bake data in the LODModel. * You can also need this function if you create a skeletalmesh with LODModel instead of import data, so your newly created skeletalmesh can be build properly. * If the LODModel is not being pulled out of the old reduction storage, and bInResetReductionAsNeeded is true, then the reduction settings for that * LOD will be reset to avoid regenerating the mesh even more reduced. */ virtual void CreateImportDataFromLODModel(USkeletalMesh* InSkeletalMesh, bool bInResetReductionAsNeeded = false) const = 0; }; #if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_5 #include "Engine/MeshMerging.h" #endif