Quaternion.RotateTowards

I am trying to make object rotate to position at constant speed with

transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion_2, speed * Time.fixedDeltaTime);

If I initialize Quaternion_2 following way everything the works fine:
Quaternion_2 = someobject.transform.rotation

If I initialize it manually with some random numbers from 0 to 1 it starts rotation at normal speed and slows down at the end:
Quaternion Quaternion_2 = new Quaternion (0.5, 0.5, 0.5, 0.5);

“If I do some really weird nonsensical thing, some really weird stuff happens. Why?”

It sounds like you already know the correct answer to this - what’s your actual issue you’re trying to solve? Plugging random numbers into a quaternion is going to come up with some weird results. That’s expected.

Yeah… I did not know that all this 4 variables are interconnected. Something like (0.5, 0.5, 0.5, 0.5) is not a valid Quanternion.

When creating a quat, you may want to create it using something like:

var rot = Quaternion.Euler(x,y,z);

…

A little breakdown/background

The 4 values in the quat have very specific meaning that relate to 3 complex numbers and 1 real number. When normalized these values can be used to represent an orientation in 3-space.

The mathematical reason that this works is fairly complex and relies on some pretty advanced knowledge about complex number theory. It’s literally called “complex number theory”, for example a complex number with 2 dimensions can be written as:
a + bi

Where i*i = -1 (i = sqrt(-1))

What you can do then is actually graph this in a 2d grid with a as the x axis, and b as the y axis.

You can represent this as a vector in shape:
<a,b>

And with this you can actually represent a simple rotation:

Well with a quat what is going on is we extend the concept to 4 dimensions:
a + bi + cj + dk
(note a is the real component since it has no i,j,k multiplied by it)

Where i,j,k are all complex. But not necessarily just that ii = -1 way. Instead it’s that:
i
i = jj = kk = ijk = -1

And if this is normalized this can be used to represent a hypersphere whose projection into 3-space (which is a sphere) will be rotated to some orientation based on a,b,c,d.

And this can all be represented as a vector:
<a,b,c,d>

Or in unity the vector values are reorganized and renamed to:
<x,y,z,w>
where w is the real component (think like how you could do rgba, or argb, for color… order doesn’t actually matter as long as you’re aware which order was chosen).

If you want an in depth… this guy does a fantastic job, better than I ever could, especially since he has visuals to go with it:

With all that said… you don’t need to know this

You don’t need care about what the x,y,z,w values are in a quat, and you don’t have to modify them ever.

You just use them for rotational arithmetic.

When you want to declare a rotation you can just use euler which is way more human readable. It’s just that euler arithmetic will result in gotchas like gimbal lock. But as long as you don’t do euler arithmetic, you’re safe.

So you can do something like this:

transform.rotation *= Quaternion.Euler(0f, 90f, 0f);

(note the order of operations matters in quats… this is different if we put the transform’s rotation after the Quat.Euler. It changes what rotation is relative to the other. So basically if it’s 90 around the global y-axis, or 90 around the transform’s up axis)

To perform a rotation around the y-axis of 90 degrees.

Where as if you did:

transform.eulerAngles += new Vector3(0f, 90f, 0f);

Well this MIGHT work… depends on the orientation of ‘transform’. If the orientation was <0,0,0> it’d work just fine. But if it was rotated around say its x-axis you might get some odd behaviour where it doesn’t seem to rotate at all.

This += vec is what I mean by “euler arithmetic”. You perform an arithmetic operation using the euler representation.

Don’t do that. Use the quat representation for the arithmetic.

Use the euler for reading/writing.

And you can just use the Euler function, and eulerAngles property, to convert.

1 Like

Well, that’s not strictly true. First of all it’s a Quaternion (Quat == Four), so watch your spelling. Second plugging in random numbers into a quaternion is a valid quaternion, but not a valid unit quaternion. Quaternions, just like complex numbers, in essence represent a rotation and a scaling. Only unit quaternions do not scale and are pure rotations as they have a magnitude of 1.0.

Your example quaternion is actually a valid unit quaternion as it’s a 120° rotation around the diagonal axis (1,1,1). The “w” value is the cosine of half the angle that the quaternion represents. Since you set w to 0.5 we get 60° when using asin. Since that’s just half the angle the total angle is 120°. The other 3 components represent the axis we rotate around. It’s a normalized direction vector that is multiplied by the sine of 60° (again, half the angle). The overall magnitude of that quaternion is exactly 1. The corresponding euler angles for this quaternion would be (0, 90, 90). Just think about a cube that is rotated around it’s diagonal axis. 120° is exactly 1/3 of 360° Since rotating a cube around a corner has a 3 step symetry, the cube will still look like a cube because in terms of euler angles it got rotated twice by 90° around two major axes.

