Add support for using animated model with anim graph using different skinned model
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
|
||||
Array<AnimatedModel*> UpdateList(256);
|
||||
Array<AnimatedModel*> UpdateList;
|
||||
Array<Matrix> UpdateBones;
|
||||
|
||||
class AnimationManagerService : public EngineService
|
||||
{
|
||||
@@ -67,9 +68,24 @@ void AnimationManagerService::Update()
|
||||
}
|
||||
animatedModel->GraphInstance.LastUpdateTime = t;
|
||||
|
||||
const auto bones = graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);
|
||||
// Evaluate animated nodes pose
|
||||
graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);
|
||||
|
||||
// Calculate the final bones transformations
|
||||
{
|
||||
ANIM_GRAPH_PROFILE_EVENT("Final Pose");
|
||||
auto& skeleton = animatedModel->SkinnedModel->Skeleton;
|
||||
UpdateBones.Resize(skeleton.Bones.Count(), false);
|
||||
for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++)
|
||||
{
|
||||
auto& bone = skeleton.Bones[boneIndex];
|
||||
UpdateBones[boneIndex] = bone.OffsetMatrix * animatedModel->GraphInstance.NodesPose[bone.NodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Update gameplay
|
||||
const bool usePrevFrameBones = animatedModel->PerBoneMotionBlur;
|
||||
animatedModel->_skinningData.SetData(bones, !usePrevFrameBones);
|
||||
animatedModel->_skinningData.SetData(UpdateBones.Get(), !usePrevFrameBones);
|
||||
animatedModel->OnAnimUpdate();
|
||||
}
|
||||
}
|
||||
@@ -79,6 +95,7 @@ void AnimationManagerService::Update()
|
||||
void AnimationManagerService::Dispose()
|
||||
{
|
||||
UpdateList.Resize(0);
|
||||
UpdateBones.Resize(0);
|
||||
}
|
||||
|
||||
void AnimationManager::AddToUpdate(AnimatedModel* obj)
|
||||
|
||||
@@ -152,8 +152,8 @@ bool AnimGraph::IsReady() const
|
||||
|
||||
bool AnimGraph::CanUseWithSkeleton(SkinnedModel* other) const
|
||||
{
|
||||
// All data loaded and bones count the same
|
||||
return IsReady() && other && other->IsLoaded() && other->Skeleton.Bones.Count() == BaseModel->Skeleton.Bones.Count();
|
||||
// All data loaded and nodes count the same
|
||||
return IsReady() && other && other->IsLoaded() && other->Skeleton.Nodes.Count() == BaseModel->Skeleton.Nodes.Count();
|
||||
}
|
||||
|
||||
void AnimGraph::ClearCustomNode(Node* node)
|
||||
|
||||
@@ -175,7 +175,7 @@ AnimGraphExecutor::AnimGraphExecutor(AnimGraph& graph)
|
||||
_perGroupProcessCall[16] = (ProcessBoxHandler)&AnimGraphExecutor::ProcessGroupFunction;
|
||||
}
|
||||
|
||||
const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
{
|
||||
ASSERT(data.Parameters.Count() == _graph.Parameters.Count());
|
||||
|
||||
@@ -185,7 +185,6 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
ANIM_GRAPH_PROFILE_EVENT("Init");
|
||||
|
||||
// Prepare graph data for the evaluation
|
||||
_skeletonBonesCount = skeleton.Bones.Count();
|
||||
_skeletonNodesCount = skeleton.Nodes.Count();
|
||||
_graphStack.Clear();
|
||||
_graphStack.Push((Graph*)&_graph);
|
||||
@@ -265,23 +264,19 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
|
||||
_data->RootMotion = animResult->RootMotion;
|
||||
}
|
||||
|
||||
// Calculate the final bones transformations
|
||||
{
|
||||
ANIM_GRAPH_PROFILE_EVENT("Final Pose");
|
||||
|
||||
_bonesTransformations.Resize(_skeletonBonesCount, false);
|
||||
|
||||
for (int32 boneIndex = 0; boneIndex < _skeletonBonesCount; boneIndex++)
|
||||
{
|
||||
auto& bone = skeleton.Bones[boneIndex];
|
||||
_bonesTransformations[boneIndex] = bone.OffsetMatrix * _data->NodesPose[bone.NodeIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
_data = nullptr;
|
||||
}
|
||||
|
||||
return _bonesTransformations.Get();
|
||||
void AnimGraphExecutor::GetInputValue(Box* box, Value& result)
|
||||
{
|
||||
result = eatBox(box->GetParent<Node>(), box->FirstConnection());
|
||||
}
|
||||
|
||||
void AnimGraphExecutor::ResetBucket(int32 bucketIndex)
|
||||
{
|
||||
auto& stateBucket = _data->State[bucketIndex];
|
||||
_graph._bucketInitializerList[bucketIndex](stateBucket);
|
||||
}
|
||||
|
||||
void AnimGraphExecutor::ResetBuckets(AnimGraphBase* graph)
|
||||
|
||||
@@ -817,12 +817,10 @@ private:
|
||||
AnimGraph& _graph;
|
||||
float _deltaTime = 0.0f;
|
||||
uint64 _currentFrameIndex = 0;
|
||||
int32 _skeletonBonesCount = 0;
|
||||
int32 _skeletonNodesCount = 0;
|
||||
RootMotionMode _rootMotionMode = RootMotionMode::NoExtraction;
|
||||
AnimGraphInstanceData* _data = nullptr;
|
||||
AnimGraphImpulse _emptyNodes;
|
||||
Array<Matrix> _bonesTransformations;
|
||||
AnimGraphTransitionData _transitionData;
|
||||
Array<Node*, FixedAllocation<ANIM_GRAPH_MAX_CALL_STACK>> _callStack;
|
||||
Array<Graph*, FixedAllocation<32>> _graphStack;
|
||||
@@ -853,18 +851,13 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="data">The instance data.</param>
|
||||
/// <param name="dt">The delta time (in seconds).</param>
|
||||
/// <returns>The pointer to the final bones structure as a result of the animation evaluation.</returns>
|
||||
const Matrix* Update(AnimGraphInstanceData& data, float dt);
|
||||
void Update(AnimGraphInstanceData& data, float dt);
|
||||
|
||||
void GetInputValue(Box* box, Value& result)
|
||||
{
|
||||
result = eatBox(box->GetParent<Node>(), box->FirstConnection());
|
||||
}
|
||||
void GetInputValue(Box* box, Value& result);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the skeleton nodes transformations structure containing identity matrices.
|
||||
/// </summary>
|
||||
/// <returns>The data.</returns>
|
||||
FORCE_INLINE const AnimGraphImpulse* GetEmptyNodes() const
|
||||
{
|
||||
return &_emptyNodes;
|
||||
@@ -914,11 +907,7 @@ public:
|
||||
/// Resets the state bucket.
|
||||
/// </summary>
|
||||
/// <param name="bucketIndex">The zero-based index of the bucket.</param>
|
||||
FORCE_INLINE void ResetBucket(int32 bucketIndex)
|
||||
{
|
||||
auto& stateBucket = _data->State[bucketIndex];
|
||||
_graph._bucketInitializerList[bucketIndex](stateBucket);
|
||||
}
|
||||
void ResetBucket(int32 bucketIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Resets all the state bucket used by the given graph including sub-graphs (total). Can eb used to reset the animation state of the nested graph (including children).
|
||||
|
||||
@@ -636,7 +636,8 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One);
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (boneIndex < 0 || boneIndex >= _skeletonBonesCount || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
|
||||
auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
if (boneIndex < 0 || boneIndex >= skeleton.Bones.Count() || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
|
||||
{
|
||||
// Pass through the input
|
||||
value = Value::Null;
|
||||
@@ -767,8 +768,9 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
const auto copyScale = (bool)node->Values[4];
|
||||
|
||||
// Skip if no change will be performed
|
||||
if (srcBoneIndex < 0 || srcBoneIndex >= _skeletonBonesCount ||
|
||||
dstBoneIndex < 0 || dstBoneIndex >= _skeletonBonesCount ||
|
||||
const auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
if (srcBoneIndex < 0 || srcBoneIndex >= skeleton.Bones.Count() ||
|
||||
dstBoneIndex < 0 || dstBoneIndex >= skeleton.Bones.Count() ||
|
||||
!(copyTranslation || copyRotation || copyScale))
|
||||
{
|
||||
// Pass through the input
|
||||
@@ -776,7 +778,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
box->Cache = value;
|
||||
return;
|
||||
}
|
||||
const auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
|
||||
// Copy bone data
|
||||
Transform srcTransform = nodes->Nodes[skeleton.Bones[srcBoneIndex].NodeIndex];
|
||||
@@ -800,7 +801,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
const auto boneIndex = (int32)node->Values[0];
|
||||
const auto& skeleton = _graph.BaseModel->Skeleton;
|
||||
const auto input = tryGetValue(node->GetBox(0), Value::Null);
|
||||
if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < _skeletonBonesCount)
|
||||
if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < skeleton.Bones.Count())
|
||||
value = Variant(((AnimGraphImpulse*)input.AsPointer)->Nodes[skeleton.Bones[boneIndex].NodeIndex]);
|
||||
else
|
||||
value = Variant(Transform::Identity);
|
||||
|
||||
Reference in New Issue
Block a user