What is even going on with 3D rotation

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By thirite
:warning: Old Version Published before Godot 3 was released.

Rotating a 3D spatial on the Y-axis results in a completely incomprehensible result.

When you rotate a spatial on the Y axis greater than or equal to 1/2 Pi, suddenly the X-Axis and Z-Axis decide to rotate one Pi and then the rotation of the Y-axis continues in the opposite direction.

This doesn’t happen when rotating the X or Z axis via rotate_*()

Why does it do this? Is this some kind of euler gimbal-lock work around? Because I can’t query which direction my character is facing due to the Y-axis rotation being the sum of all the axes.

:bust_in_silhouette: Reply From: thirite

So I figured it out, I guess. Relying on get_rotation().y is a bad idea. Will elaborate if I get the time.

I work with Y axis in my FPS game. But it doesn’t matter for me because my object rotates only its Y axis. I use Transform.looking_at() and use the Z axis, which is alway [x,0,z]. Then, thank to Vector2(1,0).angle_to(Vector2(x,z)), I get my angle, even if the get_rotate() goes crazy like you saw by yourself. I wish there was a better way to do it, but at least it works.

Gokudomatic2 | 2016-04-25 07:29

Have you had time since April to elaborate? :smiley: I would like to know as well what you found, as I struggle to understand the concept. I just need to know the rotation around the Y axis.

mydoghasworms | 2017-01-04 14:44

Hello, I would also be interested in an elaboration if possible. I need to rotate a camera on x and y axis to match a rotation, but stay upright. Were you able to correct the strange Vector3 rotation you were getting?

yepbear | 2017-01-07 19:23

Sorry for the late reply. I did work on all this stuff since then. And alas I didn’t found any better solution.

To rotate a camera to face a point while still having Y up, Transform.looking_at(target,Vector3(0,1,0)) works very well.

Edit:
In fact, I just checked my code and I found another way to get Y angle, which might be a little bit faster:
var angle=(v1 * Vector3(1,0,1)).angle_to(v2 * Vector3(1,0,1))

If you cache Vector3(1,0,1) in a constant, it should be faster than creating 2d vectors while calling getters from 3d vectors in a script. Alas I couldn’t measure it.

And if you don’t want to compare a vector to another but just want to know the angle relative to the vector of reference (which is always at 0°. I usually use the Z axis), you can cache this vector too. For instance, if Z is the reference vector, you can write:
var angle=Vector3(0,0,1).angle_to(my_vector * Vector3(1,0,1))

Gokudomatic2 | 2017-01-07 19:41

Thanks for replying, this will be very helpful!

yepbear | 2017-01-07 21:10

You’re welcome. But I already noticed some difference with the new way. Looks like the angle is always positive, where the angle_to of the 2d vector can be negative. Or something like that, because my code with the new version turns always to the same direction.

Gokudomatic2 | 2017-01-07 21:20

:bust_in_silhouette: Reply From: eaglecat

because there are many different Vector3 representation of a single rotation.

for example, in Godot, rotation (270,90,0) and (0,90,270) look the same direction

:bust_in_silhouette: Reply From: yepbear

I have been struggling with this issue for a while and have wrote a function that has made things easier for me. It is simple and might be specific to my needs but maybe it will help. I only just wrote it but it seems to work.

This fixes a rotation vector if it has been flipped due its y being greater than 1/2 pi (90 degrees). It allows y to be between 180 and -180. To use it, pass it a rotation vector and it will return a fixed one.

func fix_rot(vecToFix):
	var newX = vecToFix.x
	var newY = vecToFix.y
	var newZ = vecToFix.z
	if(abs(newZ) > 1):
		newX *= -1
		newY *= -1
		newZ *= -1
		if(newX > 0):
			newX -= PI
		else:
			newX += PI
		if(newY > 0):
			newY -= PI
		else:
			newY += PI
		if(newZ > 0):
			newZ -= PI
		else:
			newZ += PI
	return Vector3(newX, newY, newZ)

Again, this might only be helpful in my particular case but hopefully it helps someone. I am using it for a spatial that can rotate freely along y but only 90/-90 on x.

You can do quaternion rotation (with Quat), will save you a lot of if.

eons | 2017-01-07 22:09