TanukiDigital Posted April 7 Posted April 7 I'm trying to adjust bone position/scale using the new ObjectMeshSkinned in 2.21 after all animation is calculated in the Animation graph. I've read through the updated API docs and it seems the best way to do this would be to access the base pose layer in the NodeSkeletonPose, however despite trying various variations I cannot seem to edit the bone position/scale afterward, all animation seems locked to what comes out of the graph. Below is the code I've been attempting, which I'm running in PostUpdate() (though I have also tried it in other Update() functions as well)... do you have any advice on best practices here? public NodeSkeletonPose skeletonAnimation; // Reference Skeleton SkeletonPoseDecomposed pose = new SkeletonPoseDecomposed(); pose.Skeleton = skeletonAnimation.Skeleton; // Pull from the LAYER, not the final Pose skeletonAnimation.GetLayerPose(0, pose); int boneIndex = skeletonAnimation.Skeleton.FindJoint("head"); if (boneIndex != -1) { // Get, Modify, and Re-Set FloatTransform poseTransform = pose.GetTransform(boneIndex); poseTransform.position += new vec3(0f, 0f, 2.5f); poseTransform.scale = new vec3(2.5f, 2.5f, 2.5f); pose.SetTransform(boneIndex, poseTransform); } // Push back to the layer skeletonAnimation.SetLayerPose(0, pose); // Recalculate world transforms for the renderer skeletonAnimation.ForceApplyPose();
karpych11 Posted April 8 Posted April 8 Hello. Layers are internal data of the animation graph. When a graph is assigned to NodeSkeletonPose, modifying layers externally won't work correctly: In Update: the graph will overwrite your values during its own update. In PostUpdate: the final pose has already been computed from the layers, so layer changes will have no effect. For manual corrections after the graph has run, use the following methods in PostUpdate to directly access the joints of the final pose: SetJointTransform / GetJointTransform SetJointPosition / GetJointPosition SetJointRotation / GetJointRotation SetJointScale / GetJointScale All of them operate on local transforms of the final pose joints. After making changes, call ForceApplyPose() to update skinning for all objects in the hierarchy. Here is a small example: void PostUpdate() { // get local transform of the head joint from the final pose mat4 headLocalTransform = skeletonPose.GetJointTransform(headJoint); // compute object-space transform by traversing parent chain mat4 headObjectTransform = GetJointObjectSpaceTransform(headJoint); // convert target position to the joint's local space vec3 targetLocalPosition = MathLib.Inverse(headObjectTransform) * targetObjectPosition; // compute rotation from current direction to target vec3 currentDirection = new vec3(headLocalTransform.AxisZ); vec3 targetDirection = MathLib.Normalize(targetLocalPosition - headLocalTransform.Translate); quat diff = MathLib.RotationFromTo(currentDirection, targetDirection); // apply rotation to the local transform headLocalTransform = headLocalTransform * MathLib.Rotate(diff); skeletonPose.SetJointTransform(headJoint, headLocalTransform); // update skinning skeletonPose.ForceApplyPose(); } mat4 GetJointObjectSpaceTransform(int joint) { mat4 t = skeletonPose.GetJointTransform(joint); int jointParent = skeletonPose.Skeleton.GetJointParent(joint); while (jointParent != -1) { t = skeletonPose.GetJointTransform(jointParent) * t; jointParent = skeletonPose.Skeleton.GetJointParent(jointParent); } return t; } joint_rotation.mp4 1
TanukiDigital Posted April 8 Author Posted April 8 Thank you so much, this is extremely helpful, and works just as you suggested!
Recommended Posts