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!