Assigning GO.transform.rotation...

When I try and do this:

GO.transform.rotation = Quaternion.AngleAxis(desiredAngle, Vector3.up);

I get an object to rotate as expected, to an exact angle of rotation, on the expected axis.

However, doing this:

GO.transform.rotation = Quaternion.AngleAxis(desiredAngle, GO.transform.up);

I get unexpected results, where the object wildly rotates out of control so fast its hard to tell what is going on, like using transform.Rotate() to incorrectly try to do this, but I am directly setting the rotation, and since it works fine in the first line, I had expected this to just…work…

What gives? Why doesnt it act the same, only using the objects transform “up” rather than the worlds “up”? Perhaps transform.up doesn’t work like that? Maybe some Quaternion bug?

More, possibly unnecessary Info…

…The idea is to get the object to snap to an angle, set to “desiredAngle” on a certain axis. It works properly with Vector3.up, however, since the camera moves in the game, and this object needs to move around with the camera which is at funny angles, it can’t rotate around vector3.up, but rather it should be rotating around its local transform.up, which is what I had thought I would accomplish with the second line of code. Somebody please shed some light on this for me :slight_smile:

how you can recreate my problem:

  1. create blank project and scene.

  2. create a cube or plane primitive.

  3. make a script for that primitive which sets its transform just like I did

  4. try vector3.up first, and then make it so you change a float with keys or something

  5. plug that float into your keys or whatever input, and then hit those keys in-game

  6. now try it with transform.up and hit the keys or whatever

  7. witness strange things.

I suspect this is a “rotation leakage” problem. A quaternion is an angle-axis rotation coded in a mathematically convenient format: XYZ are the axis unit vector multiplied by sin(angle/2), and W is cos(angle/2). When the angle is near to 0 or 360, its sine becomes dangerously close to 0, what causes lack of precision in the XYZ components. When we repeatedly modify a quaternion, its axis information may be lost or severely distorted when passing near to these angles, and the object seems to be rotating around the wrong axes - what’s called “rotation leakage”.

You should use another up reference not tied to this object’s rotation. If its up axis is always equal to the camera’s up direction, use camera.transform.up; if there’s no other object to use as a reference, make this object a parent-child composite, and set the angle in the localEulerAngles instead - like this (parent script):

Hierarchy:

  ParentObject  <- empty game object 
    ActualObject <- your object

Get a reference to the inner object, and rotate it using its localEulerAngles:

  var actualObject: Transform;

  function Start(){ // get a reference to it at Start
    actualObject = transform.Find("ActualObject");
  }

  ...
  actualObject.localEulerAngles = Vector3(0, desiredAngle, 0);

You should move and tilt the parent object, and only use the child to set the angle relative to its initial forward direction.