Quaternions could actually be used instead of vectors to represent directions and positions and those could be added just like vectors. Actually when you rotate a point by a quaternion, that’s actually what you have to do anyways. Though for most applications, vectors are easier to use when it comes to positions or directions. In Unity the Quaternion class exclusively represent unit quaternions for rotations / orientations.

Note even a quaternion represents a single axis and an angle around that axis, it’s not always that easy to see which axis this actually is. The amazing thing to realise is that you can get from any orientation to any other orientation by rotating around a single axis by a certain amount of degrees. This always works which is the reason why quaternions are so much better at interpolating and animating rotations. Though for animations quaternions also have some limitations as they can not represent rotations greater than 360°. So you can not have a rotation that spins an object 3 times around the same axis since subtracting or adding 360° from / to an angle does not change the resulting orientation.

Anyways, I’m with lordofduct that it’s not really necessary to understand quaternions in and out. It’s enough to know how to use them. It helps when you keep in mind what they represent on an abstract level (a single rotation axis and a certain amount to rotate around that axis)

1 Like

Guys thank you a lot! That really helped me to understand quaternions at some point. Few days ago I even hired a math professor to get some math lessons… Now I am not sure that I need to go quaternions so deep, so I asked him to go some linear algebra instead :slight_smile: May be I will push it and go for quaternions at some point.

Still I don’t get why this rotation is not carried out like a single move
Quaternion Quaternion_2 = new Quaternion (0.5, 0.5, 0.5, 0.5);
it make some rotation at constant fast speed and then slows down and makes small and very slow angular turning
this never happen if I set Quaternion_2 with Quaternion.Euler(x,y,z);

Well, specifically the quaternion you’ve shown new Quaternion (0.5, 0.5, 0.5, 0.5); does work for me just fine when I use RotateTowards. As I explained above this specific example is a valid unit quaternion and is equal to Quaternion.Euler(0, 90, 90);. This literalls returns a quaternion that is (0.5, 0.5, 0.5, 0.5). So I’m not sure what you mean when you say it doesn’t work. As we said, using just random numbers would not work, as the resulting quaternion would not be a normalized unit quaternion.

If you’re looking for a random rotation, Unity already has methods for this like Random.rotation. As you can read in the documentation it actually constructs a random quaternion by randomizing all elements to values between -1 and 1 and then it normalizes the result. There’s also Random.rotationUniform which as the name suggests has a better random distribution.

As I said above, I tried your example quaternion as a RotateTowards target and it rotates perfectly linearly towards that orientation, no matter the start orientation. Are you sure that you don’t have other code that is messing around with the orientation of the object? Also you’re using transform.rotation. If the object is a child of another object, when the parent rotates it would also affect the children. You only showed us that single line of code.

Btw: It makes no sense to use Time.fixedDeltaTime anywhere. Time.deltaTime would automatically return the correct delta time value depending on where it’s used. Inside FixedUpdate (the only place where fixedDeltaTime has any meaning) Time.deltaTime will return the value of fixedDeltaTime.

Good to know, thank you!

I tried this code in new empty project, it does very slow angular turning in end of trajectory.:
void FixedUpdate()
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, new Quaternion(0.5f, 0.5f, 0, 0), 1);
}

While Quaternion(0.5f, 0.5f, 0.5f, 0.5f) works just fine as you said.

Well, it seems you have read all our answers and replies but you haven’t understood a single bit about quaternions ^^. In order to have a valid pure rotation quaternion it needs to be normalized. This new Quaternion(0.5f, 0.5f, 0, 0) is not normalized. Use the pythagorean theorem and you find out that sqrt(0.5² + 0.5² + 0² + 0²) is equal to sqrt(0.25 + 0.25 + 0 + 0) which is just sqrt(0.5). So your quaternion does not have a length of 1.0 as it should, but just a length of about 0.707. As I said above the example quaternion you have posted originally, specifically new Quaternion(0.5, 0.5, 0.5, 0.5) is normalized and therefore a pure rotation.

sqrt(0.5² + 0.5² + 0.5² + 0.5²) == sqrt(0.25 + 0.25 + 0.25 + 0.25) == sqrt(1.0) == 1.0.

I also linked the documentation to the Random.rotation which even explains that it creates the random orientation by randomizing all 4 elements and then normalizing the result. However you didn’t normalize your quaternion. When you use Quaternion.Normalize(new Quaternion(0.5f, 0.5f, 0, 0)) you would actually get a quaternion that looks something like 0.7071068, 0.7071068, 0, 0. This is a 180° rotation around the diagonal of the x-y-plane and is a valid pure rotation quaternion.

The math for rotation only works out the way we want when the quaternions we use are normalized, always.

1 Like

Thats explains it… Thank you again for your help and your time!

TLDR: don’t set the xyzw of a quaternion directly unless you truly know how they work. If you want a random rotation, there’s Random.rotation.