I am a Game Developer and did not study Mathematics. So I only want to use Quaternions as a tool. And to be able to work with 3D rotation, it's necessary to use Quaternions (Or Matrixes, but let's stay at Quaternions here in this Question). I think it's important for many developers to use them. That's why I want to share my knowledge and hopefully fill the holes I have. Now....

So for example: My 3D Object is on Position (0,0,0) and my rotation I multiply is a rotation 180° to right, my endposition is something like (0,-50,0) . Inside that Quaternion there is a Axis - and a rotation around that axis. You turn your point around that axis Y Degrees.

\$\begingroup\$Say you have not 2, but n different orientations (attitudes, poses, etc). Then you can average them using weights, effectively generalizing slerp/lerp. You can also convert a quaternion to a rotor, which is equivalent to applying an angular velocity for a certain amount of time to a rigid body. Hence you can describe angular velocity integration with quaternions also. You can also estimate how dissimilar two orientations are (compute the length of the arc spanned by the two quaternions on the hypersphere).\$\endgroup\$
– teodronNov 21 '16 at 16:15

\$\begingroup\$And yes, at a first glance, your rationale is correct (your understanding of quaternions is quite good for a non-technical person). This is inappropriate for a comment, but congrats! Not even the technically gifted know all quaternion uses, although they use them just as software engineering tools for a purpose.\$\endgroup\$
– teodronNov 21 '16 at 16:17

4

\$\begingroup\$"And to be able to work with 3D rotation, it's necessary to use Quaternions" I can't stress enough how false this sentence is. You can use Euler or Tait-Bryan angles for game developement, the only problem is the gimbal lock. If you want to be a game developer, you'll need math at one point, learn it.\$\endgroup\$
– BálintNov 22 '16 at 6:30

\$\begingroup\$I appreciate what you're trying to do with the question, but the answers should be in an answer, not the question. Make a "summary" answer if you think it's worth collating them.\$\endgroup\$
– BasicNov 23 '16 at 1:49

2 Answers
2

Multiplication

At least in terms of Unity's implementation of Quaternions, the multiplication order described in the question is not correct. This is important because 3D rotation is not commutative.

So, if I want to rotate an object by rotationChange starting from its currentOrientation I'd write it like this:

Quaternion newOrientation = rotationChange * currentOrientation;

