Add SetMasterPoseModel to Animated Model for modular characters
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user