+5 votes

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.

in Engine

## 3 Answers

0 votes

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

by (162 points)

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.lookingat()` and use the Z axis, which is alway [x,0,z]. Then, thank to `Vector2(1,0).angleto(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.

Have you had time since April to elaborate? :-D 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.

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?

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).angleto(myvector * Vector3(1,0,1))`

Thanks for replying, this will be very helpful!

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.

+1 vote

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

by (482 points)
edited by
0 votes

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.

by (29 points)

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