Bone Modifier Rotation

Godot Version

4.3

Question

I made a manual animation player following a Fair Fight YouTube channel video, but I am stuck on rotation when using the bone modifier.

My camera position and rotation setup looks like this:

And previews show everything as it should look:

My SuggestBonePose method returns a Transform3D, which provides 3D transformation information.

 public override Transform3D SuggestBonePose(int boneIndex)
    {
        var fBlendingPercentage = (float)_blendingPercentage;
        var transform = new Transform3D
        {
            Origin = Vector3.Inf
        };

        _track = _currentAnimation.FindTrack(BoneToTrackName(boneIndex), Godot.Animation.TrackType.Rotation3D);
        if (_track != -1)
        {
            if (_nextAnimation != null)
            {
                var currentPoseRotation = _currentAnimation.RotationTrackInterpolate(_track, _currentAnimationProgress).Normalized();
                var nextPoseRotation = _nextAnimation.RotationTrackInterpolate(_track, _nextAnimationProgress).Normalized();

                var interpolatedPoseRotation = new Quaternion(
                    Mathf.Lerp(currentPoseRotation.X, nextPoseRotation.X, fBlendingPercentage),
                    Mathf.Lerp(currentPoseRotation.Y, nextPoseRotation.Y, fBlendingPercentage),
                    Mathf.Lerp(currentPoseRotation.Z, nextPoseRotation.Z, fBlendingPercentage),
                    Mathf.Lerp(currentPoseRotation.W, nextPoseRotation.W, fBlendingPercentage)
                ).Normalized();

                transform.Basis = new Basis(interpolatedPoseRotation);
            }
            else
            {
                var initialRotation = _currentAnimation.RotationTrackInterpolate(_track, _currentAnimationProgress);
                transform.Basis = new Basis(initialRotation);
            }
        }

        _track = _currentAnimation.FindTrack(BoneToTrackName(boneIndex), Godot.Animation.TrackType.Position3D);
        if (_track == -1) return transform;

        if (_nextAnimation != null)
        {
            var currentPosePosition = _currentAnimation.PositionTrackInterpolate(_track, _currentAnimationProgress);
            var nextPosePosition = _nextAnimation.PositionTrackInterpolate(_track, _nextAnimationProgress);
            var interpolatedPosePosition = currentPosePosition.Lerp(nextPosePosition, fBlendingPercentage);
            transform.Origin = interpolatedPosePosition;
        }else transform.Origin = _currentAnimation.PositionTrackInterpolate(_track, _currentAnimationProgress);

        return transform;
    } 

This is the _ProcessModification method I’ve overridden, which iterates through all bones, requests the appropriate Transform3D for each bone, and applies the transformations to the current skeleton. My expectation is that everything should look as I intended, but when I run it, I get this result:

    public override void _ProcessModification()
    {
        if (_currentState == null) return;
        UpdateParameters();
        _currentState.UpdateParameters(_lastInput);
        if(_isBlending)
            _nextState.UpdateParameters(_lastInput);

        for (var boneIndex = 0; boneIndex < _skeleton.GetBoneCount(); boneIndex++)
        {
            _currentTransform = _currentState.SuggestBonePose(boneIndex);
            if (_isBlending)
            {
                var fBlendingPercentage = (float)_blendingPercentage;
                _nextTransform = _nextState.SuggestBonePose(boneIndex);
                _skeleton.SetBonePoseRotation(boneIndex, _currentTransform.Basis.GetRotationQuaternion().Slerp(_nextTransform.Basis.GetRotationQuaternion(), fBlendingPercentage));
                if(_currentTransform.Origin != Vector3.Inf)
                    _skeleton.SetBonePosePosition(boneIndex, _currentTransform.Origin.Slerp(_nextTransform.Origin, fBlendingPercentage));
            }
            else
            {
                _skeleton.SetBonePoseRotation(boneIndex, -_currentTransform.Basis.GetRotationQuaternion());
                if(_currentTransform.Origin != Vector3.Inf)
                    _skeleton.SetBonePosePosition(boneIndex, _currentTransform.Origin);
            }
        }
    }

I’m facing an issue where it doesn’t look as expected. At first, I thought it was related to my camera rotation, but it’s not. When I play with the default animation player , the camera running as I expected, but when I switch to my animation player , the character’s head turns downward, and the entire body rotates 180 degrees.

What might I be missing?

I found the mistake I made: it was all about the basis vector of the bone transform. When I don’t assign the identity basis vector to Transform3D, the assumed direction is rotated 180 degrees on the Z-axis. I resolved this by assigning Basis.Identity.

var transform = new Transform3D
{
    Origin = Vector3.Inf,
    Basis = Basis.Identity
};

Now, everything looks perfect!