Using Quaternion to Perform 3D rotations

本文深入浅出地介绍了四元数的基本概念及其在3D游戏中用于旋转的重要作用。文章详细解释了如何利用四元数避免万向节锁问题,并提供了四元数乘法及矩阵生成的具体公式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

from:http://www.cprogramming.com/tutorial/3d/quaternions.html


Using Quaternion to Perform 3D rotations

By confuted

The title of this tutorial is short and sweet.  The tutorial itself will not be.  First, an introduction.  Quaternions are the things that scare all manner of mice and men.  They are the things that go bump in the night.  They are the reason your math teacher gave you an F.  They are all that you have come to fear, and more.  Quaternions are your worst nightmare.

Okay, not really.  They aren't actually that hard.  I just wanted to scare you.  Quaternions have become a popular tool in 3d game development - and for a good reason.  Once you understand them, quaternions are really pretty amazing.  Also, unlike the other tutorials, I'm going to more or less be assuming that youknow nothing about quaternion math in this tutorial.  Here are the basics of a quaternion:



A quaternion represents two things.  It has an x, y, and z component, which represents the axis about which a rotation will occur.  It also has a w component, which represents the amount of rotation which will occur about this axis.  In short, a vector, and a float.  With these four numbers, it is possible to build a matrix which will represent all the rotations perfectly, with no chance of gimbal lock.  (I actually managed to encounter gimbal lock with quaternions when I was first coding them, but it was because I did something incorrectly.  I'll cover that later).  So far, quaternions should seem a lot like the axis angle representation.  However, there are some large differences, which start....now.

A quaternion is technically four numbers, three of which have an imaginary component.  As many of you probably know from math class, i is defined as sqrt(-1).  Well, with quaternions, i = j = k = sqrt(-1).  The quaternion itself is defined as q = w + xi + yj + zk.  w, x, y, and z are all real numbers.  The imaginary components are important if you ever have a math class with quaternions, but they aren't particularly important in the programming.  Here's why: we'll be storing a quaternion in a class with four member variables: float w, x, y, z;.  We'll be ignoring ij, and k, because we never liked them anyway.  Okay, so we're actually just ignoring them because we don't need them.  We'll define our quaternions (w, x, y, z).

You may have guessed by now that w is the amount of rotation about the axis defined by <x, y, z>.  (Warning: the math is going to start getting pretty heavy.  I'll explain the quaternion specific stuff, though).  Much like unit vectors are necessary for much of what is done in a 3d engine, with lighting, back-face culling, and the like, unit quaternions are needed to perform the operations we'll be doing below.  Luckily, normalizing a quaternion isn't much harder than normalizing a vector.  The magnitude of a quaternion is given by the formula magnitude = sqrt(w2 + x2 + y2 + z2).  For the unit quaternions, the magnitude is one.  Which means that, already, an optimization is in order.  Floating-point numbers aren't perfect.  Eventually, you'll lose accuracy with them, and you may want to check to see if you need to re-normalize your unit quaternion, to prevent math errors.  This can be done by checking the magnitude, which will need to be one... but if you're checking to see if it's one, there is no need for the sqrt() at all (sqrt(1) = 1).  So, if (w2 + x2 + y2 + z2) is more than a certain tolerance away from 1, you'll know that your quaternion needs to be normalized, and you will have saved taking a square root in the cases when it is within tolerance.  Every few clock cycles count.  But if you ever need to actually normalize a quaternion, here's how it would be done:

magnitude = sqrt(w2 + x2 + y2 + z2)
w = w / magnitude
x = x /  magnitude
y = y / magnitude
z = z / magnitude


(Yes, I'm familiar with how to do that in C++, including the /= operator.  I'm trying to keep this easy to read mathematically.)  Performing the above operations will ensure that the quaternion is a unit quaternion.  However, they are (somewhat) expensive in CPU time and should not be called unless needed - which they usually aren't.  There are many different possible unit quaternions - they actually describe a hyper-sphere, a four dimensional sphere.  Don't try to visualize it; your head will explode.  But because the end points for unit quaternions all lay on a hyper-sphere, multiplying one unit quaternion by another unit quaternion will result in a third unit quaternion.  I guess now it's time for me to describe quaternion multiplication.

One of the most important operations with a quaternion is multiplication.  If you are using C++ and coding your own quaternion class, I would highly suggest overloading the * operator to perform multiplications between quaternions.  Here is how the multiplication itself is performed: (sorry about the HTML subscripts, I know they suck)

Let Q1 and Q2 be two quaternions, which are defined, respectively, as (w1, x1, y1, z1) and (w2, x2, y2, z2).
(Q1 * Q2).w = (w1w2 - x1x2 - y1y2 - z1z2)
(Q1 * Q2).x = (w1x2 + x1w2 + y1z2 - z1y2)
(Q1 * Q2).y = (w1y2 - x1z2 + y1w2 + z1x2)
(Q1 * Q2).z = (w1z2 + x1y2 - y1x2 + z1w2


It is very, very, very important for you to note that Q1 * Q2 is NOT equal to Q2 * Q1.  Quaternion multiplication is not commutative.  If you don't remember this, it will give you trouble later, and it won't be easy to spot the cause.  So do yourself a favor and remember it.  I didn't the first time I read it.  I'm speaking from experience here.

What does the quaternion multiplication mean?  To tell you the truth, this is where quaternions start to become beautiful.  Until now, they've been a bunch of math which wasn't difficult, but might have been annoying.  Now, quaternions will become useful.  Remember that a quaternion stores an axis and the amount of rotation about the axis.  So, with that, after I give you the matrix for rotations with quaternions, you would be able to rotate an object over some arbitrarily defined axis by some arbitrary amount, without fear of gimbal lock.  However, changing the rotation would be a trickier manner.  To change the rotation represented by a quaternion, a few steps are necessary.  First, you must generate a temporary quaternion, which will simply represent how you're changing the rotation.  If you're changing the current rotation by rotating backwards over the X-axis a little bit, this temporary quaternion will represent that.  By multiplying the two quaternions (the temporary and permanent quaternions) together, we will generate a new permanent quaternion, which has been changed by the rotation described in the temporary quaternion.  At this point, it's time for a good healthy dose of pseudo-code, before you get so confused we have to bring in the EMTs to resuscitate you.

/*to keep with the conventions I've followed in some posts on cprogramming.com, I
will call the temporary quaternion described above local_rotation.  I'll be calling the
permanent quaternion described above total.*/

// generate local_rotation (details later)
total = local_rotation * total  //multiplication order matters on this line

Before I try to explain that any more, I need to teach you how to generate local_rotation.  You'll need to have the axis and angle prepared, and this will convert them to a quaternion.  Here's the formula for generating the local_rotation quaternion.

//axis is a unit vector
local_rotation.w  = cosf( fAngle/2)
local_rotation.x = axis.x * sinf( fAngle/2 )
local_rotation.y = axis.y * sinf( fAngle/2 )
local_rotation.z = axis.z * sinf( fAngle/2 )


Then, just multiply local_rotation by total as shown above.  Since you'll be multiplying two unit quaternions together, the result will be a unit quaternion.  You won't need to normalize it.  At this point, I feel the need to once again point out that quaternion multiplication is not commutative, and the order matters.

Hang in there; we're almost done.  All that is left for this tutorial is generating the matrix from the quaternion to rotate our points. 

 

w2+x2-y2-z2

2xy-2wz

2xz+2wy

0

2xy+2wz

w2-x2+y2-z2

2yz+2wx

0

2xz-2wy

2yz-2wx

w2-x2-y2+z2

0

0

0

0

1


And, since we're only dealing with unit quaternions, that matrix can be optimized a bit down to this:

1-2y2-2z2

2xy-2wz

2xz+2wy

0

2xy+2wz

1-2x2-2z2

2yz+2wx

0

2xz-2wy

2yz-2wx

1-2x2-2y2

0

0

0

0

1

 

Amazing.  Well, maybe not amazing, but pretty cool.  You'll regenerate these matrices each frame.  Most importantly, you won't get gimbal lock if you follow my directions.  One thing that I forgot to mention earlier - you'll need to initialize your total quaternion to the value (1,0,0,0).  This represents the "initial" state of your object - no rotation.


Interpolating between two orientations using quaternions is also the smoothest way to interpolate angles.  It's done via a method known as SLERP, or Spherical Linear intERPolation.  I haven't encountered a need for this yet, so I haven't researched it, but perhaps someday I'll research it and write a tutorial about it to add to this series.  If anyone needs the information, feel free to contact me, and clue me in that someone actually read this and wants more.  That's all for now, have fun coding Quake.  Or Doom.  Make sure to give me a copy of it when you're done.

资源下载链接为: https://pan.quark.cn/s/9648a1f24758 这个HTML文件是一个专门设计的网页,适合在告白或纪念日这样的特殊时刻送给女朋友,给她带来惊喜。它通过HTML技术,将普通文字转化为富有情感和创意的表达方式,让数字媒体也能传递深情。HTML(HyperText Markup Language)是构建网页的基础语言,通过标签描述网页结构和内容,让浏览器正确展示页面。在这个特效网页中,开发者可能使用了HTML5的新特性,比如音频、视频、Canvas画布或WebGL图形,来提升视觉效果和交互体验。 原本这个文件可能是基于ASP.NET技术构建的,其扩展名是“.aspx”。ASP.NET是微软开发的一个服务器端Web应用程序框架,支持多种编程语言(如C#或VB.NET)来编写动态网页。但为了在本地直接运行,不依赖服务器,开发者将其转换为纯静态的HTML格式,只需浏览器即可打开查看。 在使用这个HTML特效页时,建议使用Internet Explorer(IE)浏览器,因为一些老的或特定的网页特效可能只在IE上表现正常,尤其是那些依赖ActiveX控件或IE特有功能的页面。不过,由于IE逐渐被淘汰,现代网页可能不再对其进行优化,因此在其他现代浏览器上运行可能会出现问题。 压缩包内的文件“yangyisen0713-7561403-biaobai(html版本)_1598430618”是经过压缩的HTML文件,可能包含图片、CSS样式表和JavaScript脚本等资源。用户需要先解压,然后在浏览器中打开HTML文件,就能看到预设的告白或纪念日特效。 这个项目展示了HTML作为动态和互动内容载体的强大能力,也提醒我们,尽管技术在进步,但有时复古的方式(如使用IE浏览器)仍能唤起怀旧之情。在准备类似的个性化礼物时,掌握基本的HTML和网页制作技巧非常
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值