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

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.

主站蜘蛛池模板: 永靖县| 合水县| 蓬安县| 林芝县| 义马市| 西乌珠穆沁旗| 武汉市| 新巴尔虎左旗| 思茅市| 柳江县| 盖州市| 连州市| 咸丰县| 龙江县| 金堂县| 宜兰市| 澳门| 清苑县| 延安市| 缙云县| 会理县| 伊金霍洛旗| 连州市| 灵山县| 和平县| 彭山县| 青阳县| 海城市| 木兰县| 定襄县| 永和县| 扶风县| 扶绥县| 卢氏县| 华池县| 镇江市| 特克斯县| 曲松县| 松滋市| 临夏市| 江山市|