Advertisement
Guest User

Skeletal Mesh Merge Code

a guest
Dec 10th, 2022
62
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.85 KB | None | 0 0
  1. //Header File
  2.  
  3. // Fill out your copyright notice in the Description page of Project Settings.
  4. #pragma once
  5. #include "CoreMinimal.h"
  6. #include "Kismet/BlueprintFunctionLibrary.h"
  7. #include "UObject/NoExportTypes.h"
  8. #include "MeshMergeFunctionLibrary.generated.h"
  9. /**
  10. * Blueprint equivalent of FSkeleMeshMergeSectionMapping
  11. * Info to map all the sections from a single source skeletal mesh to
  12. * a final section entry in the merged skeletal mesh.
  13. */
  14. USTRUCT(BlueprintType)
  15. struct MyProject2_API FSkelMeshMergeSectionMapping_BP
  16. {
  17. GENERATED_BODY()
  18. /** Indices to final section entries of the merged skeletal mesh */
  19. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mesh Merge Params")
  20. TArray < int32 > SectionIDs;
  21. };
  22. /**
  23. * Used to wrap a set of UV Transforms for one mesh.
  24. */
  25. USTRUCT(BlueprintType)
  26. struct MyProject2_API FSkelMeshMergeUVTransform
  27. {
  28. GENERATED_BODY()
  29. /** A list of how UVs should be transformed on a given mesh, where index represents a specific UV channel. */
  30. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mesh Merge Params")
  31. TArray < FTransform > UVTransforms;
  32. };
  33. /**
  34. * Blueprint equivalent of FSkelMeshMergeUVTransforms
  35. * Info to map all the sections about how to transform their UVs
  36. */
  37. USTRUCT(BlueprintType)
  38. struct MyProject2_API FSkelMeshMergeUVTransformMapping
  39. {
  40. GENERATED_BODY()
  41. /** For each UV channel on each mesh, how the UVS should be transformed. */
  42. UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Mesh Merge Params")
  43. TArray < FSkelMeshMergeUVTransform > UVTransformsPerMesh;
  44. };
  45. /**
  46. * Struct containing all parameters used to perform a Skeletal Mesh merge.
  47. */
  48. USTRUCT(BlueprintType)
  49. struct MyProject2_API FSkeletalMeshMergeParams
  50. {
  51. GENERATED_BODY()
  52. FSkeletalMeshMergeParams()
  53. {
  54. StripTopLODS = 0;
  55. bNeedsCpuAccess = false;
  56. bSkeletonBefore = false;
  57. Skeleton = nullptr;
  58. }
  59. // An optional array to map sections from the source meshes to merged section entries
  60. UPROPERTY(EditAnywhere, BlueprintReadWrite)
  61. TArray < FSkelMeshMergeSectionMapping_BP > MeshSectionMappings;
  62. // An optional array to transform the UVs in each mesh
  63. UPROPERTY(EditAnywhere, BlueprintReadWrite)
  64. TArray < FSkelMeshMergeUVTransformMapping > UVTransformsPerMesh;
  65. // The list of skeletal meshes to merge.
  66. UPROPERTY(EditAnywhere, BlueprintReadWrite)
  67. TArray < USkeletalMesh* > MeshesToMerge;
  68. // The number of high LODs to remove from input meshes
  69. UPROPERTY(EditAnywhere, BlueprintReadWrite)
  70. int32 StripTopLODS;
  71. // Whether or not the resulting mesh needs to be accessed by the CPU for any reason (e.g. for spawning particle effects).
  72. UPROPERTY(EditAnywhere, BlueprintReadWrite)
  73. uint32 bNeedsCpuAccess : 1;
  74. // Update skeleton before merge. Otherwise, update after.
  75. // Skeleton must also be provided.
  76. UPROPERTY(EditAnywhere, BlueprintReadWrite)
  77. uint32 bSkeletonBefore : 1;
  78. // Skeleton that will be used for the merged mesh.
  79. // Leave empty if the generated skeleton is OK.
  80. UPROPERTY(EditAnywhere, BlueprintReadOnly)
  81. class USkeleton* Skeleton;
  82. };
  83. /**
  84. *
  85. */
  86. UCLASS()
  87. class MyProject2_API UMeshMergeFunctionLibrary : public UBlueprintFunctionLibrary
  88. {
  89. GENERATED_BODY()
  90. public:
  91. /**
  92. * Merges the given meshes into a single mesh.
  93. * @return The merged mesh (will be invalid if the merge failed).
  94. */
  95. UFUNCTION(BlueprintCallable, Category = "Mesh Merge", meta = (UnsafeDuringActorConstruction = "true"))
  96. static class USkeletalMesh* MergeMeshes(const FSkeletalMeshMergeParams& Params);
  97. };
  98.  
  99.  
  100.  
  101.  
  102.  
  103. //CPP
  104. // Fill out your copyright notice in the Description page of Project Settings.
  105. #include "MeshMergeFunctionLibrary.h"
  106. #include "SkeletalMeshMerge.h"
  107. #include "Engine/SkeletalMeshSocket.h"
  108. #include "Engine/SkeletalMesh.h"
  109. #include "Animation/Skeleton.h"
  110. static void ToMergeParams(const TArray<FSkelMeshMergeSectionMapping_BP>& InSectionMappings, TArray<FSkelMeshMergeSectionMapping>& OutSectionMappings)
  111. {
  112. if (InSectionMappings.Num() > 0)
  113. {
  114. OutSectionMappings.AddUninitialized(InSectionMappings.Num());
  115. for (int32 i = 0; i < InSectionMappings.Num(); ++i)
  116. {
  117. OutSectionMappings[i].SectionIDs = InSectionMappings[i].SectionIDs;
  118. }
  119. }
  120. };
  121. static void ToMergeParams(const TArray<FSkelMeshMergeUVTransformMapping>& InUVTransformsPerMesh, TArray<FSkelMeshMergeUVTransforms>& OutUVTransformsPerMesh)
  122. {
  123. if (InUVTransformsPerMesh.Num() > 0)
  124. {
  125. OutUVTransformsPerMesh.Empty();
  126. OutUVTransformsPerMesh.AddUninitialized(InUVTransformsPerMesh.Num());
  127. for (int32 i = 0; i < InUVTransformsPerMesh.Num(); ++i)
  128. {
  129. TArray<TArray<FTransform>>& OutUVTransforms = OutUVTransformsPerMesh[i].UVTransformsPerMesh;
  130. const TArray<FSkelMeshMergeUVTransform>& InUVTransforms = InUVTransformsPerMesh[i].UVTransformsPerMesh;
  131. if (InUVTransforms.Num() > 0)
  132. {
  133. OutUVTransforms.Empty();
  134. OutUVTransforms.AddUninitialized(InUVTransforms.Num());
  135. for (int32 j = 0; j < InUVTransforms.Num(); j++)
  136. {
  137. OutUVTransforms[i] = InUVTransforms[i].UVTransforms;
  138. }
  139. }
  140. }
  141. }
  142. };
  143. USkeletalMesh* UMeshMergeFunctionLibrary::MergeMeshes(const FSkeletalMeshMergeParams& Params)
  144. {
  145. TArray<USkeletalMesh*> MeshesToMergeCopy = Params.MeshesToMerge;
  146. MeshesToMergeCopy.RemoveAll([](USkeletalMesh* InMesh)
  147. {
  148. return InMesh == nullptr;
  149. });
  150. if (MeshesToMergeCopy.Num() <= 1)
  151. {
  152. UE_LOG(LogTemp, Warning, TEXT("Must provide multiple valid Skeletal Meshes in order to perform a merge."));
  153. return nullptr;
  154. }
  155. EMeshBufferAccess BufferAccess = Params.bNeedsCpuAccess ?
  156. EMeshBufferAccess::ForceCPUAndGPU :
  157. EMeshBufferAccess::Default;
  158. TArray<FSkelMeshMergeSectionMapping> SectionMappings;
  159. TArray<FSkelMeshMergeUVTransforms> UvTransforms;
  160. ToMergeParams(Params.MeshSectionMappings, SectionMappings);
  161. ToMergeParams(Params.UVTransformsPerMesh, UvTransforms);
  162. bool bRunDuplicateCheck = false;
  163. USkeletalMesh* BaseMesh = NewObject<USkeletalMesh>();
  164. if (Params.Skeleton && Params.bSkeletonBefore)
  165. {
  166. BaseMesh->Skeleton = Params.Skeleton;
  167. bRunDuplicateCheck = true;
  168. for (USkeletalMeshSocket* Socket : BaseMesh->GetMeshOnlySocketList())
  169. {
  170. if (Socket)
  171. {
  172. UE_LOG(LogTemp, Warning, TEXT("SkelMeshSocket: %s"), *(Socket->SocketName.ToString()));
  173. }
  174. }
  175. for (USkeletalMeshSocket* Socket : BaseMesh->Skeleton->Sockets)
  176. {
  177. if (Socket)
  178. {
  179. UE_LOG(LogTemp, Warning, TEXT("SkelSocket: %s"), *(Socket->SocketName.ToString()));
  180. }
  181. }
  182. }
  183. FSkeletalMeshMerge Merger(BaseMesh, MeshesToMergeCopy, SectionMappings, Params.StripTopLODS, BufferAccess, UvTransforms.GetData());
  184. if (!Merger.DoMerge())
  185. {
  186. UE_LOG(LogTemp, Warning, TEXT("Merge failed!"));
  187. return nullptr;
  188. }
  189. if (Params.Skeleton && !Params.bSkeletonBefore)
  190. {
  191. BaseMesh->Skeleton = Params.Skeleton;
  192. }
  193. if (bRunDuplicateCheck)
  194. {
  195. TArray<FName> SkelMeshSockets;
  196. TArray<FName> SkelSockets;
  197. for (USkeletalMeshSocket* Socket : BaseMesh->GetMeshOnlySocketList())
  198. {
  199. if (Socket)
  200. {
  201. SkelMeshSockets.Add(Socket->GetFName());
  202. UE_LOG(LogTemp, Warning, TEXT("SkelMeshSocket: %s"), *(Socket->SocketName.ToString()));
  203. }
  204. }
  205. for (USkeletalMeshSocket* Socket : BaseMesh->Skeleton->Sockets)
  206. {
  207. if (Socket)
  208. {
  209. SkelSockets.Add(Socket->GetFName());
  210. UE_LOG(LogTemp, Warning, TEXT("SkelSocket: %s"), *(Socket->SocketName.ToString()));
  211. }
  212. }
  213. TSet<FName> UniqueSkelMeshSockets;
  214. TSet<FName> UniqueSkelSockets;
  215. UniqueSkelMeshSockets.Append(SkelMeshSockets);
  216. UniqueSkelSockets.Append(SkelSockets);
  217. int32 Total = SkelSockets.Num() + SkelMeshSockets.Num();
  218. int32 UniqueTotal = UniqueSkelMeshSockets.Num() + UniqueSkelSockets.Num();
  219. UE_LOG(LogTemp, Warning, TEXT("SkelMeshSocketCount: %d | SkelSocketCount: %d | Combined: %d"), SkelMeshSockets.Num(), SkelSockets.Num(), Total);
  220. UE_LOG(LogTemp, Warning, TEXT("SkelMeshSocketCount: %d | SkelSocketCount: %d | Combined: %d"), UniqueSkelMeshSockets.Num(), UniqueSkelSockets.Num(), UniqueTotal);
  221. UE_LOG(LogTemp, Warning, TEXT("Found Duplicates: %s"), *((Total != UniqueTotal) ? FString("True") : FString("False")));
  222. }
  223. return BaseMesh;
  224. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement