Hi,

Recently I started working with Godot, I was working with Stage3D before. In Stage3D, when I wanted to rotate an object relative to the viewport coordinate system I would use prependRotation, which means the rotation would be added before all other rotations that have been added to the transform matrix, vs if I wanted to rotate an object relative to it's own coordinate system, I could do appendRotation, which means the rotation would be added to the transform matrix of the object after all other rotations, which means it would be added according to the objects own local coordinate system, if the local Y axis has been orientated diffidently because of a previous rotation on the x axis, then if you do a y rotation you get a completely different result. so to prevent that, and only add a rotation in to the beginning of all other rotations, in Stage3D we had prependRotation, what do I do in Godot to get the same result?

If you work in a 3D modeling program, like 3DS Max, before you do a rotation you need to select a coordination system, it can be the view, or the world, or a group, or the local object, it all comes down to one thing: at what stage do you add the rotation, in the end, the object current position and orientation is an accumulation of all the rotations and movements in a certain order, the order makes all the difference, so I need to have a way to determine whether I want to add my rotation to the beginning or the end of all other rotations. What option do I have in Godot to determine that when I rotate an object?

basically I get it now, it is simple, the difference between putting the rotation in before or after all other rotation is the difference between this code:

root_group.transform.basis = Basis(Vector3(1, 0, 0), deg2rad(-_X)) * root_group.transform.basis

and this code which gives you a rotation relative to the local coordinate system:

root_group.transform.basis = root_group.transform.basis * Basis(Vector3(1, 0, 0), deg2rad(-_X))

simply the order in which you multiply the transform matrices, my real problem is how do I do the rotation of the object not relative to it's local coordinate system, nor relative to the world coordinate system, but relative to the camera coordinate system?

You could look at the camera as a parent transform... I don't know, I have to find a way to order the transforms so that the camera transform is the coordinate system. Any ideas?

Actually, what I used to do on Stage3D, I used to add all the parents transformations matrix to the child using prepend which adds each parent matrix to the beginning of the manipulation chain, and then add the camera matrix at the end, because really that is all what the camera is, another manipulation to the vertex array. Though I used to always put the camera looking straight towards the object, with no rotation, and add the camera rotation to the object rotation, just to keep things simple for me to understand. Now I want the camera to stay with it's rotation, because in Godot, I don't have to deal with too much math, most of the work was done for me, but then I also don't have to add the camera matrix before rendering an object because this is done for me, so how do I somehow cancel it? Or what do I do to have the rotation be done relative to the camera rotation?

I know if I do this:

root_group.transform.basis = camera.transform.basis * root_group.transform.basis

it is putting the object in front of the camera, as if the camera is not rotated, it is basically canceling the camera rotation, but not by rotating the camera to align with the world coordinates, it only rotate the object so the camera coordinate system is aligned with the object coordinate system, the rotation is still been done according to the world coordinate system which is not aligned with the camera coordinate system.

TBH I'm not entirely sure what it is you are trying to specifically do here, or why for that matter.

I want the user to be able to examine a model, rotate it from all sides to examine it, therefore I want the rotation to be relative to the camera position, one might ask, why not move the camera? the answer is, I have a few objects in the scene, I don't want to rotate all of them, only one of them, but it has to rotate so that when the user is moving the mouse from right to left, it will rotate around the y axis of the camera coordinate system, if it will rotate around the y axis of the objects coordinate system, this rotation can be unpredictable, not necessarily from right to left, depending on the orientation of the objects y axis at the given moment.

This code rotates an object based on the mouse movement relative to the camera's up and right vectors:

extends Camera

export (NodePath) var object_to_rotate_path;
var object_to_rotate;

var rotate_object_with_mouse = false;
const ROT_SPEED = 0.2;

func _ready():
	object_to_rotate = get_node(object_to_rotate_path);

func _input(event):
	
	if (event is InputEventMouseButton):
		if (event.button_index == BUTTON_LEFT):
			rotate_object_with_mouse = event.pressed;
	
	if (event is InputEventMouseMotion):
		if (rotate_object_with_mouse == true):
			var rotX = deg2rad(event.relative.x * ROT_SPEED);
			var rotY = deg2rad(event.relative.y * ROT_SPEED);
			
			# Rotate in world space (do not take camera into account)
			#object_to_rotate.global_rotate(Vector3.UP, rotX);
			#object_to_rotate.global_rotate(Vector3.RIGHT, rotY);
			
			# Rotate relative to the camera's rotation axes
			object_to_rotate.global_rotate(global_transform.basis.y, rotX);
			object_to_rotate.global_rotate(global_transform.basis.x, rotY);

This code is the same process described in this StackExchange answer for Unity, just converted for use in Godot. I tested the code and it seems to work, though the rotation speed may need adjusting based on the distance from the camera and the size of the game viewport.

How this code works is that it uses the camera's relative Up (Y-Axis) and Right (X-Axis) vectors as the rotation axes in the global_rotate function. Because it is rotating relative to the camera's rotation, you don't need to do any post/pre processing with the transforms at all to rotate the object relative to the camera view.

Hopefully this helps :smile:

Thank you very much, finally thanks to the code you provided me I got it to work. :)

here is the code:

var rot_x = 0
var rot_y = 0
const LOOKAROUND_SPEED = .01
#
func _input(event):
	if event is InputEventMouseMotion and event.button_mask & 1:
        # modify accumulated mouse rotation
		rot_x = event.relative.x * LOOKAROUND_SPEED
		rot_y = event.relative.y * LOOKAROUND_SPEED
		root_group.rotate(camera.transform.basis.y, rot_x) # first rotate in Y
		root_group.rotate(camera.transform.basis.x, rot_y) # then rotate in X
		root_group.transform = root_group.transform.orthonormalized()
		#if you scale your object you have to put the scale back
		#after orthonormalized() like this: 
		#root_group.transform = root_group.transform.scaled(scale)

just added this

root_group.transform = root_group.transform.orthonormalized()

you have to add it if you rotate bit by bit or the transform will be corrupted over time as the float data type, like every data type, has a limited accuracy. If you do it like this:

        rot_x += event.relative.x * LOOKAROUND_SPEED
        rot_y += event.relative.y * LOOKAROUND_SPEED
        root_group.transform.basis = Basis() # reset rotation
	root_group.rotate(camera.transform.basis.y, rot_x) # first rotate in Y
	root_group.rotate(camera.transform.basis.x, rot_y) # then rotate in X

you don't have to do .orthonormalized() but for some reason, the rotation is not working properly this way.

Thank you again, you saved me so much working time, I appreciate it.

3 years later