Help understanding code related to Quaternions and rotations

Hi :slight_smile: - Been working with Unity for a while now, everything is sweet so far. The only thing that I’m kinda choking at at the moment is quaternions and rotations. I’ve been reading in UnityGems which is really a great site! - And I found this article, that had the following code below in it (in the coroutines section): (I translated it into C# cuz that’s what I’m comfortable with) - I couldn’t quite get it right and I’m the kind of person that must understand each each line of code.
I wrote questions about the stuff that I didn’t get, please have a look :slight_smile:

// rotates an object to a new angle smoothly over time.
IEnumerator RotateBy(Vector3 angle, float time)
{
     Quaternion currentRotation = transform.rotation;   // can I think of the transform.rotation as the direction of the object? or maybe its normal? :/
     Vector3 targetAngle = currentRotation.eulerAngles + angle;         // an angle is a vector?! how could that be?
     Quaternion targetRotation = Quaternion.Euler(targetAngle);         // can I think of a Quaternion as a rotation matrix?
     float t = 0;
     while(t < 1)	// I guess this would loop for one second if we didn't divide by time (below), 
     {                  // but since we did, for how long this will keep looping?

          transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, t);  // no problem here.
          t += Time.deltaTime / time;  // why divide by time?
          yield return null;		   // why? - from what I know this waites till the next frame, but why?
     } 
     transform.rotation = targetRotation;	   // why did we do that? - by the end of the loop we should have our rotation set, don't we?

So yea, as you can see I’m clearly not getting the Quaternions and rotations stuff and how they relate to vectors :confused:
So it would be nice if you could touch on the points briefly, it would be appreciated :slight_smile:
Note that I’m good with normal (basic) Linear Algebra, like Linear transformations and stuff…

And also, I found this cool video about all this stuff, which I believe is very helpful IF someone were to understand Quaternions and rotations a bit well. Any other videos/series/tutorials you know about of this kind? - Thanks everybody :slight_smile:

  1. The rotation is which way the object is facing.
  2. EulerAngles is a vector, yes. You need to use the x/y/z axes since this is 3D.
  3. A quaternion is a rotation stored with 4 dimensions instead of 3, which is useful for preventing gimbal lock.
  4. You answered that yourself.
  5. If you don’t use yield return null to wait a frame, then it wouldn’t animate, which would remove the entire point of having that function in the first place.
  6. The rotation won’t be quite set to the final rotation with the way the loop is set up, since t will be a little under 1.0. Personally I’d recommend swapping the order of lines 11 and 12; that way line 15 can be removed.

–Eric

Thanks for the answer, but:
12: I answered my self? o.O
13: you’re saying what will happen if I don’t use it, but my question was ‘why’, I mean why would it not animate? how could skipping a frame affect it so much like that?
15: yes, I just read that in lerping, objects won’t reach their ‘exact’ final position, but will get close so much, which is why we used the last line.
But how come swapping the lines affect the matter? o.O

Im not going to dive into the logic of the whole function and what its doing but will give you some comments to help … perhaps others can help further…

For 3D rotations there are 2 algorithms or representations in Unity

Euler Angles
Quaternions

Euler angles only have 3 components x,y,z rotations ( this is why they can be represented by a vector 3 storage ) . The Euler angle algorithm is flawed though as it creates gimbal lock http://en.wikipedia.org/wiki/Gimbal_lock It easy to set the properties of Euler angles as they are represented with common angles like 0-360 etc…

Quaternions have 4 components x,y,z,w and do not suffer from gimbal lock . All Euler angles are converted to Quaternions internally by Unity engine.
You cannot set Quaternion values using common representation of angles like you do with Euler angles.

A 3D Rotation has any direction you require from it , based on the 3D coordinate system used (Unity uses y up ) so the positive z direction is considered forward. Unity has these direction values built into the transform component , eg “transform.forward”, this would translate along the exact z-axis of the GameObject for whatever rotation it has.

Unity engine also has helper methods to convert coordinate systems from object to object eg camera to object : http://docs.unity3d.com/Documentation/ScriptReference/Transform.TransformDirection.html

hth

Yes, your comment on line 8.

If you don’t wait any frames, then the entire function would complete in one frame, so it would be useless.

That’s incorrect. If you pass in 1.0 for the third parameter in Lerp, then the value returned is 100% of the second parameter. The problem with the code as-is is that t will be, say, .99723 (or something) during the last run of the loop, then 1.0293 (or something) afterward, so the loop won’t run again because t is greater than 1, leaving the rotation not quite at the final position since the Lerp was computed when t was .99723. If you swap lines 11 and 12 like I said, then t will be 1.0293 (or something) when the last Lerp is computed, which will make the final rotation 100% correct (since t is clamped to 1.0 in the Lerp). Thus you can get rid of line 15.

–Eric

In case Eric’s explanation wasn’t clear: you always want your “t” value in Slerp to be between 0 and 1, that’s why you divide by time. The while loop (line 8 ) is going to last “time” seconds. As you said, it would last for one second if you didn’t divide by anything. If you pass in say, 12 for “time”, it will last 12 times as long; in other words, 12 seconds. This technique is used pretty often with Lerp and Slerp.

About yielding from coroutines: If you don’t yield from a coroutine, it just doesn’t end until the whole function completes, which makes it pointless to use a coroutine. The point of a coroutine is that you can return multiple times from within the same function to have it work across multiple frames. In this example if you passed in 12 for time and didn’t have that yield in there, your game would just freeze completely for 12 seconds and then start again with the object completely rotated. The only way to actually “see” what’s happening is by letting the Update finish and rendering a frame. You pretty much never want to do any sort of waiting on time if you’re not yielding, as that causes your game to freeze until the wait is complete.

The easiest way to grasp quaternions is to think of them as the computer-friendly way of storing a rotation. Humans are much better at understanding Euler Angles (rotate 20 degrees this way, then 50 degrees that way), but this isn’t a good way to store rotations for a graphics engine. Quaternions are pretty much incomprehensible to normal humans (math majors aren’t normal humans) but they make rotation calculations much smoother for the computer. Most of the time if you’re writing code to deal with rotations you will be converting back and forth between Euler and Quaternion since that’s the only way to make human-understandable rotations; you won’t usually mess with the values of a quaternion directly.

Thanks a BUNCH guys, really! :slight_smile: - But one thing remaining though Eric5h5:

You said t would get something like, 1.0293 in the last run, but I don’t see where the clamp is happening, where is the clamping? :confused:
I think I could also do something like this (right?)

t += Time.deltaTime / time;
if (t > 1) t = 1; 
transform.rotation = Quaternion.Slerp(currentRotation, targetRotation, t);
yield return null;

Lerp clamps t between 0 and 1. See the docs.

You could, but there’s no point, so don’t.

–Eric