├── .gitignore ├── LICENSE ├── README.md ├── Vertex Anim Toolset Documentation.pdf └── VertexAnimToolset ├── Content └── VertexAnimFunctions │ ├── ApplyPivot.uasset │ ├── AxisBasedTransform.uasset │ ├── DecodeQuat.uasset │ ├── DecodeVector.uasset │ ├── DecodeVectorHDR.uasset │ ├── ExtractAnimData_Pivot.uasset │ ├── ExtractAnimData_Pivot_Interp.uasset │ ├── ExtractAnimData_Skin.uasset │ ├── ExtractAnimData_Vert.uasset │ ├── ExtractAnimData_Vert_Interp.uasset │ ├── MultiPlyQUats.uasset │ ├── QuatNormalize.uasset │ ├── QuatRotateVector.uasset │ ├── QuatUnrotateVector.uasset │ ├── SlerpQuats.uasset │ └── TransformUniformScale.uasset ├── Resources └── Icon128.png ├── Source ├── VertexAnimToolset │ ├── Private │ │ ├── VertexAnimProfile.cpp │ │ └── VertexAnimToolset.cpp │ ├── Public │ │ ├── VertexAnimProfile.h │ │ └── VertexAnimToolset.h │ └── VertexAnimToolset.Build.cs └── VertexAnimToolsetEditor │ ├── Private │ ├── VATEditorUtils.cpp │ ├── VertexAnimToolsetEditor.cpp │ └── VertexAnimUtils.cpp │ ├── Public │ ├── VATEditorUtils.h │ ├── VertexAnimToolsetEditor.h │ └── VertexAnimUtils.h │ └── VertexAnimToolsetEditor.Build.cs └── VertexAnimToolset.uplugin /.gitignore: -------------------------------------------------------------------------------- 1 | # Visual Studio 2015 user specific files 2 | .vs/ 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | 22 | # Compiled Static libraries 23 | *.lai 24 | *.la 25 | *.a 26 | *.lib 27 | 28 | # Executables 29 | *.exe 30 | *.out 31 | *.app 32 | *.ipa 33 | 34 | # These project files can be generated by the engine 35 | *.xcodeproj 36 | *.xcworkspace 37 | *.sln 38 | *.suo 39 | *.opensdf 40 | *.sdf 41 | *.VC.db 42 | *.VC.opendb 43 | 44 | # Precompiled Assets 45 | SourceArt/**/*.png 46 | SourceArt/**/*.tga 47 | 48 | # Binary Files 49 | Binaries/* 50 | Plugins/*/Binaries/* 51 | */Binaries/* 52 | 53 | # Builds 54 | Build/* 55 | 56 | # Whitelist PakBlacklist-.txt files 57 | !Build/*/ 58 | Build/*/** 59 | !Build/*/PakBlacklist*.txt 60 | 61 | # Don't ignore icon files in Build 62 | !Build/**/*.ico 63 | 64 | # Built data for maps 65 | *_BuiltData.uasset 66 | 67 | # Configuration files generated by the Editor 68 | Saved/* 69 | 70 | # Compiled source files for the engine to use 71 | Intermediate/* 72 | Plugins/*/Intermediate/* 73 | */Intermediate/* 74 | 75 | # Cache files for the editor to use 76 | DerivedDataCache/* 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Rexocrates 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vertex Anim Toolset 2 | Unreal Engine tools for baking Skeletal Mesh animation into textures to animate meshes through the material shader 3 | 4 | ATTENTION! Epic made a plugin called AnimToTexture for the City Sample of UE 5 which does a lot of the same things as this plugin. You should use that instead if you are using UE 5 and up versions. You can find more info about the AnimToTexture plugin at minute 8:48 of this video (https://www.youtube.com/watch?v=h_dJtk3BCyg). 5 | 6 | - Video: [Crowd of 10.000 animated Mannequins](https://vimeo.com/584561248) 7 | - Video: [Crowd of 2.500 animated Mannequins with multiple animations](https://vimeo.com/584595823) 8 | - Video: [Example process](https://vimeo.com/584563404) 9 | - Example project: [Rexocrates/VAT_Example_Project](https://github.com/Rexocrates/VAT_Example_Project) 10 | -------------------------------------------------------------------------------- /Vertex Anim Toolset Documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/Vertex Anim Toolset Documentation.pdf -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/ApplyPivot.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/ApplyPivot.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/AxisBasedTransform.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/AxisBasedTransform.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/DecodeQuat.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/DecodeQuat.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/DecodeVector.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/DecodeVector.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/DecodeVectorHDR.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/DecodeVectorHDR.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Pivot.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Pivot.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Pivot_Interp.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Pivot_Interp.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Skin.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Skin.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Vert.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Vert.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Vert_Interp.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/ExtractAnimData_Vert_Interp.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/MultiPlyQUats.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/MultiPlyQUats.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/QuatNormalize.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/QuatNormalize.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/QuatRotateVector.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/QuatRotateVector.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/QuatUnrotateVector.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/QuatUnrotateVector.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/SlerpQuats.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/SlerpQuats.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Content/VertexAnimFunctions/TransformUniformScale.uasset: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Content/VertexAnimFunctions/TransformUniformScale.uasset -------------------------------------------------------------------------------- /VertexAnimToolset/Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Resources/Icon128.png -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolset/Private/VertexAnimProfile.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #include "VertexAnimProfile.h" 4 | 5 | #include "UObject/ObjectMacros.h" 6 | #include "Runtime/Engine/Classes/Engine/CanvasRenderTarget2D.h" 7 | 8 | #include "Runtime/Engine/Classes/Kismet/KismetRenderingLibrary.h" 9 | 10 | #include "Rendering/SkeletalMeshModel.h" 11 | 12 | 13 | int32 UVertexAnimProfile::CalcTotalNumOfFrames_Vert() const 14 | { 15 | int32 Out = 0; 16 | 17 | for (int32 i = 0; i < Anims_Vert.Num(); i++) 18 | { 19 | Out += Anims_Vert[i].NumFrames; 20 | } 21 | 22 | return Out; 23 | } 24 | 25 | int32 UVertexAnimProfile::CalcTotalRequiredHeight_Vert() const 26 | { 27 | return RowsPerFrame_Vert * CalcTotalNumOfFrames_Vert(); 28 | } 29 | 30 | int32 UVertexAnimProfile::CalcTotalNumOfFrames_Bone() const 31 | { 32 | int32 Out = 0; 33 | 34 | for (int32 i = 0; i < Anims_Bone.Num(); i++) 35 | { 36 | Out += Anims_Bone[i].NumFrames; 37 | } 38 | 39 | return Out; 40 | } 41 | 42 | int32 UVertexAnimProfile::CalcTotalRequiredHeight_Bone() const 43 | { 44 | return CalcTotalNumOfFrames_Bone(); 45 | } 46 | 47 | int32 UVertexAnimProfile::CalcStartHeightOfAnim_Vert(const int32 AnimIndex) const 48 | { 49 | int32 Out = 0; 50 | 51 | for (int32 i = 0; i < AnimIndex; i++) 52 | { 53 | Out += Anims_Vert[i].NumFrames; 54 | } 55 | 56 | return RowsPerFrame_Vert * Out; 57 | } 58 | 59 | int32 UVertexAnimProfile::CalcStartHeightOfAnim_Bone(const int32 AnimIndex) const 60 | { 61 | int32 Out = 0; 62 | 63 | for (int32 i = 0; i < AnimIndex; i++) 64 | { 65 | Out += Anims_Bone[i].NumFrames; 66 | } 67 | 68 | return Out + 1; 69 | } 70 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolset/Private/VertexAnimToolset.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #include "VertexAnimToolset.h" 4 | 5 | //-------------------------------------- 6 | #include "Interfaces/IPluginManager.h" 7 | #include "Misc/Paths.h" 8 | #include "ShaderCore.h" 9 | 10 | #define LOCTEXT_NAMESPACE "FVertexAnimToolsetModule" 11 | 12 | void FVertexAnimToolsetModule::StartupModule() 13 | { 14 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 15 | } 16 | 17 | void FVertexAnimToolsetModule::ShutdownModule() 18 | { 19 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 20 | // we call this function before unloading the module. 21 | } 22 | 23 | #undef LOCTEXT_NAMESPACE 24 | 25 | IMPLEMENT_MODULE(FVertexAnimToolsetModule, VertexAnimToolset) -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolset/Public/VertexAnimProfile.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Engine/DataAsset.h" 7 | #include "VertexAnimProfile.generated.h" 8 | 9 | class UTexture2D; 10 | class UStaticMesh; 11 | 12 | // Struct Holding helper data specific to an Animation Sequence needed for the baking process 13 | USTRUCT(BlueprintType) 14 | struct VERTEXANIMTOOLSET_API FVASequenceData 15 | { 16 | GENERATED_BODY() 17 | public: 18 | UPROPERTY(EditAnywhere, Category = BakeSequence) 19 | UAnimationAsset* SequenceRef = NULL; 20 | 21 | UPROPERTY(EditAnywhere, Category = BakeSequence) 22 | int32 NumFrames = 8; 23 | 24 | UPROPERTY(EditAnywhere, Category = BakeSequenceGenerated) 25 | int32 AnimStart_Generated = 0; 26 | 27 | UPROPERTY(EditAnywhere, Category = BakeSequenceGenerated) 28 | float Speed_Generated = 1.f; 29 | }; 30 | 31 | // Data asset holding all the helper data needed for the baking process 32 | UCLASS(BlueprintType) 33 | class VERTEXANIMTOOLSET_API UVertexAnimProfile : public UDataAsset 34 | { 35 | GENERATED_BODY() 36 | public: 37 | 38 | UPROPERTY(EditAnywhere, Category = AnimProfile) 39 | bool AutoSize = true; 40 | UPROPERTY(EditAnywhere, Category = AnimProfile) 41 | int32 MaxWidth = 2048; 42 | 43 | UPROPERTY(EditAnywhere, Category = VertAnim) 44 | bool UVMergeDuplicateVerts = true; 45 | UPROPERTY(EditAnywhere, Category = VertAnim) 46 | FIntPoint OverrideSize_Vert = FIntPoint(0, 0); 47 | UPROPERTY(EditAnywhere, Category = VertAnim) 48 | TArray Anims_Vert; 49 | 50 | UPROPERTY(EditAnywhere, Category = BoneAnim) 51 | bool FullBoneSkinning = false; 52 | UPROPERTY(EditAnywhere, Category = BoneAnim) 53 | FIntPoint OverrideSize_Bone = FIntPoint(0, 0); 54 | UPROPERTY(EditAnywhere, Category = BoneAnim) 55 | TArray Anims_Bone; 56 | 57 | UPROPERTY(EditAnywhere, Category = AnimProfileGenerated) 58 | UStaticMesh* StaticMesh = NULL; 59 | 60 | UPROPERTY(EditAnywhere, Category = Generated_VertAnim) 61 | int32 UVChannel_VertAnim = -1; 62 | UPROPERTY(EditAnywhere, Category = Generated_VertAnim) 63 | UTexture2D* OffsetsTexture = NULL; 64 | UPROPERTY(EditAnywhere, Category = Generated_VertAnim) 65 | UTexture2D* NormalsTexture = NULL; 66 | 67 | 68 | UPROPERTY(EditAnywhere, Category = Generated_VertAnim) 69 | int32 RowsPerFrame_Vert= 0; 70 | UPROPERTY(EditAnywhere, Category = Generated_VertAnim) 71 | float MaxValueOffset_Vert = 0; 72 | 73 | UPROPERTY(EditAnywhere, Category = Generated_BoneAnim) 74 | int32 UVChannel_BoneAnim = -1; 75 | UPROPERTY(EditAnywhere, Category = Generated_BoneAnim) 76 | int32 UVChannel_BoneAnim_Full = -1; 77 | UPROPERTY(EditAnywhere, Category = Generated_BoneAnim) 78 | UTexture2D* BonePosTexture = NULL; 79 | UPROPERTY(EditAnywhere, Category = Generated_BoneAnim) 80 | UTexture2D* BoneRotTexture = NULL; 81 | 82 | UPROPERTY(EditAnywhere, Category = Generated_BoneAnim) 83 | float MaxValuePosition_Bone = 0; 84 | 85 | int32 CalcTotalNumOfFrames_Vert() const; 86 | int32 CalcTotalRequiredHeight_Vert() const; 87 | 88 | int32 CalcTotalNumOfFrames_Bone() const; 89 | int32 CalcTotalRequiredHeight_Bone() const; 90 | 91 | int32 CalcStartHeightOfAnim_Vert(const int32 AnimIndex) const; 92 | int32 CalcStartHeightOfAnim_Bone(const int32 AnimIndex) const; 93 | 94 | }; 95 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolset/Public/VertexAnimToolset.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Modules/ModuleInterface.h" 8 | #include "Modules/ModuleManager.h" 9 | 10 | class FVertexAnimToolsetModule : public IModuleInterface 11 | { 12 | public: 13 | 14 | /** IModuleInterface implementation */ 15 | virtual void StartupModule() override; 16 | virtual void ShutdownModule() override; 17 | 18 | }; 19 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolset/VertexAnimToolset.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class VertexAnimToolset : ModuleRules 6 | { 7 | public VertexAnimToolset(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | 26 | PublicDependencyModuleNames.AddRange( 27 | new string[] 28 | { 29 | 30 | "Core", 31 | "CoreUObject", 32 | "Engine", 33 | "RHI", 34 | "Engine", 35 | "RenderCore", 36 | // ... add other public dependencies that you statically link with here ... 37 | } 38 | ); 39 | 40 | 41 | PrivateDependencyModuleNames.AddRange( 42 | new string[] 43 | { 44 | "Projects", 45 | // ... add private dependencies that you statically link with here ... 46 | } 47 | ); 48 | 49 | 50 | DynamicallyLoadedModuleNames.AddRange( 51 | new string[] 52 | { 53 | // ... add any modules that your module loads dynamically here ... 54 | } 55 | ); 56 | 57 | PrecompileForTargets = PrecompileTargetsType.Any; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/Private/VATEditorUtils.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rexocrates/Vertex_Anim_Toolset/9112c48024471c9ed0ab225ccb06af7ab70b65a4/VertexAnimToolset/Source/VertexAnimToolsetEditor/Private/VATEditorUtils.cpp -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/Private/VertexAnimToolsetEditor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #include "VertexAnimToolsetEditor.h" 4 | 5 | #include "IPersonaToolkit.h" 6 | #include "Rendering/SkeletalMeshModel.h" 7 | #include "Rendering/SkeletalMeshRenderData.h" 8 | 9 | #include "Animation/DebugSkelMeshComponent.h" 10 | 11 | 12 | #include "Textures/SlateIcon.h" 13 | #include "Styling/SlateTypes.h" 14 | #include "Framework/Commands/UIAction.h" 15 | #include "Framework/Commands/UICommandList.h" 16 | #include "Framework/MultiBox/MultiBoxExtender.h" 17 | #include "Framework/MultiBox/MultiBoxBuilder.h" 18 | 19 | #include "Engine/StaticMesh.h" 20 | #include "Materials/Material.h" 21 | #include "Materials/MaterialInstanceDynamic.h" 22 | 23 | #include "RawMesh.h" 24 | #include "StaticMeshResources.h" 25 | #include "MeshBuild.h" 26 | 27 | #include "Rendering/SkeletalMeshModel.h" 28 | #include "Rendering/SkeletalMeshRenderData.h" 29 | 30 | #include "Engine/SkeletalMesh.h" 31 | #include "SkeletalRenderPublic.h" 32 | #include "Runtime/Engine/Private/SkeletalRenderCPUSkin.h" 33 | 34 | #include "Animation/MorphTarget.h" 35 | 36 | #include "Developer/AssetTools/Public/IAssetTools.h" 37 | #include "Developer/AssetTools/Public/AssetToolsModule.h" 38 | 39 | #include "Toolkits/AssetEditorManager.h" 40 | #include "Dialogs/DlgPickAssetPath.h" 41 | #include "AssetRegistryModule.h" 42 | 43 | #include "VertexAnimUtils.h" 44 | #include "VertexAnimProfile.h" 45 | 46 | 47 | #include "Framework/Notifications/NotificationManager.h" 48 | #include "Widgets/Notifications/SNotificationList.h" 49 | 50 | //#include "Engine.h" 51 | 52 | #include "Misc/FeedbackContext.h" 53 | #include "Misc/MessageDialog.h" 54 | 55 | #include "IPersonaPreviewScene.h" 56 | #include "AssetViewerSettings.h" 57 | #include "RenderingThread.h" 58 | 59 | #include "Components/PoseableMeshComponent.h" 60 | 61 | #include "AnimationRuntime.h" 62 | 63 | //-------------------------------------- 64 | #include "Interfaces/IPluginManager.h" 65 | #include "Misc/Paths.h" 66 | #include "ShaderCore.h" 67 | 68 | #include "Animation/AnimSequence.h" 69 | 70 | //#include "Runtime/Engine/Classes/Kismet/KismetRenderingLibrary.h" 71 | 72 | #include "Kismet/KismetRenderingLibrary.h" 73 | 74 | #include "PackageTools.h" 75 | 76 | #include "VATEditorUtils.h" 77 | 78 | #define LOCTEXT_NAMESPACE "FVertexAnimToolsetEditorModule" 79 | 80 | //#define YESSCENETICK 81 | 82 | void FVertexAnimToolsetEditorModule::StartupModule() 83 | { 84 | // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module 85 | // hook up level editor extension for skeletal mesh conversion 86 | 87 | //FString PluginShaderDir = FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("VertexAnimToolset"))->GetBaseDir(), TEXT("Shaders")); 88 | //AddShaderSourceDirectoryMapping(TEXT("/Plugin/VertexAnimToolset"), PluginShaderDir); 89 | 90 | 91 | ModuleLoadedDelegateHandle = FModuleManager::Get().OnModulesChanged().AddLambda([this](FName InModuleName, EModuleChangeReason InChangeReason) 92 | { 93 | if (InChangeReason == EModuleChangeReason::ModuleLoaded) 94 | { 95 | if (InModuleName == "SkeletalMeshEditor") 96 | { 97 | //check(false); TRIGGERED 98 | AddSkeletalMeshEditorToolbarExtender(); 99 | } 100 | } 101 | }); 102 | } 103 | 104 | void FVertexAnimToolsetEditorModule::ShutdownModule() 105 | { 106 | // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, 107 | // we call this function before unloading the module. 108 | //RemoveAnimationEditorToolbarExtender(); 109 | 110 | // This is not causing the stuck on exiting Unreal?? 111 | RemoveSkeletalMeshEditorToolbarExtender(); 112 | FModuleManager::Get().OnModulesChanged().Remove(ModuleLoadedDelegateHandle); 113 | } 114 | 115 | TSharedRef FVertexAnimToolsetEditorModule::GetAnimationEditorToolbarExtender(const TSharedRef CommandList, TSharedRef InAnimationEditor) 116 | { 117 | TSharedRef Extender = MakeShareable(new FExtender); 118 | 119 | UDebugSkelMeshComponent* MeshComponent = InAnimationEditor->GetPersonaToolkit()->GetPreviewMeshComponent(); 120 | TSharedRef Scene = InAnimationEditor->GetPersonaToolkit()->GetPreviewScene(); 121 | 122 | Extender->AddToolBarExtension( 123 | "Asset", 124 | EExtensionHook::After, 125 | CommandList, 126 | FToolBarExtensionDelegate::CreateRaw(this, &FVertexAnimToolsetEditorModule::HandleAddSkeletalMeshActionExtenderToToolbar, MeshComponent) 127 | ); 128 | 129 | return Extender; 130 | 131 | } 132 | 133 | void FVertexAnimToolsetEditorModule::HandleAddSkeletalMeshActionExtenderToToolbar(FToolBarBuilder & ParentToolbarBuilder, UDebugSkelMeshComponent * InMeshComponent) 134 | { 135 | 136 | ParentToolbarBuilder.AddToolBarButton( 137 | FUIAction(FExecuteAction::CreateLambda([this, InMeshComponent]() 138 | { 139 | FVATEditorUtils::DoBakeProcess(InMeshComponent); 140 | })), 141 | NAME_None, 142 | LOCTEXT("BakeAnim", "Bake Anim"), 143 | LOCTEXT("BakeAnimToTextureTooltip", "Bake animation frames to textures"), 144 | FSlateIcon("EditorStyle", "Persona.TogglePreviewAsset", "Persona.TogglePreviewAsset.Small") 145 | ); 146 | } 147 | 148 | void FVertexAnimToolsetEditorModule::AddSkeletalMeshEditorToolbarExtender() 149 | { 150 | ISkeletalMeshEditorModule& SkeletalMeshEditorModule = FModuleManager::Get().LoadModuleChecked("SkeletalMeshEditor"); 151 | auto& ToolbarExtenders = SkeletalMeshEditorModule.GetAllSkeletalMeshEditorToolbarExtenders(); 152 | 153 | ToolbarExtenders.Add( 154 | ISkeletalMeshEditorModule::FSkeletalMeshEditorToolbarExtender::CreateRaw(this, &FVertexAnimToolsetEditorModule::GetSkeletalMeshEditorToolbarExtender)); 155 | SkeletalMeshEditorExtenderHandle = ToolbarExtenders.Last().GetHandle(); 156 | } 157 | 158 | void FVertexAnimToolsetEditorModule::RemoveSkeletalMeshEditorToolbarExtender() 159 | { 160 | ISkeletalMeshEditorModule* SkeletalMeshEditorModule = FModuleManager::Get().GetModulePtr("SkeletalMeshEditor"); 161 | if (SkeletalMeshEditorModule) 162 | { 163 | typedef ISkeletalMeshEditorModule::FSkeletalMeshEditorToolbarExtender DelegateType; 164 | SkeletalMeshEditorModule->GetAllSkeletalMeshEditorToolbarExtenders().RemoveAll([=](const DelegateType& In) { return In.GetHandle() == SkeletalMeshEditorExtenderHandle; }); 165 | } 166 | } 167 | 168 | TSharedRef FVertexAnimToolsetEditorModule::GetSkeletalMeshEditorToolbarExtender(const TSharedRef CommandList, TSharedRef InSkeletalMeshEditor) 169 | { 170 | TSharedRef Extender = MakeShareable(new FExtender); 171 | 172 | //UMeshComponent* MeshComponent = InSkeletalMeshEditor->GetPersonaToolkit()->GetPreviewMeshComponent(); 173 | UDebugSkelMeshComponent* MeshComponent = InSkeletalMeshEditor->GetPersonaToolkit()->GetPreviewMeshComponent(); 174 | 175 | Extender->AddToolBarExtension( 176 | "Asset", 177 | EExtensionHook::After, 178 | CommandList, 179 | FToolBarExtensionDelegate::CreateRaw(this, &FVertexAnimToolsetEditorModule::HandleAddSkeletalMeshActionExtenderToToolbar, MeshComponent) 180 | ); 181 | 182 | return Extender; 183 | } 184 | 185 | 186 | #undef LOCTEXT_NAMESPACE 187 | 188 | IMPLEMENT_MODULE(FVertexAnimToolsetEditorModule, VertexAnimToolsetEditor) -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/Private/VertexAnimUtils.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #include "VertexAnimUtils.h" 4 | 5 | #include "IAnimationEditor.h" 6 | 7 | #include "VertexAnimProfile.h" 8 | 9 | #include "Misc/MessageDialog.h" 10 | #include "Modules/ModuleManager.h" 11 | #include "Misc/PackageName.h" 12 | #include "Widgets/Layout/SBorder.h" 13 | #include "Widgets/Text/STextBlock.h" 14 | #include "Widgets/Layout/SUniformGridPanel.h" 15 | #include "Widgets/Input/SEditableTextBox.h" 16 | #include "Widgets/Input/SButton.h" 17 | #include "Widgets/Input/SCheckBox.h" 18 | 19 | #include "EditorStyleSet.h" 20 | #include "Editor.h" 21 | #include "IContentBrowserSingleton.h" 22 | #include "ContentBrowserModule.h" 23 | 24 | #include "Engine/TextureRenderTarget2D.h" 25 | 26 | 27 | #include "Rendering/SkeletalMeshModel.h" 28 | #include "Rendering/SkeletalMeshRenderData.h" 29 | 30 | #include "Engine/SkeletalMesh.h" 31 | #include "SkeletalRenderPublic.h" 32 | #include "Runtime/Engine/Private/SkeletalRenderCPUSkin.h" 33 | 34 | #include "Animation/MorphTarget.h" 35 | #include "VertexAnimProfile.h" 36 | 37 | #include "MeshDescriptionOperations.h" 38 | #include "UVMapSettings.h" 39 | #include "MeshAttributeArray.h" 40 | #include "MeshDescription.h" 41 | #include "MeshAttributes.h" 42 | 43 | 44 | #include "Animation/AnimSequence.h" 45 | 46 | #include "Misc/FeedbackContext.h" 47 | 48 | 49 | 50 | 51 | 52 | #include "IPersonaToolkit.h" 53 | #include "Rendering/SkeletalMeshModel.h" 54 | #include "Rendering/SkeletalMeshRenderData.h" 55 | 56 | #include "Animation/DebugSkelMeshComponent.h" 57 | 58 | 59 | #include "Textures/SlateIcon.h" 60 | #include "Styling/SlateTypes.h" 61 | #include "Framework/Commands/UIAction.h" 62 | #include "Framework/Commands/UICommandList.h" 63 | #include "Framework/MultiBox/MultiBoxExtender.h" 64 | #include "Framework/MultiBox/MultiBoxBuilder.h" 65 | 66 | #include "Engine/StaticMesh.h" 67 | #include "Materials/Material.h" 68 | #include "Materials/MaterialInstanceDynamic.h" 69 | 70 | #include "RawMesh.h" 71 | #include "StaticMeshResources.h" 72 | #include "MeshBuild.h" 73 | 74 | #include "Rendering/SkeletalMeshModel.h" 75 | #include "Rendering/SkeletalMeshRenderData.h" 76 | 77 | #include "Engine/SkeletalMesh.h" 78 | #include "SkeletalRenderPublic.h" 79 | #include "Runtime/Engine/Private/SkeletalRenderCPUSkin.h" 80 | 81 | #include "Animation/MorphTarget.h" 82 | 83 | #include "Developer/AssetTools/Public/IAssetTools.h" 84 | #include "Developer/AssetTools/Public/AssetToolsModule.h" 85 | 86 | #include "Toolkits/AssetEditorManager.h" 87 | #include "Dialogs/DlgPickAssetPath.h" 88 | #include "AssetRegistryModule.h" 89 | 90 | #include "VertexAnimProfile.h" 91 | 92 | 93 | #include "Framework/Notifications/NotificationManager.h" 94 | #include "Widgets/Notifications/SNotificationList.h" 95 | 96 | #include "Engine.h" 97 | 98 | #include "Misc/FeedbackContext.h" 99 | #include "Misc/MessageDialog.h" 100 | 101 | #include "IPersonaPreviewScene.h" 102 | #include "AssetViewerSettings.h" 103 | #include "RenderingThread.h" 104 | 105 | #include "Components/PoseableMeshComponent.h" 106 | 107 | #include "AnimationRuntime.h" 108 | 109 | //-------------------------------------- 110 | #include "Interfaces/IPluginManager.h" 111 | #include "Misc/Paths.h" 112 | #include "ShaderCore.h" 113 | 114 | #include "VertexAnimUtils.h" 115 | 116 | #include "Animation/AnimSequence.h" 117 | 118 | #include "Kismet/KismetRenderingLibrary.h" 119 | 120 | #include "PackageTools.h" 121 | 122 | #include "Animation/AnimSequence.h" 123 | 124 | #include "Rendering/SkinWeightVertexBuffer.h" 125 | 126 | 127 | #include "Misc/App.h" 128 | #include "RenderingThread.h" 129 | #include "GameFramework/PlayerController.h" 130 | #include "ContentStreaming.h" 131 | #include "DrawDebugHelpers.h" 132 | #include "UnrealEngine.h" 133 | #include "SkeletalRenderPublic.h" 134 | 135 | #include "Animation/AnimStats.h" 136 | #include "Engine/SkeletalMeshSocket.h" 137 | #include "PhysicsEngine/PhysicsAsset.h" 138 | #include "EngineGlobals.h" 139 | #include "PrimitiveSceneProxy.h" 140 | #include "Engine/CollisionProfile.h" 141 | #include "Rendering/SkinWeightVertexBuffer.h" 142 | #include "SkeletalMeshTypes.h" 143 | #include "Animation/MorphTarget.h" 144 | #include "AnimationRuntime.h" 145 | 146 | #include "Animation/AnimSingleNodeInstance.h" 147 | 148 | 149 | #define LOCTEXT_NAMESPACE "PickAssetDialog" 150 | 151 | float FVertexAnimUtils::EncodeFloat(const float & T, const float& Bound) 152 | { 153 | // Divide to normalize, + 1 * 0.5 to account for negative Values 154 | return ((T / Bound) + 1.f) * 0.5f; 155 | } 156 | 157 | float FVertexAnimUtils::DeEncodeFloat(const float & T, const float & Bound) 158 | { 159 | return ((T * 2.f) - 1.f) * Bound; 160 | } 161 | 162 | FVector FVertexAnimUtils::DeEncodeVec(const FVector4& T, const float& Bound) 163 | { 164 | return (((FVector(T) * 2.f) - 1.f) * T.W) * Bound; 165 | } 166 | 167 | FVector4 FVertexAnimUtils::BitEncodeVecId(const FVector T, const float Bound, const int32 Id) 168 | { 169 | const FVector N = ((T / Bound) +1.0) * 0.5; 170 | 171 | uint32 RI = N.X * 1023; 172 | uint32 GI = N.Y * 1023; 173 | uint32 BI = N.Z * 1023; 174 | 175 | uint8 R8 = (uint8)(RI); 176 | uint8 G8 = (uint8)(GI); 177 | uint8 B8 = (uint8)(BI); 178 | 179 | // Should I be doing and & on these?? 180 | uint8 RA = (uint8)((RI >> 8) & 0x3); 181 | uint8 GA = (uint8)((GI >> 6) & 0xc); 182 | uint8 BA = (uint8)((BI >> 4) & 0x30); 183 | uint8 IA = (uint8)(Id) << 6; 184 | 185 | uint8 A8 = ((RA | GA) | BA) | IA; 186 | 187 | return FVector4(R8 / 255.0, G8 / 255.0, B8 / 255.0, A8 / 255.0); 188 | } 189 | 190 | FVector4 FVertexAnimUtils::BitEncodeVecId_HD(const FVector T, const float Bound, const int32 Id) 191 | { 192 | const FVector N = ((T / Bound) + 1.0) * 0.5; 193 | 194 | uint32 RI = N.X * 0xFFFFF; 195 | uint32 GI = N.Y * 0xFFFFF; 196 | uint32 BI = N.Z * 0xFFFFF; 197 | 198 | uint16 R8 = (uint16)(RI); 199 | uint16 G8 = (uint16)(GI); 200 | uint16 B8 = (uint16)(BI); 201 | 202 | // Should I be doing and & on these?? 203 | uint16 RA = (uint16)((RI >> 16) & 0xF); 204 | uint16 GA = (uint16)((GI >> 12) & 0xF0); 205 | uint16 BA = (uint16)((BI >> 8) & 0xF00); 206 | uint16 IA = (uint16)(Id) << 12; 207 | 208 | //UE_LOG(LogUnrealMath, Warning, TEXT("RI %i, R8 %i || RA %i || IA %i"), RI, R8, RA, IA); 209 | 210 | uint16 A8 = ((RA | GA) | BA) | IA; 211 | 212 | return FVector4( 213 | -1.0 + ((R8 / 65535.0) * 2.0), 214 | -1.0 + ((G8 / 65535.0) * 2.0), 215 | -1.0 + ((B8 / 65535.0) * 2.0), 216 | -1.0 + ((A8 / 65535.0) * 2.0)); 217 | 218 | } 219 | 220 | 221 | int32 FVertexAnimUtils::Grid2DIndex(const int32& X, const int32& Y, const int32& Width) 222 | { 223 | //(LocationX * GridSize.Height) + LocationY // CellIndex 224 | //return (X * Height) + Y; 225 | return (Y * Width) + X; 226 | } 227 | // This should be Y with Width 228 | int32 FVertexAnimUtils::Grid2D_X(const int32 & Index, const int32 & Width) 229 | { 230 | // Original // X = CellIndex / GridSize.Height 231 | //return Index % Height; 232 | return Index % Width; 233 | } 234 | 235 | // This Should be X with Width 236 | int32 FVertexAnimUtils::Grid2D_Y(const int32 & Index, const int32 & Width) 237 | { 238 | // For Y = CellIndex % GridSize.Height 239 | //return Index / Height; 240 | return Index / Width; 241 | } 242 | 243 | 244 | 245 | // Helper function for ConvertMeshesToStaticMesh 246 | static void AddOrDuplicateMaterial(UMaterialInterface* InMaterialInterface, const FString& InPackageName, TArray& OutMaterials) 247 | { 248 | if (InMaterialInterface && !InMaterialInterface->GetOuter()->IsA()) 249 | { 250 | // Convert runtime material instances to new concrete material instances 251 | // Create new package 252 | FString OriginalMaterialName = InMaterialInterface->GetName(); 253 | FString MaterialPath = FPackageName::GetLongPackagePath(InPackageName) / OriginalMaterialName; 254 | FString MaterialName; 255 | FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked("AssetTools"); 256 | AssetToolsModule.Get().CreateUniqueAssetName(MaterialPath, TEXT(""), MaterialPath, MaterialName); 257 | UPackage* MaterialPackage = CreatePackage(NULL, *MaterialPath); 258 | 259 | // Duplicate the object into the new package 260 | UMaterialInterface* NewMaterialInterface = DuplicateObject(InMaterialInterface, MaterialPackage, *MaterialName); 261 | NewMaterialInterface->SetFlags(RF_Public | RF_Standalone); 262 | 263 | if (UMaterialInstanceDynamic* MaterialInstanceDynamic = Cast(NewMaterialInterface)) 264 | { 265 | UMaterialInstanceDynamic* OldMaterialInstanceDynamic = CastChecked(InMaterialInterface); 266 | MaterialInstanceDynamic->K2_CopyMaterialInstanceParameters(OldMaterialInstanceDynamic); 267 | } 268 | 269 | NewMaterialInterface->MarkPackageDirty(); 270 | 271 | FAssetRegistryModule::AssetCreated(NewMaterialInterface); 272 | 273 | InMaterialInterface = NewMaterialInterface; 274 | } 275 | 276 | OutMaterials.Add(InMaterialInterface); 277 | } 278 | 279 | // Helper function for ConvertMeshesToStaticMesh 280 | template 281 | static void ProcessMaterials(ComponentType* InComponent, const FString& InPackageName, TArray& OutMaterials) 282 | { 283 | const int32 NumMaterials = InComponent->GetNumMaterials(); 284 | for (int32 MaterialIndex = 0; MaterialIndex < NumMaterials; MaterialIndex++) 285 | { 286 | UMaterialInterface* MaterialInterface = InComponent->GetMaterial(MaterialIndex); 287 | AddOrDuplicateMaterial(MaterialInterface, InPackageName, OutMaterials); 288 | } 289 | } 290 | 291 | // Helper function for ConvertMeshesToStaticMesh 292 | static bool IsValidSkinnedMeshComponent(USkinnedMeshComponent* InComponent) 293 | { 294 | return InComponent && InComponent->MeshObject && InComponent->IsVisible(); 295 | } 296 | 297 | /** Helper struct for tracking validity of optional buffers */ 298 | struct FRawMeshTracker 299 | { 300 | FRawMeshTracker() 301 | : bValidColors(false) 302 | { 303 | FMemory::Memset(bValidTexCoords, 0); 304 | } 305 | 306 | bool bValidTexCoords[MAX_MESH_TEXTURE_COORDS]; 307 | bool bValidColors; 308 | }; 309 | 310 | 311 | // Helper function for ConvertMeshesToStaticMesh 312 | static void SkinnedMeshToRawMeshes(USkinnedMeshComponent* InSkinnedMeshComponent, int32 InOverallMaxLODs, const FMatrix& InComponentToWorld, const FString& InPackageName, TArray& OutRawMeshTrackers, TArray& OutRawMeshes, TArray& OutMaterials) 313 | { 314 | const int32 BaseMaterialIndex = OutMaterials.Num(); 315 | 316 | // Export all LODs to raw meshes 317 | const int32 NumLODs = InSkinnedMeshComponent->GetNumLODs(); 318 | 319 | for (int32 OverallLODIndex = 0; OverallLODIndex < InOverallMaxLODs; OverallLODIndex++) 320 | { 321 | int32 LODIndexRead = FMath::Min(OverallLODIndex, NumLODs - 1); 322 | 323 | FRawMesh& RawMesh = OutRawMeshes[OverallLODIndex]; 324 | FRawMeshTracker& RawMeshTracker = OutRawMeshTrackers[OverallLODIndex]; 325 | const int32 BaseVertexIndex = RawMesh.VertexPositions.Num(); 326 | 327 | FSkeletalMeshLODInfo& SrcLODInfo = *(InSkinnedMeshComponent->SkeletalMesh->GetLODInfo(LODIndexRead)); 328 | 329 | // Get the CPU skinned verts for this LOD 330 | TArray FinalVertices; 331 | InSkinnedMeshComponent->GetCPUSkinnedVertices(FinalVertices, LODIndexRead); 332 | 333 | FSkeletalMeshRenderData& SkeletalMeshRenderData = InSkinnedMeshComponent->MeshObject->GetSkeletalMeshRenderData(); 334 | FSkeletalMeshLODRenderData& LODData = SkeletalMeshRenderData.LODRenderData[LODIndexRead]; 335 | 336 | // Copy skinned vertex positions 337 | for (int32 VertIndex = 0; VertIndex < FinalVertices.Num(); ++VertIndex) 338 | { 339 | RawMesh.VertexPositions.Add(InComponentToWorld.TransformPosition(FinalVertices[VertIndex].Position)); 340 | } 341 | 342 | const uint32 NumTexCoords = FMath::Min(LODData.StaticVertexBuffers.StaticMeshVertexBuffer.GetNumTexCoords(), (uint32)MAX_MESH_TEXTURE_COORDS); 343 | const int32 NumSections = LODData.RenderSections.Num(); 344 | FRawStaticIndexBuffer16or32Interface& IndexBuffer = *LODData.MultiSizeIndexContainer.GetIndexBuffer(); 345 | 346 | for (int32 SectionIndex = 0; SectionIndex < NumSections; SectionIndex++) 347 | { 348 | const FSkelMeshRenderSection& SkelMeshSection = LODData.RenderSections[SectionIndex]; 349 | if (InSkinnedMeshComponent->IsMaterialSectionShown(SkelMeshSection.MaterialIndex, LODIndexRead)) 350 | { 351 | // Build 'wedge' info 352 | const int32 NumWedges = SkelMeshSection.NumTriangles * 3; 353 | for (int32 WedgeIndex = 0; WedgeIndex < NumWedges; WedgeIndex++) 354 | { 355 | const int32 VertexIndexForWedge = IndexBuffer.Get(SkelMeshSection.BaseIndex + WedgeIndex); 356 | 357 | RawMesh.WedgeIndices.Add(BaseVertexIndex + VertexIndexForWedge); 358 | 359 | const FFinalSkinVertex& SkinnedVertex = FinalVertices[VertexIndexForWedge]; 360 | const FVector TangentX = InComponentToWorld.TransformVector(SkinnedVertex.TangentX.ToFVector()); 361 | const FVector TangentZ = InComponentToWorld.TransformVector(SkinnedVertex.TangentZ.ToFVector()); 362 | const FVector4 UnpackedTangentZ = SkinnedVertex.TangentZ.ToFVector4(); 363 | const FVector TangentY = (TangentZ ^ TangentX).GetSafeNormal() * UnpackedTangentZ.W; 364 | 365 | RawMesh.WedgeTangentX.Add(TangentX); 366 | RawMesh.WedgeTangentY.Add(TangentY); 367 | RawMesh.WedgeTangentZ.Add(TangentZ); 368 | 369 | for (uint32 TexCoordIndex = 0; TexCoordIndex < MAX_MESH_TEXTURE_COORDS; TexCoordIndex++) 370 | { 371 | if (TexCoordIndex >= NumTexCoords) 372 | { 373 | RawMesh.WedgeTexCoords[TexCoordIndex].AddDefaulted(); 374 | } 375 | else 376 | { 377 | RawMesh.WedgeTexCoords[TexCoordIndex].Add(LODData.StaticVertexBuffers.StaticMeshVertexBuffer.GetVertexUV(VertexIndexForWedge, TexCoordIndex)); 378 | RawMeshTracker.bValidTexCoords[TexCoordIndex] = true; 379 | } 380 | } 381 | 382 | if (LODData.StaticVertexBuffers.ColorVertexBuffer.IsInitialized()) 383 | { 384 | RawMesh.WedgeColors.Add(LODData.StaticVertexBuffers.ColorVertexBuffer.VertexColor(VertexIndexForWedge)); 385 | RawMeshTracker.bValidColors = true; 386 | } 387 | else 388 | { 389 | RawMesh.WedgeColors.Add(FColor::White); 390 | } 391 | } 392 | 393 | int32 MaterialIndex = SkelMeshSection.MaterialIndex; 394 | // use the remapping of material indices if there is a valid value 395 | if (SrcLODInfo.LODMaterialMap.IsValidIndex(SectionIndex) && SrcLODInfo.LODMaterialMap[SectionIndex] != INDEX_NONE) 396 | { 397 | MaterialIndex = FMath::Clamp(SrcLODInfo.LODMaterialMap[SectionIndex], 0, InSkinnedMeshComponent->SkeletalMesh->Materials.Num()); 398 | } 399 | 400 | // copy face info 401 | for (uint32 TriIndex = 0; TriIndex < SkelMeshSection.NumTriangles; TriIndex++) 402 | { 403 | RawMesh.FaceMaterialIndices.Add(BaseMaterialIndex + MaterialIndex); 404 | RawMesh.FaceSmoothingMasks.Add(0); // Assume this is ignored as bRecomputeNormals is false 405 | } 406 | } 407 | } 408 | } 409 | 410 | ProcessMaterials(InSkinnedMeshComponent, InPackageName, OutMaterials); 411 | } 412 | 413 | 414 | UStaticMesh* FVertexAnimUtils::ConvertMeshesToStaticMesh(const TArray& InMeshComponents, const FTransform& InRootTransform, const FString& InPackageName) 415 | { 416 | UStaticMesh* StaticMesh = nullptr; 417 | 418 | // Build a package name to use 419 | FString MeshName; 420 | FString PackageName; 421 | if (InPackageName.IsEmpty()) 422 | { 423 | FString NewNameSuggestion = FString(TEXT("StaticMesh")); 424 | FString PackageNameSuggestion = FString(TEXT("/Game/Meshes/")) + NewNameSuggestion; 425 | FString Name; 426 | FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked("AssetTools"); 427 | AssetToolsModule.Get().CreateUniqueAssetName(PackageNameSuggestion, TEXT(""), PackageNameSuggestion, Name); 428 | 429 | TSharedPtr PickAssetPathWidget = 430 | SNew(SDlgPickAssetPath) 431 | .Title(LOCTEXT("ConvertToStaticMeshPickName", "Choose New StaticMesh Location")) 432 | .DefaultAssetPath(FText::FromString(PackageNameSuggestion)); 433 | 434 | if (PickAssetPathWidget->ShowModal() == EAppReturnType::Ok) 435 | { 436 | // Get the full name of where we want to create the mesh asset. 437 | PackageName = PickAssetPathWidget->GetFullAssetPath().ToString(); 438 | MeshName = FPackageName::GetLongPackageAssetName(PackageName); 439 | 440 | // Check if the user inputed a valid asset name, if they did not, give it the generated default name 441 | if (MeshName.IsEmpty()) 442 | { 443 | // Use the defaults that were already generated. 444 | PackageName = PackageNameSuggestion; 445 | MeshName = *Name; 446 | } 447 | } 448 | } 449 | else 450 | { 451 | PackageName = InPackageName; 452 | MeshName = *FPackageName::GetLongPackageAssetName(PackageName); 453 | } 454 | 455 | if (!PackageName.IsEmpty() && !MeshName.IsEmpty()) 456 | { 457 | TArray RawMeshes; 458 | TArray Materials; 459 | 460 | TArray RawMeshTrackers; 461 | 462 | FMatrix WorldToRoot = InRootTransform.ToMatrixWithScale().Inverse(); 463 | 464 | // first do a pass to determine the max LOD level we will be combining meshes into 465 | int32 OverallMaxLODs = 0; 466 | for (UMeshComponent* MeshComponent : InMeshComponents) 467 | { 468 | USkinnedMeshComponent* SkinnedMeshComponent = Cast(MeshComponent); 469 | UStaticMeshComponent* StaticMeshComponent = Cast(MeshComponent); 470 | 471 | if (IsValidSkinnedMeshComponent(SkinnedMeshComponent)) 472 | { 473 | OverallMaxLODs = FMath::Max(SkinnedMeshComponent->MeshObject->GetSkeletalMeshRenderData().LODRenderData.Num(), OverallMaxLODs); 474 | } 475 | else if (false)//(IsValidStaticMeshComponent(StaticMeshComponent)) 476 | { 477 | OverallMaxLODs = FMath::Max(StaticMeshComponent->GetStaticMesh()->RenderData->LODResources.Num(), OverallMaxLODs); 478 | } 479 | } 480 | 481 | // Resize raw meshes to accommodate the number of LODs we will need 482 | RawMeshes.SetNum(OverallMaxLODs); 483 | RawMeshTrackers.SetNum(OverallMaxLODs); 484 | 485 | // Export all visible components 486 | for (UMeshComponent* MeshComponent : InMeshComponents) 487 | { 488 | FMatrix ComponentToWorld = MeshComponent->GetComponentTransform().ToMatrixWithScale() * WorldToRoot; 489 | 490 | USkinnedMeshComponent* SkinnedMeshComponent = Cast(MeshComponent); 491 | UStaticMeshComponent* StaticMeshComponent = Cast(MeshComponent); 492 | 493 | if (IsValidSkinnedMeshComponent(SkinnedMeshComponent)) 494 | { 495 | SkinnedMeshToRawMeshes(SkinnedMeshComponent, OverallMaxLODs, ComponentToWorld, PackageName, RawMeshTrackers, RawMeshes, Materials); 496 | } 497 | else if (false)//(IsValidStaticMeshComponent(StaticMeshComponent)) 498 | { 499 | //StaticMeshToRawMeshes(StaticMeshComponent, OverallMaxLODs, ComponentToWorld, PackageName, RawMeshTrackers, RawMeshes, Materials); 500 | } 501 | } 502 | 503 | uint32 MaxInUseTextureCoordinate = 0; 504 | 505 | // scrub invalid vert color & tex coord data 506 | check(RawMeshes.Num() == RawMeshTrackers.Num()); 507 | for (int32 RawMeshIndex = 0; RawMeshIndex < RawMeshes.Num(); RawMeshIndex++) 508 | { 509 | if (!RawMeshTrackers[RawMeshIndex].bValidColors) 510 | { 511 | RawMeshes[RawMeshIndex].WedgeColors.Empty(); 512 | } 513 | 514 | for (uint32 TexCoordIndex = 0; TexCoordIndex < MAX_MESH_TEXTURE_COORDS; TexCoordIndex++) 515 | { 516 | if (!RawMeshTrackers[RawMeshIndex].bValidTexCoords[TexCoordIndex]) 517 | { 518 | RawMeshes[RawMeshIndex].WedgeTexCoords[TexCoordIndex].Empty(); 519 | } 520 | else 521 | { 522 | // Store first texture coordinate index not in use 523 | MaxInUseTextureCoordinate = FMath::Max(MaxInUseTextureCoordinate, TexCoordIndex); 524 | } 525 | } 526 | } 527 | 528 | // Check if we got some valid data. 529 | bool bValidData = false; 530 | for (FRawMesh& RawMesh : RawMeshes) 531 | { 532 | if (RawMesh.IsValidOrFixable()) 533 | { 534 | bValidData = true; 535 | break; 536 | } 537 | } 538 | 539 | if (bValidData) 540 | { 541 | // Then find/create it. 542 | UPackage* Package = CreatePackage(NULL, *PackageName); 543 | check(Package); 544 | 545 | // Create StaticMesh object 546 | StaticMesh = NewObject(Package, *MeshName, RF_Public | RF_Standalone); 547 | StaticMesh->InitResources(); 548 | 549 | StaticMesh->LightingGuid = FGuid::NewGuid(); 550 | 551 | // Determine which texture coordinate map should be used for storing/generating the lightmap UVs 552 | const uint32 LightMapIndex = FMath::Min(MaxInUseTextureCoordinate + 1, (uint32)MAX_MESH_TEXTURE_COORDS - 1); 553 | 554 | // Add source to new StaticMesh 555 | for (FRawMesh& RawMesh : RawMeshes) 556 | { 557 | if (RawMesh.IsValidOrFixable()) 558 | { 559 | FStaticMeshSourceModel& SrcModel = StaticMesh->AddSourceModel(); 560 | SrcModel.BuildSettings.bRecomputeNormals = false; 561 | SrcModel.BuildSettings.bRecomputeTangents = false; 562 | SrcModel.BuildSettings.bRemoveDegenerates = true; 563 | SrcModel.BuildSettings.bUseHighPrecisionTangentBasis = false; 564 | SrcModel.BuildSettings.bUseFullPrecisionUVs = false; 565 | SrcModel.BuildSettings.bGenerateLightmapUVs = true; 566 | SrcModel.BuildSettings.SrcLightmapIndex = 0; 567 | SrcModel.BuildSettings.DstLightmapIndex = LightMapIndex; 568 | SrcModel.SaveRawMesh(RawMesh); 569 | } 570 | } 571 | 572 | // Copy materials to new mesh 573 | for (UMaterialInterface* Material : Materials) 574 | { 575 | StaticMesh->StaticMaterials.Add(FStaticMaterial(Material)); 576 | } 577 | 578 | //Set the Imported version before calling the build 579 | StaticMesh->ImportVersion = EImportStaticMeshVersion::LastVersion; 580 | 581 | // Set light map coordinate index to match DstLightmapIndex 582 | StaticMesh->LightMapCoordinateIndex = LightMapIndex; 583 | 584 | // setup section info map 585 | for (int32 RawMeshLODIndex = 0; RawMeshLODIndex < RawMeshes.Num(); RawMeshLODIndex++) 586 | { 587 | const FRawMesh& RawMesh = RawMeshes[RawMeshLODIndex]; 588 | TArray UniqueMaterialIndices; 589 | for (int32 MaterialIndex : RawMesh.FaceMaterialIndices) 590 | { 591 | UniqueMaterialIndices.AddUnique(MaterialIndex); 592 | } 593 | 594 | int32 SectionIndex = 0; 595 | for (int32 UniqueMaterialIndex : UniqueMaterialIndices) 596 | { 597 | StaticMesh->GetSectionInfoMap().Set(RawMeshLODIndex, SectionIndex, FMeshSectionInfo(UniqueMaterialIndex)); 598 | SectionIndex++; 599 | } 600 | } 601 | StaticMesh->GetOriginalSectionInfoMap().CopyFrom(StaticMesh->GetSectionInfoMap()); 602 | 603 | // Build mesh from source 604 | StaticMesh->Build(false); 605 | StaticMesh->PostEditChange(); 606 | 607 | StaticMesh->MarkPackageDirty(); 608 | 609 | // Notify asset registry of new asset 610 | FAssetRegistryModule::AssetCreated(StaticMesh); 611 | 612 | // Display notification so users can quickly access the mesh 613 | if (GIsEditor) 614 | { 615 | FNotificationInfo Info(FText::Format(LOCTEXT("SkeletalMeshConverted", "Successfully Converted Mesh"), FText::FromString(StaticMesh->GetName()))); 616 | Info.ExpireDuration = 8.0f; 617 | Info.bUseLargeFont = false; 618 | Info.Hyperlink = FSimpleDelegate::CreateLambda([=]() { GEditor->GetEditorSubsystem()->OpenEditorForAssets(TArray({ StaticMesh })); }); 619 | Info.HyperlinkText = FText::Format(LOCTEXT("OpenNewAnimationHyperlink", "Open {0}"), FText::FromString(StaticMesh->GetName())); 620 | TSharedPtr Notification = FSlateNotificationManager::Get().AddNotification(Info); 621 | if (Notification.IsValid()) 622 | { 623 | Notification->SetCompletionState(SNotificationItem::CS_Success); 624 | } 625 | } 626 | } 627 | } 628 | 629 | return StaticMesh; 630 | } 631 | 632 | 633 | 634 | void FVertexAnimUtils::VATUVsToStaticMeshLODs(UStaticMesh* StaticMesh, const int32 UVChannel, const TArray>& UVs) 635 | { 636 | for (int32 LOD = 0; LOD < StaticMesh->GetNumLODs(); LOD++) 637 | { 638 | const uint32 PaintingMeshLODIndex = LOD; 639 | 640 | if (StaticMesh->IsSourceModelValid(PaintingMeshLODIndex)) 641 | { 642 | if (StaticMesh->GetSourceModel(PaintingMeshLODIndex).IsRawMeshEmpty() == false) 643 | { 644 | const uint32 NumUVChannels = StaticMesh->GetNumUVChannels(PaintingMeshLODIndex); 645 | // Extract the raw mesh. 646 | FRawMesh Mesh; 647 | StaticMesh->GetSourceModel(PaintingMeshLODIndex).LoadRawMesh(Mesh); 648 | 649 | // Build a mapping of vertex positions to vertex colors. 650 | for (int32 WedgeIndex = 0; WedgeIndex < Mesh.WedgeIndices.Num(); ++WedgeIndex) 651 | { 652 | int32 VertID = Mesh.WedgeIndices[WedgeIndex]; 653 | FVector Position = Mesh.VertexPositions[VertID]; 654 | 655 | for (uint32 TexCoordIndex = 0; TexCoordIndex < MAX_MESH_TEXTURE_COORDS; TexCoordIndex++) 656 | { 657 | if (TexCoordIndex <= NumUVChannels)//(!RawMeshTrackers[RawMeshIndex].bValidTexCoords[TexCoordIndex]) 658 | { 659 | if ((TexCoordIndex == UVChannel)) 660 | { 661 | // Mesh.WedgeTexCoords[TexCoordIndex].Empty(); 662 | if (Mesh.WedgeTexCoords[TexCoordIndex].Num() != Mesh.WedgeIndices.Num()) 663 | Mesh.WedgeTexCoords[TexCoordIndex].SetNum(Mesh.WedgeIndices.Num()); 664 | 665 | Mesh.WedgeTexCoords[TexCoordIndex][WedgeIndex] = UVs[PaintingMeshLODIndex][VertID]; 666 | } 667 | else if(TexCoordIndex >= NumUVChannels) 668 | { 669 | Mesh.WedgeTexCoords[TexCoordIndex].Empty(); 670 | } 671 | } 672 | else 673 | { 674 | Mesh.WedgeTexCoords[TexCoordIndex].Empty(); 675 | } 676 | } 677 | } 678 | 679 | // Determine which texture coordinate map should be used for storing/generating the lightmap UVs 680 | const uint32 LightMapIndex = FMath::Min(UVChannel == NumUVChannels ? NumUVChannels + 1 : NumUVChannels, (uint32)MAX_MESH_TEXTURE_COORDS - 1); 681 | StaticMesh->GetSourceModel(PaintingMeshLODIndex).BuildSettings.DstLightmapIndex = LightMapIndex; 682 | 683 | // Save the new raw mesh. 684 | StaticMesh->GetSourceModel(PaintingMeshLODIndex).SaveRawMesh(Mesh); 685 | 686 | 687 | StaticMesh->ImportVersion = EImportStaticMeshVersion::LastVersion; 688 | // Set light map coordinate index to match DstLightmapIndex 689 | StaticMesh->LightMapCoordinateIndex = LightMapIndex; 690 | 691 | 692 | } 693 | } 694 | } 695 | 696 | // Build mesh from source 697 | StaticMesh->Build(false); 698 | StaticMesh->PostEditChange(); 699 | StaticMesh->MarkPackageDirty(); 700 | } 701 | 702 | void FVertexAnimUtils::VATColorsToStaticMeshLODs(UStaticMesh* StaticMesh, const TArray>& Colors) 703 | { 704 | for (int32 LOD = 0; LOD < StaticMesh->GetNumLODs(); LOD++) 705 | { 706 | const uint32 PaintingMeshLODIndex = LOD; 707 | 708 | if (StaticMesh->IsSourceModelValid(PaintingMeshLODIndex)) 709 | { 710 | if (StaticMesh->GetSourceModel(PaintingMeshLODIndex).IsRawMeshEmpty() == false) 711 | { 712 | const uint32 NumUVChannels = StaticMesh->GetNumUVChannels(PaintingMeshLODIndex); 713 | // Extract the raw mesh. 714 | FRawMesh Mesh; 715 | StaticMesh->GetSourceModel(PaintingMeshLODIndex).LoadRawMesh(Mesh); 716 | 717 | // Reserve space for the new vertex colors. 718 | if (Mesh.WedgeColors.Num() == 0 || Mesh.WedgeColors.Num() != Mesh.WedgeIndices.Num()) 719 | { 720 | Mesh.WedgeColors.Empty(Mesh.WedgeIndices.Num()); 721 | Mesh.WedgeColors.AddUninitialized(Mesh.WedgeIndices.Num()); 722 | } 723 | 724 | // Build a mapping of vertex positions to vertex colors. 725 | for (int32 WedgeIndex = 0; WedgeIndex < Mesh.WedgeIndices.Num(); ++WedgeIndex) 726 | { 727 | int32 VertID = Mesh.WedgeIndices[WedgeIndex]; 728 | FVector Position = Mesh.VertexPositions[VertID]; 729 | Mesh.WedgeColors[WedgeIndex] = Colors[PaintingMeshLODIndex][VertID]; 730 | } 731 | 732 | // Save the new raw mesh. 733 | StaticMesh->GetSourceModel(PaintingMeshLODIndex).SaveRawMesh(Mesh); 734 | StaticMesh->ImportVersion = EImportStaticMeshVersion::LastVersion; 735 | } 736 | } 737 | } 738 | 739 | // Build mesh from source 740 | StaticMesh->Build(false); 741 | StaticMesh->PostEditChange(); 742 | StaticMesh->MarkPackageDirty(); 743 | } 744 | 745 | 746 | 747 | 748 | 749 | void SPickAssetDialog::Construct(const FArguments& InArgs) 750 | { 751 | 752 | FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked("ContentBrowser"); 753 | 754 | TSharedPtr AssetPickerBox1 = SNew(SVerticalBox) 755 | + SVerticalBox::Slot() 756 | .FillHeight(0.1) 757 | .FillHeight(0.1) 758 | [ 759 | SNew(STextBlock) 760 | .Text(LOCTEXT("Profile", "Profile")) 761 | ]; 762 | 763 | /* 764 | TSharedPtr AssetPickerBox2 = SNew(SVerticalBox) 765 | +SVerticalBox::Slot() 766 | .FillHeight(0.1) 767 | .FillHeight(0.1) 768 | [ 769 | SNew(STextBlock) 770 | .Text(LOCTEXT("Offsets", "Offsets Render Target")) 771 | ]; 772 | 773 | TSharedPtr AssetPickerBox3 = SNew(SVerticalBox) 774 | + SVerticalBox::Slot() 775 | .FillHeight(0.1) 776 | .FillHeight(0.1) 777 | [ 778 | SNew(STextBlock) 779 | .Text(LOCTEXT("Normals", "Normals Render Target")) 780 | ]; 781 | 782 | TSharedPtr AssetPickerBox4 = SNew(SVerticalBox) 783 | + SVerticalBox::Slot() 784 | .FillHeight(0.1) 785 | .FillHeight(0.1) 786 | [ 787 | SNew(STextBlock) 788 | .Text(LOCTEXT("StaticMesh", "Static Mesh")) 789 | ]; 790 | */ 791 | 792 | { 793 | // Vertex Anim Profile 794 | { 795 | FAssetPickerConfig AssetPickerConfig; 796 | AssetPickerConfig.Filter.ClassNames.Add(UVertexAnimProfile::StaticClass()->GetFName()); 797 | AssetPickerConfig.SelectionMode = ESelectionMode::Single; 798 | 799 | AssetPickerConfig.GetCurrentSelectionDelegates.Add(&GetCurrentSelectionDelegate_Profile); 800 | 801 | AssetPickerConfig.OnShouldFilterAsset = FOnShouldFilterAsset::CreateSP(this, &SPickAssetDialog::Filter); 802 | AssetPickerConfig.bAllowNullSelection = true; 803 | AssetPickerConfig.InitialAssetViewType = EAssetViewType::List; 804 | AssetPickerConfig.ThumbnailScale = 1.f; 805 | 806 | AssetPickerBox1->AddSlot() 807 | .FillHeight(1) 808 | .Padding(3) 809 | [ 810 | ContentBrowserModule.Get().CreateAssetPicker(AssetPickerConfig) 811 | ]; 812 | } 813 | } 814 | 815 | // 816 | AssetPath = FText::FromString(FPackageName::GetLongPackagePath(InArgs._DefaultAssetPath.ToString())); 817 | AssetName = FText::FromString(FPackageName::GetLongPackageAssetName(InArgs._DefaultAssetPath.ToString())); 818 | 819 | FPathPickerConfig PathPickerConfig; 820 | PathPickerConfig.DefaultPath = AssetPath.ToString(); 821 | PathPickerConfig.OnPathSelected = FOnPathSelected::CreateSP(this, &SPickAssetDialog::OnPathChange); 822 | PathPickerConfig.bAddDefaultPath = true; 823 | // 824 | 825 | /* 826 | SWindow::Construct(SWindow::FArguments() 827 | .Title(InArgs._Title) 828 | .SupportsMinimize(false) 829 | .SupportsMaximize(false) 830 | .ClientSize(FVector2D(1080, 720)) 831 | [ 832 | SNew(SVerticalBox) 833 | 834 | + SVerticalBox::Slot() 835 | .Padding(2, 2, 2, 4) 836 | .HAlign(HAlign_Fill) 837 | [ 838 | SNew(SBorder) 839 | .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) 840 | [ 841 | SNew(SVerticalBox) 842 | 843 | + SVerticalBox::Slot() 844 | .FillHeight(1) 845 | .Padding(3) 846 | .HAlign(HAlign_Fill) 847 | [ 848 | SNew(SVerticalBox) 849 | 850 | + SVerticalBox::Slot() 851 | .FillHeight(2) 852 | .Padding(3) 853 | [ 854 | SNew(SHorizontalBox) 855 | 856 | + SHorizontalBox::Slot() 857 | .FillWidth(1) 858 | .HAlign(HAlign_Fill) 859 | .VAlign(VAlign_Fill) 860 | [ 861 | AssetPickerBox1.ToSharedRef() 862 | ] 863 | ] 864 | 865 | + SVerticalBox::Slot() 866 | .AutoHeight() 867 | .Padding(3) 868 | [ 869 | SNew(SHorizontalBox) 870 | + SHorizontalBox::Slot() 871 | .AutoWidth() 872 | .Padding(0, 0, 10, 0) 873 | .VAlign(VAlign_Center) 874 | [ 875 | SNew(STextBlock) 876 | .Text(LOCTEXT("CreateStaticMesh", "Create Static Mesh")) 877 | ] 878 | 879 | + SHorizontalBox::Slot() 880 | .AutoWidth() 881 | .Padding(0, 0, 10, 0) 882 | .VAlign(VAlign_Center) 883 | [ 884 | SNew(SCheckBox) 885 | .ToolTipText(LOCTEXT("CreateStaticMesh_Tooltip", "Create Static Mesh with special UV channel for vertex animation")) 886 | .IsChecked(ECheckBoxState::Checked) 887 | .OnCheckStateChanged(this, &SPickAssetDialog::OnCheckedCreateStaticMesh) 888 | 889 | ] 890 | 891 | ] 892 | 893 | 894 | + SVerticalBox::Slot() 895 | .FillHeight(1) 896 | .Padding(3) 897 | .HAlign(HAlign_Fill) 898 | [ 899 | ContentBrowserModule.Get().CreatePathPicker(PathPickerConfig) 900 | ] 901 | 902 | ] 903 | 904 | 905 | + SVerticalBox::Slot() 906 | .AutoHeight() 907 | .Padding(3) 908 | [ 909 | SNew(SHorizontalBox) 910 | + SHorizontalBox::Slot() 911 | .AutoWidth() 912 | .Padding(0, 0, 10, 0) 913 | .VAlign(VAlign_Center) 914 | [ 915 | SNew(STextBlock) 916 | .Text(LOCTEXT("Name", "Name")) 917 | ] 918 | 919 | + SHorizontalBox::Slot() 920 | [ 921 | SNew(SEditableTextBox) 922 | .Text(AssetName) 923 | .OnTextCommitted(this, &SPickAssetDialog::OnNameChange) 924 | .MinDesiredWidth(250) 925 | ] 926 | ] 927 | 928 | ] 929 | ] 930 | 931 | + SVerticalBox::Slot() 932 | .AutoHeight() 933 | .HAlign(HAlign_Right) 934 | .VAlign(VAlign_Bottom) 935 | [ 936 | SNew(SUniformGridPanel) 937 | .SlotPadding(FEditorStyle::GetMargin("StandardDialog.SlotPadding")) 938 | .MinDesiredSlotWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth")) 939 | .MinDesiredSlotHeight(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotHeight")) 940 | + SUniformGridPanel::Slot(0, 0) 941 | [ 942 | SNew(SButton) 943 | .Text(LOCTEXT("OK", "OK")) 944 | .HAlign(HAlign_Center) 945 | .ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding")) 946 | .OnClicked(this, &SPickAssetDialog::OnButtonClick, EAppReturnType::Ok) 947 | ] 948 | + SUniformGridPanel::Slot(1, 0) 949 | [ 950 | SNew(SButton) 951 | .Text(LOCTEXT("Cancel", "Cancel")) 952 | .HAlign(HAlign_Center) 953 | .ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding")) 954 | .OnClicked(this, &SPickAssetDialog::OnButtonClick, EAppReturnType::Cancel) 955 | ] 956 | ] 957 | ] 958 | ); 959 | */ 960 | 961 | 962 | SWindow::Construct(SWindow::FArguments() 963 | .Title(InArgs._Title) 964 | .SupportsMinimize(false) 965 | .SupportsMaximize(false) 966 | .ClientSize(FVector2D(1080, 720)) 967 | [ 968 | SNew(SVerticalBox) 969 | + SVerticalBox::Slot() 970 | .Padding(2, 2, 2, 4) 971 | .HAlign(HAlign_Fill) 972 | [ 973 | SNew(SBorder) 974 | .BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder")) 975 | [ 976 | SNew(SVerticalBox) 977 | + SVerticalBox::Slot() 978 | .FillHeight(1) 979 | .Padding(3) 980 | .HAlign(HAlign_Fill) 981 | [ 982 | SNew(SVerticalBox) 983 | + SVerticalBox::Slot() 984 | .FillHeight(2) 985 | .Padding(3) 986 | [ 987 | SNew(SHorizontalBox) 988 | + SHorizontalBox::Slot() 989 | .FillWidth(1) 990 | .HAlign(HAlign_Fill) 991 | .VAlign(VAlign_Fill) 992 | [ 993 | AssetPickerBox1.ToSharedRef() 994 | ] 995 | ] 996 | ] 997 | ] 998 | ] 999 | + SVerticalBox::Slot() 1000 | .AutoHeight() 1001 | .Padding(3) 1002 | [ 1003 | SNew(SHorizontalBox) 1004 | + SHorizontalBox::Slot() 1005 | .AutoWidth() 1006 | .Padding(0, 0, 10, 0) 1007 | .VAlign(VAlign_Center) 1008 | [ 1009 | SNew(STextBlock) 1010 | .Text(LOCTEXT("OnlyCreateStaticMesh", "Only Create Static Mesh")) 1011 | ] 1012 | 1013 | + SHorizontalBox::Slot() 1014 | .AutoWidth() 1015 | .Padding(0, 0, 10, 0) 1016 | .VAlign(VAlign_Center) 1017 | [ 1018 | SNew(SCheckBox) 1019 | .ToolTipText(LOCTEXT("OnlyCreateStaticMesh_Tooltip", "Only create static mesh without baking any animation to textures")) 1020 | .IsChecked(ECheckBoxState::Unchecked) 1021 | .OnCheckStateChanged(this, &SPickAssetDialog::OnCheckedOnlyCreateStaticMesh) 1022 | 1023 | ] 1024 | 1025 | ] 1026 | + SVerticalBox::Slot() 1027 | .AutoHeight() 1028 | .HAlign(HAlign_Right) 1029 | .VAlign(VAlign_Bottom) 1030 | [ 1031 | SNew(SUniformGridPanel) 1032 | .SlotPadding(FEditorStyle::GetMargin("StandardDialog.SlotPadding")) 1033 | .MinDesiredSlotWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth")) 1034 | .MinDesiredSlotHeight(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotHeight")) 1035 | + SUniformGridPanel::Slot(0, 0) 1036 | [ 1037 | SNew(SButton) 1038 | .Text(LOCTEXT("OK", "OK")) 1039 | .HAlign(HAlign_Center) 1040 | .ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding")) 1041 | .OnClicked(this, &SPickAssetDialog::OnButtonClick, EAppReturnType::Ok) 1042 | ] 1043 | + SUniformGridPanel::Slot(1, 0) 1044 | [ 1045 | SNew(SButton) 1046 | .Text(LOCTEXT("Cancel", "Cancel")) 1047 | .HAlign(HAlign_Center) 1048 | .ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding")) 1049 | .OnClicked(this, &SPickAssetDialog::OnButtonClick, EAppReturnType::Cancel) 1050 | ] 1051 | ] 1052 | ]); 1053 | } 1054 | 1055 | void SPickAssetDialog::OnNameChange(const FText& NewName, ETextCommit::Type CommitInfo) 1056 | { 1057 | AssetName = NewName; 1058 | } 1059 | 1060 | void SPickAssetDialog::OnPathChange(const FString& NewPath) 1061 | { 1062 | AssetPath = FText::FromString(NewPath); 1063 | } 1064 | 1065 | FReply SPickAssetDialog::OnButtonClick(EAppReturnType::Type ButtonID) 1066 | { 1067 | if (ButtonID == EAppReturnType::Ok) 1068 | { 1069 | const int32 ValidateResult = ValidateProfile(); 1070 | 1071 | switch (ValidateResult) 1072 | { 1073 | case 0: // Valid Profile 1074 | break; 1075 | case 1: // NULL Profile 1076 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("NULLProfile", "No Profile Selected")); 1077 | return FReply::Unhandled(); 1078 | break; 1079 | case 2: // Invalid Offsets or Normals Texture 1080 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("NULLOffsetsNormalsTexture", "Selected Profile has invalid Offsets or Normals Texture")); 1081 | return FReply::Unhandled(); 1082 | break; 1083 | case 3: // No Width / Height correspondence between Profile and Offsets Texture 1084 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("NoWidthHeightCorrespondenceOffsets", "Selected Profile has no Width / Height correspondence with Offsets texture")); 1085 | return FReply::Unhandled(); 1086 | break; 1087 | case 4: // No Width / Height correspondence between Profile and Normals Texture 1088 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("Invalid Override Width Height", "Deactivated Auto Size, but invalid Override Size")); 1089 | return FReply::Unhandled(); 1090 | break; 1091 | case 5: // Profile has not Anims 1092 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("SelectedProfileHasNoAnims", "Selected Profile has no Anims")); 1093 | return FReply::Unhandled(); 1094 | break; 1095 | case 6: // Invalid Sequence Ref 1096 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("InvalidSequenceRefInProfile", "Selected Profile has anim with invalid Sequence Ref")); 1097 | return FReply::Unhandled(); 1098 | break; 1099 | case 7: // Anims have different Skeletons 1100 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("DifferentSkeletonsInProfileAnims", "Selected Profile has anims with different skeletons")); 1101 | return FReply::Unhandled(); 1102 | break; 1103 | case 8: // Anim has Num of Frames less than 1 1104 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("AnimsInProfileWith0NumFrames", "Selected Profile has anim with Num Frames less than 1")); 1105 | return FReply::Unhandled(); 1106 | break; 1107 | default: 1108 | break; 1109 | }; 1110 | 1111 | // If no valid profile selected it doesnt get here 1112 | 1113 | UVertexAnimProfile* SelectedProfile = GetSelectedProfile(); 1114 | 1115 | if (bOnlyCreateStaticMesh) 1116 | { 1117 | if (false)//(!ValidatePackage()) 1118 | { 1119 | FMessageDialog::Open(EAppMsgType::Ok, LOCTEXT("InvalidPackage", "Invalid Package for static mesh")); 1120 | return FReply::Unhandled(); 1121 | } 1122 | } 1123 | } 1124 | 1125 | //----------------------------------------------------------------------------------------------------- 1126 | 1127 | UserResponse = ButtonID; 1128 | 1129 | RequestDestroyWindow(); 1130 | 1131 | return FReply::Handled(); 1132 | } 1133 | 1134 | /** Ensures supplied package name information is valid */ 1135 | bool SPickAssetDialog::ValidatePackage() 1136 | { 1137 | FText Reason; 1138 | if (!FPackageName::IsValidLongPackageName(GetFullAssetPath().ToString(), false, &Reason) 1139 | || !FName(*AssetName.ToString()).IsValidObjectName(Reason)) 1140 | { 1141 | FMessageDialog::Open(EAppMsgType::Ok, Reason); 1142 | return false; 1143 | } 1144 | 1145 | if (FPackageName::DoesPackageExist(GetFullAssetPath().ToString()) || 1146 | FindObject(NULL, *(AssetPath.ToString() + "/" + AssetName.ToString() + "." + AssetName.ToString())) != NULL) 1147 | { 1148 | if (GetSelectedProfile() != NULL) 1149 | { 1150 | if (GetSelectedProfile()->StaticMesh == FindObject(NULL, *(AssetPath.ToString() + "/" + AssetName.ToString() + "." + AssetName.ToString()))) 1151 | { 1152 | return true; 1153 | } 1154 | } 1155 | 1156 | FMessageDialog::Open(EAppMsgType::Ok, FText::Format(LOCTEXT("AssetAlreadyExists", "Asset {0} already exists."), GetFullAssetPath())); 1157 | return false; 1158 | } 1159 | 1160 | return true; 1161 | } 1162 | 1163 | EAppReturnType::Type SPickAssetDialog::ShowModal() 1164 | { 1165 | GEditor->EditorAddModalWindow(SharedThis(this)); 1166 | return UserResponse; 1167 | } 1168 | 1169 | 1170 | const FText& SPickAssetDialog::GetAssetPath() 1171 | { 1172 | return AssetPath; 1173 | } 1174 | 1175 | const FText& SPickAssetDialog::GetAssetName() 1176 | { 1177 | return AssetName; 1178 | } 1179 | 1180 | FText SPickAssetDialog::GetFullAssetPath() 1181 | { 1182 | return FText::FromString(AssetPath.ToString() + "/" + AssetName.ToString()); 1183 | } 1184 | 1185 | void SPickAssetDialog::OnCheckedOnlyCreateStaticMesh(ECheckBoxState NewCheckedState) 1186 | { 1187 | if (NewCheckedState == ECheckBoxState::Checked) 1188 | { 1189 | bOnlyCreateStaticMesh = true; 1190 | } 1191 | else //if (NewCheckedState == ECheckBoxState::Unchecked) 1192 | { 1193 | bOnlyCreateStaticMesh = false; 1194 | } 1195 | } 1196 | 1197 | 1198 | 1199 | UVertexAnimProfile * SPickAssetDialog::GetSelectedProfile() const 1200 | { 1201 | TArray SelectionArray = GetCurrentSelectionDelegate_Profile.Execute(); 1202 | 1203 | if (SelectionArray.Num() > 0) 1204 | { 1205 | TArray StoredProfiles; 1206 | 1207 | for (int i = 0; i < SelectionArray.Num(); i++) 1208 | { 1209 | SelectionArray[i].GetPackage()->FullyLoad(); 1210 | if (SelectionArray[i].IsAssetLoaded()) 1211 | { 1212 | UVertexAnimProfile* NewSequence = Cast (SelectionArray[i].GetAsset()); 1213 | if (NewSequence) 1214 | { 1215 | StoredProfiles.Add(NewSequence); 1216 | } 1217 | } 1218 | } 1219 | 1220 | return StoredProfiles[0]; 1221 | } 1222 | 1223 | return NULL; 1224 | } 1225 | 1226 | 1227 | 1228 | bool SPickAssetDialog::Filter(const FAssetData & AssetData) 1229 | { 1230 | if (!AssetData.IsAssetLoaded()) 1231 | { 1232 | AssetData.GetPackage()->FullyLoad(); 1233 | } 1234 | 1235 | return false; 1236 | } 1237 | 1238 | int32 SPickAssetDialog::ValidateProfile() const 1239 | { 1240 | UVertexAnimProfile* Profile = GetSelectedProfile(); 1241 | if (Profile != NULL) 1242 | { 1243 | // Invalid Offsets or Normals Texture 1244 | if ((!Profile->AutoSize) && (Profile->OverrideSize_Vert.GetMax() < 8)) return 4; 1245 | // Profile has not Anims 1246 | if ((Profile->Anims_Vert.Num() == 0) && (Profile->Anims_Bone.Num() == 0)) return 5; 1247 | 1248 | 1249 | USkeleton* Skeleton = NULL; 1250 | if (Profile->Anims_Vert.Num()) 1251 | if (Profile->Anims_Vert[0].SequenceRef != NULL) Skeleton = Profile->Anims_Vert[0].SequenceRef->GetSkeleton(); 1252 | if (Profile->Anims_Bone.Num()) 1253 | if (Profile->Anims_Bone[0].SequenceRef != NULL) Skeleton = Profile->Anims_Bone[0].SequenceRef->GetSkeleton(); 1254 | 1255 | { 1256 | for (int32 i = 0; i < Profile->Anims_Vert.Num(); i++) 1257 | { 1258 | // Invalid Sequence Ref 1259 | if (Profile->Anims_Vert[i].SequenceRef == NULL) return 6; 1260 | 1261 | if (Profile->Anims_Vert[i].SequenceRef->GetSkeleton() != Skeleton) 1262 | { 1263 | // Anims have different Skeletons 1264 | return 7; 1265 | } 1266 | if ((Profile->Anims_Vert[i].NumFrames < 1)) 1267 | { 1268 | // Anim has Num Frames less than 1 1269 | return 8; 1270 | } 1271 | } 1272 | } 1273 | { 1274 | for (int32 i = 0; i < Profile->Anims_Bone.Num(); i++) 1275 | { 1276 | // Invalid Sequence Ref 1277 | if (Profile->Anims_Bone[i].SequenceRef == NULL) return 6; 1278 | 1279 | if (Profile->Anims_Bone[i].SequenceRef->GetSkeleton() != Skeleton) 1280 | { 1281 | // Anims have different Skeletons 1282 | return 7; 1283 | } 1284 | if ((Profile->Anims_Bone[i].NumFrames < 1)) 1285 | { 1286 | // Anim has Num Frames less than 1 1287 | return 8; 1288 | } 1289 | } 1290 | } 1291 | 1292 | //Profile->LODInSkeletalMesh; 1293 | return 0; 1294 | } 1295 | 1296 | // NULL PROFILE 1297 | return 1; 1298 | } 1299 | 1300 | 1301 | #undef LOCTEXT_NAMESPACE 1302 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/Public/VATEditorUtils.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GPUSkinPublicDefs.h" 7 | #include "UObject/ObjectMacros.h" 8 | #include "UObject/Object.h" 9 | #include "Engine/EngineTypes.h" 10 | #include "Components/SceneComponent.h" 11 | #include "Engine/TextureStreamingTypes.h" 12 | #include "Components/MeshComponent.h" 13 | #include "Containers/SortedMap.h" 14 | 15 | class UDebugSkelMeshComponent; 16 | class UTextureRenderTarget2D; 17 | class UAnimSequence; 18 | 19 | class FPrimitiveSceneProxy; 20 | class FColorVertexBuffer; 21 | class FSkinWeightVertexBuffer; 22 | class FSkeletalMeshRenderData; 23 | class FSkeletalMeshLODRenderData; 24 | struct FSkelMeshRenderSection; 25 | class FPositionVertexBuffer; 26 | 27 | class VERTEXANIMTOOLSETEDITOR_API FVATEditorUtils 28 | { 29 | public: 30 | static float PackBits(const uint32& bit); 31 | static int UnPackBits(const float bit); 32 | 33 | static void DoBakeProcess(UDebugSkelMeshComponent* PreviewComponent); 34 | 35 | static void SkelPivotPos(USkeletalMesh* Skel, TArray & VectorData); 36 | static void SkelOrigin(USkeletalMesh* Skel, TArray & VectorData); 37 | static void SkelExtents(USkeletalMesh* Skel, TArray & VectorData); 38 | 39 | static void VectorDataToTextureColor(const TArray& InVectorData, TArray & Data); 40 | // used for HDR Pivot Pos, Origin Pos, Origin Extents | ldr Pivot Directions (X, Y or Z) 41 | static void VectorDataToUV(const TArray& InVectorData, const int32 StartIdx, TArray& UVs); 42 | // used for ldr Pivot Directions (X, Y or Z) 43 | static void VectorDataToVertColor(const TArray& InVectorData, TArray& Colors); 44 | 45 | static void UVChannelsToSkeletalMesh(USkeletalMesh* Skel, const int32 LODIndex, const int32 UVChannelStart, TArray>& UVChannels); 46 | static void UVChannelToStaticMesh(UStaticMesh* Mesh, const int32 TargetUVChannel, TArray & UVs); 47 | 48 | static void IntoIslands(const TArray & IndexBuffer, const TArray & UVs, TArray & OutIslandIDs, int32& OutNumIslands); 49 | static void ClosestUVPivotAssign( 50 | const TArray & IndexBuffer, const TArray & UVs, const TArray & PivotUVPos, TArray & VertPivotIDs); 51 | }; 52 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/Public/VertexAnimToolsetEditor.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | #include "Misc/Guid.h" 9 | #include "IAnimationEditor.h" 10 | #include "IAnimationEditorModule.h" 11 | 12 | #include "ISkeletalMeshEditor.h" 13 | #include "ISkeletalMeshEditorModule.h" 14 | 15 | 16 | class UDebugSkelMeshComponent; 17 | class IPersonaPreviewScene; 18 | 19 | class FVertexAnimToolsetEditorModule : public IModuleInterface 20 | { 21 | public: 22 | 23 | /** IModuleInterface implementation */ 24 | virtual void StartupModule() override; 25 | virtual void ShutdownModule() override; 26 | 27 | protected: 28 | TSharedRef GetAnimationEditorToolbarExtender(const TSharedRef CommandList, TSharedRef InAnimationEditor); 29 | 30 | //void AddAnimationEditorToolbarExtender(); 31 | //void RemoveAnimationEditorToolbarExtender(); 32 | 33 | void HandleAddSkeletalMeshActionExtenderToToolbar(FToolBarBuilder& ParentToolbarBuilder, UDebugSkelMeshComponent* InMeshComponent); 34 | 35 | 36 | void AddSkeletalMeshEditorToolbarExtender(); 37 | 38 | void RemoveSkeletalMeshEditorToolbarExtender(); 39 | 40 | TSharedRef GetSkeletalMeshEditorToolbarExtender(const TSharedRef CommandList, TSharedRef InSkeletalMeshEditor); 41 | 42 | void DoBakeProcess(UDebugSkelMeshComponent* PreviewComponent) {}; 43 | 44 | FDelegateHandle ModuleLoadedDelegateHandle; 45 | //FDelegateHandle AnimationEditorExtenderHandle; 46 | FDelegateHandle SkeletalMeshEditorExtenderHandle; 47 | private: 48 | }; 49 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/Public/VertexAnimUtils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019-2021 Rexocrates. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | 7 | #include "Input/Reply.h" 8 | #include "Widgets/DeclarativeSyntaxSupport.h" 9 | #include "Widgets/SCompoundWidget.h" 10 | #include "Engine/Texture2D.h" 11 | #include "IDetailsView.h" 12 | 13 | 14 | #include "Layout/Visibility.h" 15 | #include "Widgets/SWidget.h" 16 | 17 | #include "IDetailCustomization.h" 18 | 19 | #include "Widgets/DeclarativeSyntaxSupport.h" 20 | #include "Input/Reply.h" 21 | #include "Widgets/SWindow.h" 22 | 23 | #include "ContentBrowserDelegates.h" 24 | 25 | class UTextureRenderTarget2D; 26 | 27 | class FSkeletalMeshLODRenderData; 28 | class FSkinWeightVertexBuffer; 29 | struct FActiveMorphTarget; 30 | class UVertexAnimProfile; 31 | 32 | // Abstract class holding helper functions to be used in the baking process 33 | class FVertexAnimUtils 34 | { 35 | public: 36 | 37 | static float EncodeFloat(const float& T, const float& Bound); 38 | static float DeEncodeFloat(const float& T, const float& Bound); 39 | 40 | static FVector DeEncodeVec(const FVector4& T, const float& Bound); 41 | 42 | static FVector4 BitEncodeVecId(const FVector T, const float Bound, const int32 Id); 43 | static FVector4 BitEncodeVecId_HD(const FVector T, const float Bound, const int32 Id); 44 | 45 | static int32 Grid2DIndex(const int32& X, const int32& Y, const int32& Width); 46 | static int32 Grid2D_X(const int32& Index, const int32& Height); 47 | static int32 Grid2D_Y(const int32& Index, const int32& Height); 48 | 49 | 50 | 51 | /** 52 | * Convert a set of mesh components in their current pose to a static mesh. 53 | * @param InMeshComponents The mesh components we want to convert 54 | * @param InRootTransform The transform of the root of the mesh we want to output 55 | * @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. 56 | * @return a new static mesh (specified by the user) 57 | */ 58 | static UStaticMesh* ConvertMeshesToStaticMesh(const TArray& InMeshComponents, const FTransform& InRootTransform = FTransform::Identity, const FString& InPackageName = FString()); 59 | 60 | static void VATUVsToStaticMeshLODs(UStaticMesh* StaticMesh, const int32 UVChannel, const TArray >& UVs); 61 | static void VATColorsToStaticMeshLODs(UStaticMesh* StaticMesh, const TArray >& Colors); 62 | 63 | }; 64 | 65 | 66 | #define LOCTEXT_NAMESPACE "PickAssetDialog" 67 | // dialog for using the bake anim tool in the editor 68 | class SPickAssetDialog : public SWindow 69 | { 70 | public: 71 | SLATE_BEGIN_ARGS(SPickAssetDialog) 72 | { 73 | } 74 | SLATE_ARGUMENT(FText, Title) 75 | SLATE_ARGUMENT(FText, DefaultAssetPath) 76 | SLATE_END_ARGS() 77 | 78 | VERTEXANIMTOOLSETEDITOR_API SPickAssetDialog() 79 | : UserResponse(EAppReturnType::Cancel) 80 | { 81 | } 82 | 83 | VERTEXANIMTOOLSETEDITOR_API void Construct(const FArguments& InArgs); 84 | 85 | /** Displays the dialog in a blocking fashion */ 86 | VERTEXANIMTOOLSETEDITOR_API EAppReturnType::Type ShowModal(); 87 | 88 | /** Gets the resulting asset path */ 89 | VERTEXANIMTOOLSETEDITOR_API const FText& GetAssetPath(); 90 | 91 | /** Gets the resulting asset name */ 92 | VERTEXANIMTOOLSETEDITOR_API const FText& GetAssetName(); 93 | 94 | /** Gets the resulting full asset path (path+'/'+name) */ 95 | VERTEXANIMTOOLSETEDITOR_API FText GetFullAssetPath(); 96 | 97 | void OnCheckedOnlyCreateStaticMesh(ECheckBoxState NewCheckedState); 98 | 99 | UVertexAnimProfile* GetSelectedProfile() const; 100 | 101 | bool GetOnlyCreateStaticMesh() const 102 | { 103 | return bOnlyCreateStaticMesh; 104 | } 105 | 106 | bool Filter(const FAssetData& AssetData); 107 | 108 | int32 ValidateProfile() const; 109 | 110 | private: 111 | /** Used to get the currently selected assets */ 112 | FGetCurrentSelectionDelegate GetCurrentSelectionDelegate_Profile; 113 | 114 | protected: 115 | void OnPathChange(const FString& NewPath); 116 | void OnNameChange(const FText& NewName, ETextCommit::Type CommitInfo); 117 | FReply OnButtonClick(EAppReturnType::Type ButtonID); 118 | 119 | bool ValidatePackage(); 120 | 121 | EAppReturnType::Type UserResponse; 122 | 123 | FText AssetPath; 124 | FText AssetName; 125 | 126 | bool bOnlyCreateStaticMesh = false; 127 | }; 128 | 129 | #undef LOCTEXT_NAMESPACE 130 | -------------------------------------------------------------------------------- /VertexAnimToolset/Source/VertexAnimToolsetEditor/VertexAnimToolsetEditor.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class VertexAnimToolsetEditor : ModuleRules 6 | { 7 | public VertexAnimToolsetEditor(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "VertexAnimToolset", 29 | "Core", 30 | "CoreUObject", 31 | "Engine", 32 | "RHI", 33 | "Engine", 34 | "RenderCore", 35 | // ... add other public dependencies that you statically link with here ... 36 | } 37 | ); 38 | 39 | 40 | PrivateDependencyModuleNames.AddRange( 41 | new string[] 42 | { 43 | "Projects", 44 | "TargetPlatform", 45 | "MeshDescription", 46 | "MeshDescriptionOperations", 47 | 48 | "CoreUObject", 49 | "Engine", 50 | "RawMesh", 51 | "Slate", 52 | "SlateCore", 53 | "UnrealEd", 54 | "EditorStyle", 55 | "RHI", 56 | "SlateCore", 57 | "Slate", 58 | "RenderCore", 59 | "AnimGraph", 60 | "AnimationBlueprintEditor", 61 | "AnimationEditor", 62 | "SkeletalMeshEditor", 63 | "MeshUtilities", 64 | // ... add private dependencies that you statically link with here ... 65 | } 66 | ); 67 | 68 | 69 | DynamicallyLoadedModuleNames.AddRange( 70 | new string[] 71 | { 72 | // ... add any modules that your module loads dynamically here ... 73 | } 74 | ); 75 | 76 | PrecompileForTargets = PrecompileTargetsType.Any; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /VertexAnimToolset/VertexAnimToolset.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "3.0", 5 | "FriendlyName": "Vertex Anim Toolset V3", 6 | "Description": "Tools for baking Skeletal Mesh animation into textures to animate meshes through the material shader", 7 | "Category": "Rendering", 8 | "CreatedBy": "Rexocrates", 9 | "CreatedByURL": "https://github.com/Rexocrates", 10 | "DocsURL": "https://github.com/Rexocrates/Vertex_Anim_Toolset/blob/main/Vertex%20Anim%20Toolset%20Documentation.pdf", 11 | "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/d998b22372a44975b312e85cf663bbab", 12 | "SupportURL": "https://github.com/Rexocrates/Vertex_Anim_Toolset/issues", 13 | "EngineVersion": "4.26.0", 14 | "CanContainContent": true, 15 | "Installed": false, 16 | "Modules": [ 17 | { 18 | "Name": "VertexAnimToolset", 19 | "Type": "UncookedOnly", 20 | "LoadingPhase": "PostConfigInit", 21 | "BlacklistPlatforms": [] 22 | }, 23 | { 24 | "Name": "VertexAnimToolsetEditor", 25 | "Type": "Editor", 26 | "LoadingPhase": "Default", 27 | "BlacklistPlatforms": [] 28 | } 29 | ] 30 | } --------------------------------------------------------------------------------