Merge branch 'Swiggies-animated-model-additions'

This commit is contained in:
Wojtek Figat
2025-08-22 23:04:00 +02:00
2 changed files with 73 additions and 1 deletions

View File

@@ -176,6 +176,14 @@ void AnimatedModel::GetNodeTransformation(const StringView& nodeName, Matrix& no
GetNodeTransformation(SkinnedModel ? SkinnedModel->FindNode(nodeName) : -1, nodeTransformation, worldSpace);
}
void AnimatedModel::GetNodeTransformation(Array<NodeTransformation>& nodeTransformations, bool worldSpace) const
{
for (NodeTransformation& item : nodeTransformations)
{
GetNodeTransformation(item.NodeIndex, item.NodeMatrix, worldSpace);
}
}
void AnimatedModel::SetNodeTransformation(int32 nodeIndex, const Matrix& nodeTransformation, bool worldSpace)
{
if (GraphInstance.NodesPose.IsEmpty())
@@ -193,6 +201,33 @@ void AnimatedModel::SetNodeTransformation(int32 nodeIndex, const Matrix& nodeTra
OnAnimationUpdated();
}
void AnimatedModel::SetNodeTransformation(const Array<NodeTransformation>& nodeTransformations, bool worldSpace)
{
if (GraphInstance.NodesPose.IsEmpty())
const_cast<AnimatedModel*>(this)->PreInitSkinningData(); // Ensure to have valid nodes pose to return
// Calculate it once, outside loop
Matrix invWorld;
if (worldSpace)
{
Matrix world;
GetLocalToWorldMatrix(world);
Matrix::Invert(world, invWorld);
}
for (int i = 0; i < nodeTransformations.Count(); i++)
{
int nodeIndex = nodeTransformations[i].NodeIndex;
CHECK(nodeIndex >= 0 && nodeIndex < GraphInstance.NodesPose.Count());
GraphInstance.NodesPose[nodeIndex] = nodeTransformations[i].NodeMatrix;
if (worldSpace)
{
GraphInstance.NodesPose[nodeIndex] = GraphInstance.NodesPose[nodeIndex] * invWorld;
}
}
OnAnimationUpdated();
}
void AnimatedModel::SetNodeTransformation(const StringView& nodeName, const Matrix& nodeTransformation, bool worldSpace)
{
SetNodeTransformation(SkinnedModel ? SkinnedModel->FindNode(nodeName) : -1, nodeTransformation, worldSpace);
@@ -821,7 +856,10 @@ void AnimatedModel::OnAnimationUpdated_Async()
_skinningData.OnDataChanged(!PerBoneMotionBlur);
}
UpdateBounds();
if (UpdateWhenOffscreen)
{
UpdateBounds();
}
}
void AnimatedModel::OnAnimationUpdated_Sync()

View File

@@ -18,6 +18,24 @@ class FLAXENGINE_API AnimatedModel : public ModelInstanceActor
DECLARE_SCENE_OBJECT(AnimatedModel);
friend class AnimationsSystem;
/// <summary>
/// Keeps the data of a Node and its relevant Transform Matrix together when passing it between functions.
/// </summary>
API_STRUCT() struct NodeTransformation
{
DECLARE_SCRIPTING_TYPE_MINIMAL(NodeTransformation);
/// <summary>
/// The index of the node in the node hierarchy.
/// </summary>
API_FIELD() uint32 NodeIndex;
/// <summary>
/// The transformation matrix of the node
/// </summary>
API_FIELD() Matrix NodeMatrix;
};
/// <summary>
/// Describes the animation graph updates frequency for the animated model.
/// </summary>
@@ -236,6 +254,14 @@ public:
/// <param name="worldSpace">True if convert matrices into world-space, otherwise returned values will be in local-space of the actor.</param>
API_FUNCTION() void GetNodeTransformation(const StringView& nodeName, API_PARAM(Out) Matrix& nodeTransformation, bool worldSpace = false) const;
/// <summary>
/// Gets the node final transformation for a series of nodes.
/// </summary>
/// <param name="nodeTransformations">The series of nodes that will be returned</param>
/// <param name="worldSpace">True if convert matrices into world-space, otherwise returned values will be in local-space of the actor.</param>
/// <returns></returns>
API_FUNCTION() void GetNodeTransformation(API_PARAM(Ref) Array<NodeTransformation>& nodeTransformations, bool worldSpace = false) const;
/// <summary>
/// Sets the node final transformation. If multiple nodes are to be set within a frame, do not use set worldSpace to true, and do the conversion yourself to avoid recalculation of inv matrices.
/// </summary>
@@ -252,6 +278,14 @@ public:
/// <param name="worldSpace">True if convert matrices from world-space, otherwise values will be in local-space of the actor.</param>
API_FUNCTION() void SetNodeTransformation(const StringView& nodeName, const Matrix& nodeTransformation, bool worldSpace = false);
/// <summary>
/// Sets a group of nodes final transformation.
/// </summary>
/// <param name="nodeTransformations">Array of the final node transformation matrix.</param>
/// <param name="worldSpace">True if convert matrices from world-space, otherwise values will be in local-space of the actor.</param>
/// <returns></returns>
API_FUNCTION() void SetNodeTransformation(const Array<NodeTransformation>& nodeTransformations, bool worldSpace = false);
/// <summary>
/// Finds the closest node to a given location.
/// </summary>