I adapted your function to work with my variables, and am comparing it to the transform that my original code has constructed. The below screenshot of my debugger shows new_t
with the correct transform, reached with Euler math, and new_direction
, the vector calculated from your example. On the right you can see transform
, which is the player's current transform when entering the teleport plane. It appears that new_direction
is close to the z
component of new_t
, but new_direction.y
is negative when it should be positive. I also still need the x
and y
components of the transform with your method.
Thank you for helping, I know it's my lack of understanding that's the problem here. If I knew more about the subject I know I could take your advice and apply it properly :(

var to_rot = tp["to_transform"].basis.get_euler()
var from_rot = tp["from_transform"].basis.get_euler()
var rot_diff = to_rot + from_rot
var new_t = Transform()
new_t.origin = state.get_transform().origin - tp["from_transform"].origin
new_t.basis = state.get_transform().basis
if rot_diff.y != 0.0:
new_t = new_t.rotated(Vector3(0, 1, 0), -rot_diff.y)
state.set_linear_velocity(state.get_linear_velocity().rotated(Vector3(0, 1, 0), -rot_diff.y))
state.set_angular_velocity(state.get_angular_velocity().rotated(Vector3(0, 1, 0), -rot_diff.y))
if rot_diff.z != 0.0:
new_t = new_t.rotated(Vector3(0, 0, 1), rot_diff.z)
state.set_linear_velocity(state.get_linear_velocity().rotated(Vector3(0, 0, 1), rot_diff.z))
state.set_angular_velocity(state.get_angular_velocity().rotated(Vector3(0, 0, 1), rot_diff.z))
if rot_diff.x != 0.0:
new_t = new_t.rotated(Vector3(1, 0, 0), -rot_diff.x)
state.set_linear_velocity(state.get_linear_velocity().rotated(Vector3(1, 0, 0), -rot_diff.x))
state.set_angular_velocity(state.get_angular_velocity().rotated(Vector3(0, 0, 0), -rot_diff.x))
new_t.origin += tp["from_transform"].origin
new_t.origin -= tp["from_transform"].origin - tp["to_transform"].origin
# this is the global direction vector the player is facing, one unit forward minus the players global offset
var global_player_direction = body.to_global( Vector3.FORWARD ) - body.global_transform.origin
# now add this direction to the global position of the portal and transform this into local coordinate system of the portal. this is the relative (to the portal) viewing vector of the player.
var relative_player_direction = tp["from_body"].to_local( tp["from_transform"].origin + global_player_direction)
# transform this relative direction to global from the coordinate system of the other portal
var new_direction = tp["to_body"].to_global( relative_player_direction ) - tp["to_transform"].origin
# debug screenshot point
state.set_transform(new_t)