From fb5c45f4742c5ca132b464ee80d96dad900441c4 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 13 May 2021 14:41:43 +0200 Subject: [PATCH] Add `SetMasterPoseModel` to Animated Model for modular characters --- Source/Engine/Content/Assets/SkinnedModel.h | 2 -- Source/Engine/Level/Actors/AnimatedModel.cpp | 27 ++++++++++++++++++-- Source/Engine/Level/Actors/AnimatedModel.h | 7 +++++ 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Source/Engine/Content/Assets/SkinnedModel.h b/Source/Engine/Content/Assets/SkinnedModel.h index d2d6eba96..08cbf23b0 100644 --- a/Source/Engine/Content/Assets/SkinnedModel.h +++ b/Source/Engine/Content/Assets/SkinnedModel.h @@ -64,7 +64,6 @@ public: /// /// Gets the amount of loaded model LODs. /// - /// Loaded LODs count API_PROPERTY() FORCE_INLINE int32 GetLoadedLODs() const { return _loadedLODs; @@ -93,7 +92,6 @@ public: /// /// Gets index of the highest resident LOD (may be equal to LODs.Count if no LOD has been uploaded). Note: LOD=0 is the highest (top quality) /// - /// LOD index FORCE_INLINE int32 HighestResidentLODIndex() const { return GetLODsCount() - _loadedLODs; diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index a1a9d6db6..a62aad592 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -44,7 +44,8 @@ void AnimatedModel::UpdateAnimation() || !IsActiveInHierarchy() || SkinnedModel == nullptr || !SkinnedModel->IsLoaded() - || _lastUpdateFrame == Engine::FrameCount) + || _lastUpdateFrame == Engine::FrameCount + || _masterPose) return; _lastUpdateFrame = Engine::FrameCount; @@ -183,6 +184,17 @@ int32 AnimatedModel::FindClosestNode(const Vector3& location, bool worldSpace) c return result; } +void AnimatedModel::SetMasterPoseModel(AnimatedModel* masterPose) +{ + if (masterPose == _masterPose) + return; + if (_masterPose) + _masterPose->AnimationUpdated.Unbind(this); + _masterPose = masterPose; + if (_masterPose) + _masterPose->AnimationUpdated.Bind(this); +} + #define CHECK_ANIM_GRAPH_PARAM_ACCESS() \ if (!AnimationGraph) \ { \ @@ -378,6 +390,7 @@ void AnimatedModel::BeginPlay(SceneBeginData* data) void AnimatedModel::EndPlay() { AnimationManager::RemoveFromUpdate(this); + SetMasterPoseModel(nullptr); // Base ModelInstanceActor::EndPlay(); @@ -443,11 +456,21 @@ void AnimatedModel::UpdateBounds() void AnimatedModel::OnAnimationUpdated() { ANIM_GRAPH_PROFILE_EVENT("OnAnimationUpdated"); + auto& skeleton = SkinnedModel->Skeleton; + + // Copy pose from the master + if (_masterPose && _masterPose->SkinnedModel->Skeleton.Nodes.Count() == skeleton.Nodes.Count()) + { + ANIM_GRAPH_PROFILE_EVENT("Copy Master Pose"); + const auto& masterInstance = _masterPose->GraphInstance; + GraphInstance.NodesPose = masterInstance.NodesPose; + GraphInstance.RootTransform = masterInstance.RootTransform; + GraphInstance.RootMotion = masterInstance.RootMotion; + } // Calculate the final bones transformations and update skinning { ANIM_GRAPH_PROFILE_EVENT("Final Pose"); - auto& skeleton = SkinnedModel->Skeleton; UpdateBones.Resize(skeleton.Bones.Count(), false); for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++) { diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h index 6317e280c..df218b897 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.h +++ b/Source/Engine/Level/Actors/AnimatedModel.h @@ -65,6 +65,7 @@ private: float _lastMinDstSqr; uint64 _lastUpdateFrame; BlendShapesInstance _blendShapes; + ScriptingObjectReference _masterPose; public: @@ -224,6 +225,12 @@ public: /// The zero-based index of the found node. Returns -1 if skeleton is missing. API_FUNCTION() int32 FindClosestNode(const Vector3& location, bool worldSpace = false) const; + /// + /// Sets the master pose model that will be used to copy the skeleton nodes animation. Useful for modular characters. + /// + /// The master pose actor to use. + API_FUNCTION() void SetMasterPoseModel(AnimatedModel* masterPose); + public: ///