官术网_书友最值得收藏!

Multiplying quaternions

Two quaternions can be concatenated by multiplying them together. Like with matrices, the operation is carried out from right to left; the right quaternion's rotation is applied first and then the left quaternion's.

Assume you have two quaternions, q and p. They are subscripted with 0, 1, 2, and 3, which correspond to the X, Y, Z, and W components, respectively. These quaternions can be expressed in ijk notation, as shown:

To multiply these two quaternions together, distribute the components of p to the components of q. Distributing the real component is simple. Distributing p3 to q would look like this:

Distributing the imaginary components looks very similar. The real and imaginary parts are combined separately; the order of imaginary components matters. For example, distributing poi to q would look like this:

Fully distributing p to q looks like this:

Start simplifying for the case when imaginary numbers are squared. The square root of an imaginary number is -1. If you raise -1 to the power of -1, the result is also -1. This means that any instance of i2, j2, or k2 can be replaced by -1, like so:

What about the rest of the imaginary numbers? When talking about quaternions,

ijk= -1, the squared value of each of these components is also -1, which means that

i2= j2= k2=ijk. This property of quaternions can be used to simplify the rest of the equation.

Take jk, for example. Start with ijk= -1 and try to isolate jk to one side of the equation.

To do this, multiply both sides by i, leaving you with i(ijk)= -i. Distribute i, which will leave you with i2 jk= -i. You already know that the value of i2 is -1. Substitute it to get

-jk= -i. Multiply both sides by -1 and you have found the value of jk— jk=i.

The values for ki and ij can be found in a similar way; they are ki=j and k=ij. You can now substitute any instances of ki with j, ij with k, and jk with i. Substituting these values leaves you with the following:

The remaining imaginary numbers are ik, ji, and kj. Like the cross product, the order matters: ik= -ki. From this, you can assume that ik= -j, ji= -k, and kj= -1. Substituting these values leaves you with the following:

Numbers with different imaginary components cannot be added together. Re-arrange the preceding formula so that like imaginary components are next to each other. This results in the final equation for quaternion multiplication:

To implement this formula in code, change from this subscripted ijk notation back to vector notation with X, Y, Z, and W subscripts. Implement the quaternion multiplication function in quat.cpp and don't forget to add the function declaration to quat.h:

quat operator*(const quat& Q1, const quat& Q2) {

   return quat(

       Q2.x*Q1.w + Q2.y*Q1.z - Q2.z*Q1.y + Q2.w*Q1.x,

      -Q2.x*Q1.z + Q2.y*Q1.w + Q2.z*Q1.x + Q2.w*Q1.y,

       Q2.x*Q1.y - Q2.y*Q1.x + Q2.z*Q1.w + Q2.w*Q1.z,

      -Q2.x*Q1.x - Q2.y*Q1.y - Q2.z*Q1.z + Q2.w*Q1.w

   );

}

When looking at the preceding code, notice that the real part of the quaternion has one positive component, but the vector part has one negative component. Re-arrange the quaternion so that the negative numbers are always last. Write it down using vector notation:

qpx= px qw+ pw qx+ py qz- pz qy

qpy= py qw+ pw qy+ pz qx- px qz

qpz= pz qw+ pw qz+ px qy- py qx

qpw= pw qw- px qx- py qy- pz qz

There are two interesting parts in the preceding equation. If you look closely at the last two columns of the first three rows, the columns with the subtraction are the cross product. The first two columns are just scaling the vector parts of each quaternion by the scalar parts of the others.

If you look at the last row, the dot product is in there with the negative of the dot product. The last row is basically multiplying the real parts of both quaternions, then subtracting the dot product of their vector parts. This means that an alternate multiplication implementation could look like this:

quat operator*(const quat& Q1, const quat& Q2) {

  quat result;

  result.scalar = Q2.scalar * Q1.scalar -

  dot(Q2.vector, Q1.vector);

  result.vector = (Q1.vector * Q2.scalar) +

  (Q2.vector * Q1.scalar)+cross(Q2.vector, Q1.vector);

  return result;

}

The original implementation is a bit more performant since it doesn't need to invoke other functions. The sample code for this book will use the first implementation.

Next, you will learn how to transform vectors by quaternions.

主站蜘蛛池模板: 马山县| 云梦县| 宁津县| 辽阳市| 上饶县| 朝阳市| 郸城县| 张家口市| 肥东县| 武乡县| 清流县| 光泽县| 瑞安市| 松阳县| 淮北市| 东阳市| 金山区| 宝坻区| 宁强县| 宝丰县| 平和县| 运城市| 西安市| 洪湖市| 谢通门县| 江安县| 延吉市| 泊头市| 正安县| 通辽市| 甘泉县| 鲁山县| 柞水县| 虹口区| 达州市| 高阳县| 诸城市| 普兰县| 双鸭山市| 交口县| 光山县|