+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 by (162 points)

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.

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to webmaster@godotengine.org with your username.