I'm working on a program in Godot using Gdscript, and I ran into a problem when trying to use the Transform.translated(Vector3)
function. My code is supposed to move a bone to (0,0,0) by translating it by its current coordinates but with negative sign. Example: (1,2,3) would be translated by (-1,-2,-3) so it would end up at (0,0,0). For some reason when I do this, the end position of the bone is not (0,0,0), but some other coordinate. In the Godot documents, it says the .translated function is "relative to the transform's basis vectors", so maybe that's why? Also if there is a better way to change a bones position than using the Transform.translated(Vector3)
function that would be helpful too. Thanks!
My Code:
bonePose = skel.get_bone_global_pose(bone)
var globalBonePose = skel.to_global(bonePose.origin)
translateVector = -globalBonePose
var newPose = bonePose.translated(translateVector)
skel.set_bone_pose(bone, newPose)
Code Output / Results:
bonePose (the original position of the bone) is around (-0.82,0.49,0.50)
translateVector (the amount the bone will be translated) is around (0.82,-0.49,-0.50)
newPose (the final position of the bone -- should be [0,0,0]) is around (0.82,-0.66,-0.46). Even when I call skel.to_global(newPose.origin)
to see the global coordinates, it's (-0.76,0.44,0.42), which is not (0,0,0)
In Godot a Transform
is composed of a basis
(a Basis
) and an origin
(a Vector3
). Where the origin
handles the translation part of the transform, and the Basis
the rest.
A Basis
is the set of vectors that define the coordinate system. There is a vector that defines the x
axis, another for the y
axis, and another for the z
axis. And this is the way Godot will encode rotation and scaling transformations.
When the documentation says "relative to the transform's basis vectors" it means the Basis
will be applied to the vector you pass in. Thus, in your case, you are getting a translation on the local space of the bone. Which implies that if the bone is rotated or scaled (or something like that), that will affect the translation.
If you don't want to deal with rotation, scaling, et.al. I suggest you work with the origin
of the Transform
instead.
If you have a Transform
and you want another that is otherwise equal but located at (0, 0, 0)
, you do this:
var new_transform = Transform(transform.basis, Vector.ZERO)
Or replace Vector.ZERO
with whatever origin you want to give the new transform.
I also need to remind you that get_bone_global_pose
and set_bone_pose
do not operate on the same thing. On one hand set_bone_pose
is relative to the parent bone, on the other get_bone_global_pose
is relative to the Skeleton
. Thus, I suggest you use set_bone_global_pose_override
instead.
The final piece you need is the opposite of Spatial.to_global
. Because setting the pose like as follows…
bonePose = skel.get_bone_global_pose(bone)
var newPose = Transform(bonePose.basis, Vector.ZERO)
skel.set_bone_global_pose_override(bone, newPose, 1.0)
… Would place it at the origin of the Skeleton
.
Well, the opposite of Spatial.to_global
is Spatial.to_local
, and you would use it like this:
bonePose = skel.get_bone_global_pose(bone)
var newPose = Transform(bonePose.basis, skel.to_local(Vector.ZERO))
skel.set_bone_global_pose_override(bone, newPose, 1.0)
Here skel.to_local(Vector.ZERO)
should give the origin of the world relative to the Skeleton
. And given that set_bone_global_pose_override
wants a Transform
relative to the Skeleton
, the result should be that the bone is placed at the origin of the world. With its rotation and scaling preserved.