How to Retrieve Bone Coordinates in Global Space with GeckoLib?

Started by landreyl on

Topic category: Help with Minecraft modding (Java Edition)

Joined Feb 2024
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
How to Retrieve Bone Coordinates in Global Space with GeckoLib?

Hello everyone,

I'm currently working with GeckoLib and I've encountered an issue while trying to retrieve the global coordinates of a bone in a 3D model. Specifically, I'm trying to find the coordinates of a bone relative to the model's root, taking into account its local transformations such as translation, rotation, and scaling.

Here is a general breakdown of what I'm trying to achieve:

  • I want to get the position of a bone in global coordinates, which involves combining the bone's local transformations (pivot, rotation, etc.) with its parent's transformations, all the way up the bone hierarchy.
  • I'm using GeckoLib's GeoBone class, and I am currently applying the getPivotX(), getPivotY(), and getPivotZ() methods to retrieve translation values, along with rotation methods for local transforms.
  • After applying the local transformations to a Matrix4f object, I'm multiplying them by the parent's transforms recursively.

Despite this approach, the results aren't as expected — the bone's global position doesn't seem correct in some cases, and I believe I may be overlooking something.

import org.joml.Matrix4f;
import org.joml.Vector3f;

private Vec3 getBoneWorldPosition(CoreGeoBone bone) {
    // Initialize the transformation matrix
    Matrix4f transform = new Matrix4f().identity();

    // Traverse up the bone hierarchy
    CoreGeoBone currentBone = bone;
    while (currentBone != null) {
        Matrix4f localTransform = new Matrix4f().identity();

        // Apply local transformations (translation, rotation)
        localTransform.translate(currentBone.getPivotX(), currentBone.getPivotY(), currentBone.getPivotZ());
        localTransform.rotateX((float) Math.toRadians(currentBone.getRotX()));
        localTransform.rotateY((float) Math.toRadians(currentBone.getRotY()));
        localTransform.rotateZ((float) Math.toRadians(currentBone.getRotZ()));

        // Apply the local transform to the accumulated global transform
        transform.mulLocal(localTransform);

        // Move to the parent bone
        currentBone = currentBone.getParent();
    }

    // Extract the global position from the final transformation matrix
    Vector3f worldPosition = transform.getTranslation(new Vector3f());
    return new Vec3(worldPosition.x(), worldPosition.y(), worldPosition.z());
}
Vec3 localPos = getBoneWorldPosition(bone);
        		
        		Vec3 globalPosition = new Vec3(
    				animatable.getX() + localPos.x,
    				animatable.getY() + localPos.y,
    				animatable.getZ() + localPos.z
				);

 

However, the results are not always accurate(the numbers are too big), especially when dealing with complex bone hierarchies or non-zero rotations. I’m wondering if there’s a better approach or a common pitfall I might be missing.

 

I also tried another approach but it didn't help either:

 

private Vec3 getBoneGlobalPosition(CoreGeoBone bone) {
Vec3 localPosition = new Vec3(bone.getPivotX(), bone.getPivotY(), bone.getPivotZ());
CoreGeoBone parentBone = bone.getParent();

// We go through the parents, adding their positions
while (parentBone != null) {
Vec3 parentPosition = new Vec3(parentBone.getPivotX(), parentBone.getPivotY(), parentBone.getPivotZ());
localPosition = localPosition.add(parentPosition);
parentBone = parentBone.getParent(); // Go to the parent bone
}

// Return global position
return localPosition;
}

Has anyone here worked with GeckoLib and dealt with similar issues? Any suggestions or insights on how to correctly calculate the bone’s global position in world space would be greatly appreciated!

Thank you in advance!

Joined Feb 2024
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • MCreator plugins:
  • Comments:
Hi everyone, After spending…
Wed, 11/27/2024 - 10:35

Hi everyone,

After spending some time working with GeckoLib and trying to calculate the global coordinates of a bone, I found a simpler and more efficient solution. Initially, I was attempting to manually apply local transformations and recursively multiply them with parent bone transformations. However, I encountered issues with accuracy, especially when dealing with complex bone hierarchies and rotations.

Instead of manually combining the transformations, I realized that GeckoLib provides a more straightforward approach by using the GeoBone class's getWorldPosition() method. This method automatically calculates the global position of a bone, taking into account all local transformations and its parent's transformations.

Here’s the simplified solution:

private Vec3 getBoneWorldPosition(CoreGeoBone bone) {
   GeoBone geoBone = (GeoBone) bone;
   Vector3d worldPose = geoBone.getWorldPosition();
   return new Vec3(worldPose.x(), worldPose.y(), worldPose.z());
}

In this code:

  • The getWorldPosition() method returns the bone’s global position as a Vector3d.
  • We then convert the Vector3d to Vec3 (which is a custom class for your project, based on the context) for further use.

This approach directly gives you the correct global position without having to manually combine transformations, and it resolves issues like large or inaccurate values when using complex bone hierarchies.

I hope this helps others who are facing similar challenges with GeckoLib!