(ie. Transformations stack up to the left - same as Unity's matrix convention. The rightmost rotation is applied first / at the "most local" end)

And if I wanted to transform a direction or offset vector by a rotation, I'd write it like this:

Vector3 rotatedOffsetVector = rotationChange * currentOffsetVector;

(Unity will generate a compile error if you do the opposite)

Blending

For most cases you can get away with Lerping rotations. That's because the angle used "under the hood" in a quaternion is half the angle of rotation, making it substantially closer to the linear approximation of Lerp than something like a Matrix (which in general will not Lerp well!). Check out around 40 minutes into this video for more explanation.

The one case when you really need Slerp is when you need consistent speed over time, like interpolating between keyframes on an animation timeline. For cases where you just care that an output is intermediate between two inputs (like blending layers of an animation) then usually Lerp serves quite well.

What Else?

The dot product of two unit quaternions gives the cosine of the angle between them, so you can use the dot product as a measure of similarity if you need to compare rotations. This is a little obscure though, so for more legible code I'd often use Quaternion.Angle(a, b) instead, which more clearly expresses that we're comparing angles, in familiar units (degrees).

rotates the local z+ axis to point exactly along the forward vector argument

rotates the local y+ axis to point as close as possible to the up vector argument, if provided, or to (0, 1, 0) if omitted

The reason the "up" only gets "as close as possible" is that the system is overdetermined. Facing z+ to forward uses up two degrees of freedom (ie. yaw and pitch) so we have only one degree of freedom remaining (roll).

I find quite often I want something with the opposite exactness properties: I want local y+ to point exactly along up, and local z+ to get as close as possible to forward with the remaining freedom.

This comes up for example when trying to form a camera-relative coordinate frame for movement input: I want my local up direction to stay perpendicular to the floor or inclined surface normal, so my input doesn't try to tunnel the character into the terrain or levitate them off of it.

You might also get this if you want the turret housing of a tank to face a target, without peeling up off of the tank's body when aiming up/down.

We can build our own convenience function to do this, using LookRotation for the heavy lifting:

Then we rotate the new z+ to our up direction (so the net result is local y+ points directly along exactUp), and the new y+ as close as possible to the negated forward direction (so the net result is local z+ points as close as possible along approximateForward)

Another handy convenience method is Quaternion.RotateTowards, which I often use like so:

This lets us close in on targetRotation at a consistent, controllable speed regardless of framerate - important for rotations that affect the outcome/fairness of gameplay mechanics (like turning a character's movement, or having a turret track-in on the player). Naively Lerping/Slerping in this situation can easily lead to cases where the movement gets snappier at high framerates, impacting game balance. (That's not to say these methods are wrong - there's ways to use them correctly without changing fairness, it just requires care. RotateTowards gives a convenient shortcut that takes care of this for us)

\$\begingroup\$Tip: Add &t=40m to the end of the video URL so it'll hop straight there (optionally e.g. 40m5s). Quaternion dot products come in handy when dealing with spherical gameworlds too - or more broadly when orientating chunks of rotating spheres.\$\endgroup\$
– Luke BriggsNov 22 '16 at 2:41

\$\begingroup\$@Luke Briggs: The spherical game world point sounds like it would be worth elaborating on in its own answer (especially with diagrams) if you'd be up for it. :)\$\endgroup\$
– DMGregory♦Nov 22 '16 at 2:43

\$\begingroup\$Great idea - it's 3am here (so I think it would come out a little gibberish!) but I'd be happy to pull something together tomorrow (If I remember!)\$\endgroup\$
– Luke BriggsNov 22 '16 at 2:45

1

\$\begingroup\$Edit: I've got a little carried away thinking about an answer so challenge accepted! I'll at least mark it as a rough cut so people can be aware of the late night burn that went into it :P\$\endgroup\$
– Luke BriggsNov 22 '16 at 2:52

\$\begingroup\$There we go! I attempted to cover it in a graphical overview sense on the basis that your answer already covers the underlying functions really well. Time for some sleep I think!\$\endgroup\$
– Luke BriggsNov 22 '16 at 3:48

Where's the dot product used?

In Unity, one of the most common users of the dot product is whenever you check if two quaternions are equal via == or !=. Unity computes the dot product to check similarity rather than directly comparing the internal x,y,z,w values. It's worth keeping this one in mind as it makes the call more expensive than you might expect it to be.

We also use it in an interesting use case too..

Fun with quaternion dot products - Spherical worlds and orbitals

Simulations of entire planets and even entire solar systems are getting increasingly common. In order to pull this off in realtime, we need the quaternion dot product too. Lots of them. The quaternion dot product is very underused but it certainly has its uses - Let's take a look!

Firstly, we have a whole series of rotations to consider:

(Optionally) The star around the galactic centre

The planet around the star

The tilt of the planet

The spin of the planet

The position of nearby grid cells (rotated about the planets core)*

Multiple orbital planes

Combine them all together and you end up with a lot of complexity (and a lot of huge numbers!). When the viewer is standing on the surface of the planet, we don't want them to be hurtling at some crazy speed through our gameworld space. We'd actually rather they were stationary and somewhere near the origin - move the universe around the player instead.

Importantly, in order for us to be able to get the planet's spin and tilt correct in this scenario, we need to axis lock the pole so it can only swing up/down on the image above (i.e. swinging "up" as the player travels north). That's where a quaternion dot product comes in. If we didn't use a dot product here and instead just multiplied the tilt too, this would happen:

Notice how the poles of our orbiting 'planets' are always tilting towards the star. This isn't what happens in reality - the tilt is in a fixed direction.

Without going too far off topic, here's a quick summary:

On a sphere, an orientation also neatly describes a surface position.

We've got lots of rotations to combine together.

Describe everything as rotation; the position of the viewer, too. This helps boost performance as ultimately we end up doing less operations.

The angle between rotations (our dot product) then helps measure longitude and works particularly well at dealing with tilts.

By obtaining only the angle, we drop some of that unwanted rotation. At the same time we also ended up with a longitude measurement which is useful for navigation as well as the local climate.

* Planets are constructed from lots of grid cells. Only the nearby ones actually get displayed.

\$\begingroup\$This does a great job setting the scene and motivating the problem, but I'm still a bit fuzzy on how the math of the quaternion dot product (ie. the scalar product dot(a, b) = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w as opposed to quaternion composition which we'd use to chain-together rotations) would help us solve this problem. I'd gladly upvote if you're able to elaborate on this a little later (I don't mean to keep you from your slerp...I mean sleep!)\$\endgroup\$
– DMGregory♦Nov 22 '16 at 3:55

\$\begingroup\$@DmGregory the short answer is tilt is the odd one out; everything composes nicely except for that one (the planet would appear to wobble around its star otherwise). I'll (hopefully!) add some more context tomorrow!\$\endgroup\$
– Luke BriggsNov 22 '16 at 4:05

\$\begingroup\$Sorry if I'm being a bit dense, but after re-reading several times I still don't know how I'd use the dot product in a formula to achieve the transformation you're describing. Would you be able to add a little pseudocode laying out the operations you perform explicitly?\$\endgroup\$
– DMGregory♦Nov 22 '16 at 16:07

\$\begingroup\$@DMGregory I'm not familiar with the quaternions but if this is rotations on a sphere, then this isn't rotation compositions. This is using spherical geometry with vectors to compute the normal vector for a "line" on the surface of a sphere AKA any circumference. Once again, the answer makes little sense nor does this question, but I believe they are using spherical geometry.\$\endgroup\$
– The Great DuckNov 23 '16 at 5:27