Expected conventions for Skeleton3D bones' transforms?

Godot Version

4.6

Question

Hi! I’m trying to deepen my understanding of Skeleton3D and joint constraints in order to build my own physical skeleton / active ragdoll system. (Not using PhysicalSkeletonSimulator). I’m starting as simple as possible: building my own Skeleton with a @tool script, then building rigid bodies and joints around it. But just regarding Skeleton for now –

I built a rough humanoid Skeleton. But when I apply FABRIK3D to it for something simple (a limb reaching to a point), the solutions I get are awful, compared to a skeleton that I import from Blender. I suspect the discrepancy is that the basis vectors for my bones are wrong and that FABRIK relies on some conventions that I am not obeying.

So my questions are:

  • Are there conventions for the transform of a bone, specifically the rotation? Are they stronger than conventions, e.g. requirements, for systems like IK to work?
  • If so, what are the conventions? Should Y point along the bone? If so, should X or Z also be pointed in some specific way?
  • I’m deeply confused about whether a bone is named for its “start point” (the squat end of the prism) or its “end point” (the tapered end of the prism) … ?
  • If there is a convention, say it’s Y points along the bone, is it pointing from child to parent? Or parent to child?
  • If the convention is for Y to point from parent to child, what the heck do you do when there are multiple children? And does the guidance here change for optimal IK support?

Some possible related questions:

  • I notice there are no (set/get)_global_rest functions, even they exist for pose. Why is that? It makes me worried that I don’t understand rest; is it in a different frame of reference than a pose?

Is there anything else that’s relevant to what I’m asking about but haven’t thought to ask yet? (Unknown unknowns)

Thanks!

Also, I do have some code, but only posting this for context. I think my understanding of things might be so off-base it’s not even worth trying to bug fix this code. But this is where I’m at right now. It mangles the skeleton. If I don’t ever set any rotations, the skeleton is ok, but when i apply rotations, it ends up all twisted in on itsel

func basis_from_y(v: Vector3) -> Basis:
	var y = v.normalized()
	var x = y.cross(Vector3.UP)
	if x.length_squared() < 0.001:
		x = y.cross(Vector3.FORWARD)
	x = x.normalized()
	var z = x.cross(y)
	return Basis(x, y, z)

func set_bone(do_basis: bool, bone_idx: int, transform: Transform3D) -> void:
    # set positions first just so we can look them up later
	set_bone_global_pose(bone_idx, Transform3D(Basis.IDENTITY, transform.origin))
	set_bone_rest(bone_idx, get_bone_pose(bone_idx))
	if do_basis:
		var children = get_bone_children(bone_idx)
		if children != null and children.size() > 0:
            # now also set rotation
			var child_idx = children[0]
			var origin := get_bone_global_rest(bone_idx).origin
			var child_origin := get_bone_global_rest(child_idx).origin
			var bone = child_origin - origin
			var basis = basis_from_y(bone.normalized())
			set_bone_global_pose(bone_idx, Transform3D(basis, transform.origin))
			set_bone_rest(bone_idx, get_bone_pose(bone_idx))