Add SetMasterPoseModel to Animated Model for modular characters

This commit is contained in:
Wojtek Figat
2021-05-13 14:41:43 +02:00
parent 899e749d2d
commit fb5c45f474
3 changed files with 32 additions and 4 deletions

View File

@@ -64,7 +64,6 @@ public:
/// <summary> /// <summary>
/// Gets the amount of loaded model LODs. /// Gets the amount of loaded model LODs.
/// </summary> /// </summary>
/// <returns>Loaded LODs count</returns>
API_PROPERTY() FORCE_INLINE int32 GetLoadedLODs() const API_PROPERTY() FORCE_INLINE int32 GetLoadedLODs() const
{ {
return _loadedLODs; return _loadedLODs;
@@ -93,7 +92,6 @@ public:
/// <summary> /// <summary>
/// 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) /// 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)
/// </summary> /// </summary>
/// <returns>LOD index</returns>
FORCE_INLINE int32 HighestResidentLODIndex() const FORCE_INLINE int32 HighestResidentLODIndex() const
{ {
return GetLODsCount() - _loadedLODs; return GetLODsCount() - _loadedLODs;

View File

@@ -44,7 +44,8 @@ void AnimatedModel::UpdateAnimation()
|| !IsActiveInHierarchy() || !IsActiveInHierarchy()
|| SkinnedModel == nullptr || SkinnedModel == nullptr
|| !SkinnedModel->IsLoaded() || !SkinnedModel->IsLoaded()
|| _lastUpdateFrame == Engine::FrameCount) || _lastUpdateFrame == Engine::FrameCount
|| _masterPose)
return; return;
_lastUpdateFrame = Engine::FrameCount; _lastUpdateFrame = Engine::FrameCount;
@@ -183,6 +184,17 @@ int32 AnimatedModel::FindClosestNode(const Vector3& location, bool worldSpace) c
return result; return result;
} }
void AnimatedModel::SetMasterPoseModel(AnimatedModel* masterPose)
{
if (masterPose == _masterPose)
return;
if (_masterPose)
_masterPose->AnimationUpdated.Unbind<AnimatedModel, &AnimatedModel::OnAnimationUpdated>(this);
_masterPose = masterPose;
if (_masterPose)
_masterPose->AnimationUpdated.Bind<AnimatedModel, &AnimatedModel::OnAnimationUpdated>(this);
}
#define CHECK_ANIM_GRAPH_PARAM_ACCESS() \ #define CHECK_ANIM_GRAPH_PARAM_ACCESS() \
if (!AnimationGraph) \ if (!AnimationGraph) \
{ \ { \
@@ -378,6 +390,7 @@ void AnimatedModel::BeginPlay(SceneBeginData* data)
void AnimatedModel::EndPlay() void AnimatedModel::EndPlay()
{ {
AnimationManager::RemoveFromUpdate(this); AnimationManager::RemoveFromUpdate(this);
SetMasterPoseModel(nullptr);
// Base // Base
ModelInstanceActor::EndPlay(); ModelInstanceActor::EndPlay();
@@ -443,11 +456,21 @@ void AnimatedModel::UpdateBounds()
void AnimatedModel::OnAnimationUpdated() void AnimatedModel::OnAnimationUpdated()
{ {
ANIM_GRAPH_PROFILE_EVENT("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 // Calculate the final bones transformations and update skinning
{ {
ANIM_GRAPH_PROFILE_EVENT("Final Pose"); ANIM_GRAPH_PROFILE_EVENT("Final Pose");
auto& skeleton = SkinnedModel->Skeleton;
UpdateBones.Resize(skeleton.Bones.Count(), false); UpdateBones.Resize(skeleton.Bones.Count(), false);
for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++) for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++)
{ {

View File

@@ -65,6 +65,7 @@ private:
float _lastMinDstSqr; float _lastMinDstSqr;
uint64 _lastUpdateFrame; uint64 _lastUpdateFrame;
BlendShapesInstance _blendShapes; BlendShapesInstance _blendShapes;
ScriptingObjectReference<AnimatedModel> _masterPose;
public: public:
@@ -224,6 +225,12 @@ public:
/// <returns>The zero-based index of the found node. Returns -1 if skeleton is missing.</returns> /// <returns>The zero-based index of the found node. Returns -1 if skeleton is missing.</returns>
API_FUNCTION() int32 FindClosestNode(const Vector3& location, bool worldSpace = false) const; API_FUNCTION() int32 FindClosestNode(const Vector3& location, bool worldSpace = false) const;
/// <summary>
/// Sets the master pose model that will be used to copy the skeleton nodes animation. Useful for modular characters.
/// </summary>
/// <param name="masterPose">The master pose actor to use.</param>
API_FUNCTION() void SetMasterPoseModel(AnimatedModel* masterPose);
public: public:
/// <summary> /// <summary>