四元数

   1:  package com.jme.math;
   2:   
   3:  import java.io.Externalizable;
   4:  import java.io.IOException;
   5:  import java.io.ObjectInput;
   6:  import java.io.ObjectOutput;
   7:  import java.util.logging.Logger;
   8:   
   9:  import com.jme.system.JmeException;
  10:  import com.jme.util.export.InputCapsule;
  11:  import com.jme.util.export.JMEExporter;
  12:  import com.jme.util.export.JMEImporter;
  13:  import com.jme.util.export.OutputCapsule;
  14:  import com.jme.util.export.Savable;
  15:   
  16:  /**
  17:   * Quaternion defines a single example of a more general class of
  18:   * hypercomplex numbers. Quaternions extends a rotation in three dimensions to a
  19:   * rotation in four dimensions. This avoids "gimbal lock" and allows for smooth
  20:   * continuous rotation.
  21:   * 四元数
  22:   * 
  23:   * Quaternion is defined by four floating point numbers: {x y z w}.
  24:   * 
  25:   * @author Mark Powell
  26:   * @author Joshua Slack
  27:   */
  28:  public class Quaternion implements Externalizable, Savable, Cloneable {
  29:      private static final Logger logger = Logger.getLogger(Quaternion.class
  30:              .getName());
  31:   
  32:      private static final long serialVersionUID = 1L;
  33:   
  34:      public float x, y, z, w;
  35:   
  36:      /**
  37:       * Constructor instantiates a new Quaternion object
  38:       * initializing all values to zero, except w which is initialized to 1.
  39:       * 
  40:       */
  41:      public Quaternion() {
  42:          x = 0;
  43:          y = 0;
  44:          z = 0;
  45:          w = 1;
  46:      }
  47:   
  48:      /**
  49:       * Constructor instantiates a new Quaternion object from the
  50:       * given list of parameters.
  51:       * 
  52:       * @param x
  53:       *            the x value of the quaternion.
  54:       * @param y
  55:       *            the y value of the quaternion.
  56:       * @param z
  57:       *            the z value of the quaternion.
  58:       * @param w
  59:       *            the w value of the quaternion.
  60:       */
  61:      public Quaternion(float x, float y, float z, float w) {
  62:          this.x = x;
  63:          this.y = y;
  64:          this.z = z;
  65:          this.w = w;
  66:      }
  67:   
  68:      /**
  69:       * sets the data in a Quaternion object from the given list of
  70:       * parameters.
  71:       * 
  72:       * @param x
  73:       *            the x value of the quaternion.
  74:       * @param y
  75:       *            the y value of the quaternion.
  76:       * @param z
  77:       *            the z value of the quaternion.
  78:       * @param w
  79:       *            the w value of the quaternion.
  80:       */
  81:      public void set(float x, float y, float z, float w) {
  82:          this.x = x;
  83:          this.y = y;
  84:          this.z = z;
  85:          this.w = w;
  86:      }
  87:   
  88:      /**
  89:       * Sets the data in this Quaternion object to be equal to the
  90:       * passed Quaternion object. The values are copied producing a
  91:       * new object.
  92:       * 
  93:       * @param q
  94:       *            The Quaternion to copy values from.
  95:       * @return this for chaining
  96:       */
  97:      public Quaternion set(Quaternion q) {
  98:          this.x = q.x;
  99:          this.y = q.y;
 100:          this.z = q.z;
 101:          this.w = q.w;
 102:          return this;
 103:      }
 104:   
 105:      /**
 106:       * Constructor instantiates a new Quaternion object from a
 107:       * collection of rotation angles.
 108:       * 从欧拉角转换成四元数
 109:       * 
 110:       * @param angles
 111:       *            the angles of rotation (x, y, z) that will define the
 112:       *            Quaternion.
 113:       */
 114:      public Quaternion(float[] angles) {
 115:          fromAngles(angles);
 116:      }
 117:   
 118:      /**
 119:       * Constructor instantiates a new Quaternion object from an
 120:       * interpolation between two other quaternions.
 121:       * 球面线性插值构造四元数
 122:       * 
 123:       * @param q1
 124:       *            the first quaternion.
 125:       * @param q2
 126:       *            the second quaternion.
 127:       * @param interp
 128:       *            the amount to interpolate between the two quaternions.
 129:       */
 130:      public Quaternion(Quaternion q1, Quaternion q2, float interp) {
 131:          slerp(q1, q2, interp);
 132:      }
 133:   
 134:      /**
 135:       * Constructor instantiates a new Quaternion object from an
 136:       * existing quaternion, creating a copy.
 137:       * 
 138:       * @param q
 139:       *            the quaternion to copy.
 140:       */
 141:      public Quaternion(Quaternion q) {
 142:          this.x = q.x;
 143:          this.y = q.y;
 144:          this.z = q.z;
 145:          this.w = q.w;
 146:      }
 147:   
 148:      /**
 149:       * Sets this Quaternion to {0, 0, 0, 1}. Same as calling set(0,0,0,1).
 150:       */
 151:      public void loadIdentity() {
 152:          x = y = z = 0;
 153:          w = 1;
 154:      }
 155:   
 156:      /**
 157:       * @return true if this Quaternion is {0,0,0,1}
 158:       */
 159:      public boolean isIdentity() {
 160:          if (x == 0 && y == 0 && z == 0 && w == 1)
 161:              return true;
 162:          else
 163:              return false;
 164:      }
 165:   
 166:      /**
 167:       * fromAngles builds a quaternion from the Euler rotation
 168:       * angles (y,r,p).
 169:       * 从欧拉角转换成四元数
 170:       * 
 171:       * @param angles
 172:       *            the Euler angles of rotation (in radians).
 173:       */
 174:      public void fromAngles(float[] angles) {
 175:          if (angles.length != 3)
 176:              throw new IllegalArgumentException(
 177:                      "Angles array must have three elements");
 178:   
 179:          fromAngles(angles[0], angles[1], angles[2]);
 180:      }
 181:   
 182:      /**
 183:       * fromAngles builds a Quaternion from the Euler rotation
 184:       * angles (y,r,p). Note that we are applying in order: roll, pitch, yaw but
 185:       * we've ordered them in x, y, and z for convenience. See:
 186:       * http://www.euclideanspace
 187:       * .com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm
 188:       * 从欧拉角转换成四元数
 189:       * 
 190:       * @param yaw
 191:       *            the Euler yaw of rotation (in radians). (aka Bank, often rot
 192:       *            around x)
 193:       * @param roll
 194:       *            the Euler roll of rotation (in radians). (aka Heading, often
 195:       *            rot around y)
 196:       * @param pitch
 197:       *            the Euler pitch of rotation (in radians). (aka Attitude, often
 198:       *            rot around z)
 199:       */
 200:      public Quaternion fromAngles(float yaw, float roll, float pitch) {
 201:          float angle;
 202:          float sinRoll, sinPitch, sinYaw, cosRoll, cosPitch, cosYaw;
 203:          angle = pitch * 0.5f;
 204:          sinPitch = FastMath.sin(angle);
 205:          cosPitch = FastMath.cos(angle);
 206:          angle = roll * 0.5f;
 207:          sinRoll = FastMath.sin(angle);
 208:          cosRoll = FastMath.cos(angle);
 209:          angle = yaw * 0.5f;
 210:          sinYaw = FastMath.sin(angle);
 211:          cosYaw = FastMath.cos(angle);
 212:   
 213:          // variables used to reduce multiplication calls.
 214:          float cosRollXcosPitch = cosRoll * cosPitch;
 215:          float sinRollXsinPitch = sinRoll * sinPitch;
 216:          float cosRollXsinPitch = cosRoll * sinPitch;
 217:          float sinRollXcosPitch = sinRoll * cosPitch;
 218:   
 219:          w = (cosRollXcosPitch * cosYaw - sinRollXsinPitch * sinYaw);
 220:          x = (cosRollXcosPitch * sinYaw + sinRollXsinPitch * cosYaw);
 221:          y = (sinRollXcosPitch * cosYaw + cosRollXsinPitch * sinYaw);
 222:          z = (cosRollXsinPitch * cosYaw - sinRollXcosPitch * sinYaw);
 223:   
 224:          normalize();
 225:          return this;
 226:      }
 227:   
 228:      /**
 229:       * toAngles returns this quaternion converted to Euler rotation
 230:       * angles (yaw,roll,pitch).
 231:       * See http://www.euclideanspace.com/maths/geometry/rotations/conversions/
 232:       * quaternionToEuler/index.htm
 233:       * 从四元数转换成欧拉角
 234:       * 
 235:       * @param angles
 236:       *            the float[] in which the angles should be stored, or null if
 237:       *            you want a new float[] to be created
 238:       * @return the float[] in which the angles are stored.
 239:       */
 240:      public float[] toAngles(float[] angles) {
 241:          if (angles == null)
 242:              angles = new float[3];
 243:          else if (angles.length != 3)
 244:              throw new IllegalArgumentException(
 245:                      "Angles array must have three elements");
 246:   
 247:          float sqw = w * w;
 248:          float sqx = x * x;
 249:          float sqy = y * y;
 250:          float sqz = z * z;
 251:          float unit = sqx + sqy + sqz + sqw; // if normalized is one, otherwise
 252:          // is correction factor
 253:          float test = x * y + z * w;
 254:          if (test > 0.499 * unit) { // singularity at north pole
 255:              angles[1] = 2 * FastMath.atan2(x, w);
 256:              angles[2] = FastMath.HALF_PI;
 257:              angles[0] = 0;
 258:          } else if (test < -0.499 * unit) { // singularity at south pole
 259:              angles[1] = -2 * FastMath.atan2(x, w);
 260:              angles[2] = -FastMath.HALF_PI;
 261:              angles[0] = 0;
 262:          } else {
 263:              angles[1] = FastMath.atan2(2 * y * w - 2 * x * z, sqx - sqy - sqz
 264:                      + sqw); // roll or heading
 265:              angles[2] = FastMath.asin(2 * test / unit); // pitch or attitude
 266:              angles[0] = FastMath.atan2(2 * x * w - 2 * y * z, -sqx + sqy - sqz
 267:                      + sqw); // yaw or bank
 268:          }
 269:          return angles;
 270:      }
 271:   
 272:      /**
 273:       * 
 274:       * fromRotationMatrix generates a quaternion from a supplied
 275:       * matrix. This matrix is assumed to be a rotational matrix.
 276:       * 从矩阵转换成四元数,矩阵必须是旋转矩阵
 277:       * 
 278:       * @param matrix
 279:       *            the matrix that defines the rotation.
 280:       */
 281:      public Quaternion fromRotationMatrix(Matrix3f matrix) {
 282:          return fromRotationMatrix(matrix.m00, matrix.m01, matrix.m02,
 283:                  matrix.m10, matrix.m11, matrix.m12, matrix.m20, matrix.m21,
 284:                  matrix.m22);
 285:      }
 286:   
 287:      /**
 288:       * 从矩阵转换成四元数,矩阵必须是旋转矩阵
 289:       */
 290:      public Quaternion fromRotationMatrix(float m00, float m01, float m02,
 291:              float m10, float m11, float m12, float m20, float m21, float m22) {
 292:          // Use the Graphics Gems code, from
 293:          // ftp://ftp.cis.upenn.edu/pub/graphics/shoemake/quatut.ps.Z
 294:          // *NOT* the "Matrix and Quaternions FAQ", which has errors!
 295:  
 296:          // the trace is the sum of the diagonal elements; see
 297:          // http://mathworld.wolfram.com/MatrixTrace.html
 298:          float t = m00 + m11 + m22;
 299:   
 300:          // we protect the division by s by ensuring that s>=1
 301:          if (t >= 0) { // |w| >= .5
 302:              float s = FastMath.sqrt(t + 1); // |s|>=1 ...
 303:              w = 0.5f * s;
 304:              s = 0.5f / s; // so this division isn't bad
 305:              x = (m21 - m12) * s;
 306:              y = (m02 - m20) * s;
 307:              z = (m10 - m01) * s;
 308:          } else if ((m00 > m11) && (m00 > m22)) {
 309:              float s = FastMath.sqrt(1.0f + m00 - m11 - m22); // |s|>=1
 310:              x = s * 0.5f; // |x| >= .5
 311:              s = 0.5f / s;
 312:              y = (m10 + m01) * s;
 313:              z = (m02 + m20) * s;
 314:              w = (m21 - m12) * s;
 315:          } else if (m11 > m22) {
 316:              float s = FastMath.sqrt(1.0f + m11 - m00 - m22); // |s|>=1
 317:              y = s * 0.5f; // |y| >= .5
 318:              s = 0.5f / s;
 319:              x = (m10 + m01) * s;
 320:              z = (m21 + m12) * s;
 321:              w = (m02 - m20) * s;
 322:          } else {
 323:              float s = FastMath.sqrt(1.0f + m22 - m00 - m11); // |s|>=1
 324:              z = s * 0.5f; // |z| >= .5
 325:              s = 0.5f / s;
 326:              x = (m02 + m20) * s;
 327:              y = (m21 + m12) * s;
 328:              w = (m10 - m01) * s;
 329:          }
 330:   
 331:          return this;
 332:      }
 333:   
 334:      /**
 335:       * toRotationMatrix converts this quaternion to a rotational
 336:       * matrix. Note: the result is created from a normalized version of this
 337:       * quat.
 338:       * 由四元数构造完整的旋转矩阵
 339:       * 
 340:       * @return the rotation matrix representation of this quaternion.
 341:       */
 342:      public Matrix3f toRotationMatrix() {
 343:          Matrix3f matrix = new Matrix3f();
 344:          return toRotationMatrix(matrix);
 345:      }
 346:   
 347:      /**
 348:       * toRotationMatrix converts this quaternion to a rotational
 349:       * matrix. The result is stored in result.
 350:       * 由四元数构造完整的旋转矩阵
 351:       * 
 352:       * @param result
 353:       *            The Matrix3f to store the result in.
 354:       * @return the rotation matrix representation of this quaternion.
 355:       */
 356:      public Matrix3f toRotationMatrix(Matrix3f result) {
 357:   
 358:          float norm = norm();
 359:          // we explicitly test norm against one here, saving a division
 360:          // at the cost of a test and branch. Is it worth it?
 361:          float s = (norm == 1f) ? 2f : (norm > 0f) ? 2f / norm : 0;
 362:   
 363:          // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
 364:          // will be used 2-4 times each.
 365:          float xs = x * s;
 366:          float ys = y * s;
 367:          float zs = z * s;
 368:          float xx = x * xs;
 369:          float xy = x * ys;
 370:          float xz = x * zs;
 371:          float xw = w * xs;
 372:          float yy = y * ys;
 373:          float yz = y * zs;
 374:          float yw = w * ys;
 375:          float zz = z * zs;
 376:          float zw = w * zs;
 377:   
 378:          // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
 379:          result.m00 = 1 - (yy + zz);
 380:          result.m01 = (xy - zw);
 381:          result.m02 = (xz + yw);
 382:          result.m10 = (xy + zw);
 383:          result.m11 = 1 - (xx + zz);
 384:          result.m12 = (yz - xw);
 385:          result.m20 = (xz - yw);
 386:          result.m21 = (yz + xw);
 387:          result.m22 = 1 - (xx + yy);
 388:   
 389:          return result;
 390:      }
 391:   
 392:      /**
 393:       * toRotationMatrix converts this quaternion to a rotational
 394:       * matrix. The result is stored in result. 4th row and 4th column values are
 395:       * untouched. Note: the result is created from a normalized version of this
 396:       * quat.
 397:       * 由四元数构造完整的旋转矩阵
 398:       * 
 399:       * @param result
 400:       *            The Matrix4f to store the result in.
 401:       * @return the rotation matrix representation of this quaternion.
 402:       */
 403:      public Matrix4f toRotationMatrix(Matrix4f result) {
 404:   
 405:          float norm = norm();
 406:          // we explicitly test norm against one here, saving a division
 407:          // at the cost of a test and branch. Is it worth it?
 408:          float s = (norm == 1f) ? 2f : (norm > 0f) ? 2f / norm : 0;
 409:   
 410:          // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
 411:          // will be used 2-4 times each.
 412:          float xs = x * s;
 413:          float ys = y * s;
 414:          float zs = z * s;
 415:          float xx = x * xs;
 416:          float xy = x * ys;
 417:          float xz = x * zs;
 418:          float xw = w * xs;
 419:          float yy = y * ys;
 420:          float yz = y * zs;
 421:          float yw = w * ys;
 422:          float zz = z * zs;
 423:          float zw = w * zs;
 424:   
 425:          // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
 426:          result.m00 = 1 - (yy + zz);
 427:          result.m01 = (xy - zw);
 428:          result.m02 = (xz + yw);
 429:          result.m10 = (xy + zw);
 430:          result.m11 = 1 - (xx + zz);
 431:          result.m12 = (yz - xw);
 432:          result.m20 = (xz - yw);
 433:          result.m21 = (yz + xw);
 434:          result.m22 = 1 - (xx + yy);
 435:   
 436:          return result;
 437:      }
 438:   
 439:      /**
 440:       * getRotationColumn returns one of three columns specified by
 441:       * the parameter. This column is returned as a Vector3f object.
 442:       * 四元数转换到矩阵,获取指定的列构造的向量
 443:       * 
 444:       * @param i
 445:       *            the column to retrieve. Must be between 0 and 2.
 446:       * @return the column specified by the index.
 447:       */
 448:      public Vector3f getRotationColumn(int i) {
 449:          return getRotationColumn(i, null);
 450:      }
 451:   
 452:      /**
 453:       * getRotationColumn returns one of three columns specified by
 454:       * the parameter. This column is returned as a Vector3f object.
 455:       * The value is retrieved as if this quaternion was first normalized.
 456:       * 四元数转换到矩阵,获取指定的列构造的向量
 457:       * 
 458:       * @param i
 459:       *            the column to retrieve. Must be between 0 and 2.
 460:       * @param store
 461:       *            the vector object to store the result in. if null, a new one
 462:       *            is created.
 463:       * @return the column specified by the index.
 464:       */
 465:      public Vector3f getRotationColumn(int i, Vector3f store) {
 466:          if (store == null)
 467:              store = new Vector3f();
 468:   
 469:          float norm = norm();
 470:          if (norm != 1.0f) {
 471:              norm = FastMath.invSqrt(norm);
 472:          }
 473:   
 474:          float xx = x * x * norm;
 475:          float xy = x * y * norm;
 476:          float xz = x * z * norm;
 477:          float xw = x * w * norm;
 478:          float yy = y * y * norm;
 479:          float yz = y * z * norm;
 480:          float yw = y * w * norm;
 481:          float zz = z * z * norm;
 482:          float zw = z * w * norm;
 483:   
 484:          switch (i) {
 485:          case 0:
 486:              store.x = 1 - 2 * (yy + zz);
 487:              store.y = 2 * (xy + zw);
 488:              store.z = 2 * (xz - yw);
 489:              break;
 490:          case 1:
 491:              store.x = 2 * (xy - zw);
 492:              store.y = 1 - 2 * (xx + zz);
 493:              store.z = 2 * (yz + xw);
 494:              break;
 495:          case 2:
 496:              store.x = 2 * (xz + yw);
 497:              store.y = 2 * (yz - xw);
 498:              store.z = 1 - 2 * (xx + yy);
 499:              break;
 500:          default:
 501:              logger.warning("Invalid column index.");
 502:              throw new JmeException("Invalid column index. " + i);
 503:          }
 504:   
 505:          return store;
 506:      }
 507:   
 508:      /**
 509:       * fromAngleAxis sets this quaternion to the values specified
 510:       * by an angle and an axis of rotation. This method creates an object, so
 511:       * use fromAngleNormalAxis if your axis is already normalized.
 512:       * 绕轴axis(非单位向量)旋转angle(弧度)角的四元数
 513:       * 
 514:       * @param angle
 515:       *            the angle to rotate (in radians).
 516:       * @param axis
 517:       *            the axis of rotation.
 518:       * @return this quaternion
 519:       */
 520:      public Quaternion fromAngleAxis(float angle, Vector3f axis) {
 521:          Vector3f normAxis = axis.normalize();
 522:          fromAngleNormalAxis(angle, normAxis);
 523:          return this;
 524:      }
 525:   
 526:      /**
 527:       * fromAngleNormalAxis sets this quaternion to the values
 528:       * specified by an angle and a normalized axis of rotation.
 529:       * 绕轴axis(单位向量)旋转angle(弧度)角的四元数
 530:       * 
 531:       * @param angle
 532:       *            the angle to rotate (in radians).
 533:       * @param axis
 534:       *            the axis of rotation (already normalized).
 535:       */
 536:      public Quaternion fromAngleNormalAxis(float angle, Vector3f axis) {
 537:          if (axis.x == 0 && axis.y == 0 && axis.z == 0) {
 538:              loadIdentity();
 539:          } else {
 540:              float halfAngle = 0.5f * angle;
 541:              float sin = FastMath.sin(halfAngle);
 542:              w = FastMath.cos(halfAngle);
 543:              x = sin * axis.x;
 544:              y = sin * axis.y;
 545:              z = sin * axis.z;
 546:          }
 547:          return this;
 548:      }
 549:   
 550:      /**
 551:       * toAngleAxis sets a given angle and axis to that represented
 552:       * by the current quaternion. The values are stored as following: The axis
 553:       * is provided as a parameter and built by the method, the angle is returned
 554:       * as a float.
 555:       * 获取由该四元数代表的旋转的旋转轴和角
 556:       * 
 557:       * @param axisStore
 558:       *            the object we'll store the computed axis in.
 559:       * @return the angle of rotation in radians.
 560:       */
 561:      public float toAngleAxis(Vector3f axisStore) {
 562:          float sqrLength = x * x + y * y + z * z;
 563:          float angle;
 564:          if (sqrLength == 0.0f) {
 565:              angle = 0.0f;
 566:              if (axisStore != null) {
 567:                  axisStore.x = 1.0f;
 568:                  axisStore.y = 0.0f;
 569:                  axisStore.z = 0.0f;
 570:              }
 571:          } else {
 572:              angle = (2.0f * FastMath.acos(w));
 573:              if (axisStore != null) {
 574:                  float invLength = (1.0f / FastMath.sqrt(sqrLength));
 575:                  axisStore.x = x * invLength;
 576:                  axisStore.y = y * invLength;
 577:                  axisStore.z = z * invLength;
 578:              }
 579:          }
 580:   
 581:          return angle;
 582:      }
 583:   
 584:      /**
 585:       * slerp sets this quaternion's value as an interpolation
 586:       * between two other quaternions. 
 587:       * slerp:球面线性插值(Spherical Linear interpolation),返回q1到q2之间的插值方位
 588:       * 
 589:       * @param q1
 590:       *            the first quaternion.
 591:       * @param q2
 592:       *            the second quaternion.
 593:       * @param t
 594:       *            the amount to interpolate between the two quaternions.
 595:       *            插值参数,在0到1之间变化
 596:       */
 597:      public Quaternion slerp(Quaternion q1, Quaternion q2, float t) {
 598:          // Create a local quaternion to store the interpolated quaternion
 599:          if (q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w) {
 600:              this.set(q1);
 601:              return this;
 602:          }
 603:   
 604:          float result = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z)
 605:                  + (q1.w * q2.w);
 606:   
 607:          if (result < 0.0f) {
 608:              // Negate the second quaternion and the result of the dot product
 609:              q2.x = -q2.x;
 610:              q2.y = -q2.y;
 611:              q2.z = -q2.z;
 612:              q2.w = -q2.w;
 613:              result = -result;
 614:          }
 615:   
 616:          // Set the first and second scale for the interpolation
 617:          float scale0 = 1 - t;
 618:          float scale1 = t;
 619:   
 620:          // Check if the angle between the 2 quaternions was big enough to
 621:          // warrant such calculations
 622:          if ((1 - result) > 0.1f) {// Get the angle between the 2 quaternions,
 623:              // and then store the sin() of that angle
 624:              float theta = FastMath.acos(result);
 625:              float invSinTheta = 1f / FastMath.sin(theta);
 626:   
 627:              // Calculate the scale for q1 and q2, according to the angle and
 628:              // it's sine value
 629:              scale0 = FastMath.sin((1 - t) * theta) * invSinTheta;
 630:              scale1 = FastMath.sin((t * theta)) * invSinTheta;
 631:          }
 632:   
 633:          // Calculate the x, y, z and w values for the quaternion by using a
 634:          // special
 635:          // form of linear interpolation for quaternions.
 636:          this.x = (scale0 * q1.x) + (scale1 * q2.x);
 637:          this.y = (scale0 * q1.y) + (scale1 * q2.y);
 638:          this.z = (scale0 * q1.z) + (scale1 * q2.z);
 639:          this.w = (scale0 * q1.w) + (scale1 * q2.w);
 640:   
 641:          // Return the interpolated quaternion
 642:          return this;
 643:      }
 644:   
 645:      /**
 646:       * Sets the values of this quaternion to the slerp from itself to q2 by
 647:       * changeAmnt
 648:       * slerp:球面线性插值(Spherical Linear interpolation)
 649:       * 
 650:       * @param q2
 651:       *            Final interpolation value
 652:       * @param changeAmnt
 653:       *            The amount diffrence
 654:       */
 655:      public void slerp(Quaternion q2, float changeAmnt) {
 656:          if (this.x == q2.x && this.y == q2.y && this.z == q2.z
 657:                  && this.w == q2.w) {
 658:              return;
 659:          }
 660:   
 661:          float result = (this.x * q2.x) + (this.y * q2.y) + (this.z * q2.z)
 662:                  + (this.w * q2.w);
 663:   
 664:          if (result < 0.0f) {
 665:              // Negate the second quaternion and the result of the dot product
 666:              q2.x = -q2.x;
 667:              q2.y = -q2.y;
 668:              q2.z = -q2.z;
 669:              q2.w = -q2.w;
 670:              result = -result;
 671:          }
 672:   
 673:          // Set the first and second scale for the interpolation
 674:          float scale0 = 1 - changeAmnt;
 675:          float scale1 = changeAmnt;
 676:   
 677:          // Check if the angle between the 2 quaternions was big enough to
 678:          // warrant such calculations
 679:          if ((1 - result) > 0.1f) {
 680:              // Get the angle between the 2 quaternions, and then store the sin()
 681:              // of that angle
 682:              float theta = FastMath.acos(result);
 683:              float invSinTheta = 1f / FastMath.sin(theta);
 684:   
 685:              // Calculate the scale for q1 and q2, according to the angle and
 686:              // it's sine value
 687:              scale0 = FastMath.sin((1 - changeAmnt) * theta) * invSinTheta;
 688:              scale1 = FastMath.sin((changeAmnt * theta)) * invSinTheta;
 689:          }
 690:   
 691:          // Calculate the x, y, z and w values for the quaternion by using a
 692:          // special
 693:          // form of linear interpolation for quaternions.
 694:          this.x = (scale0 * this.x) + (scale1 * q2.x);
 695:          this.y = (scale0 * this.y) + (scale1 * q2.y);
 696:          this.z = (scale0 * this.z) + (scale1 * q2.z);
 697:          this.w = (scale0 * this.w) + (scale1 * q2.w);
 698:      }
 699:   
 700:      /**
 701:       * add adds the values of this quaternion to those of the
 702:       * parameter quaternion. The result is returned as a new quaternion.
 703:       * 
 704:       * @param q
 705:       *            the quaternion to add to this.
 706:       * @return the new quaternion.
 707:       */
 708:      public Quaternion add(Quaternion q) {
 709:          return new Quaternion(x + q.x, y + q.y, z + q.z, w + q.w);
 710:      }
 711:   
 712:      /**
 713:       * add adds the values of this quaternion to those of the
 714:       * parameter quaternion. The result is stored in this Quaternion.
 715:       * 
 716:       * @param q
 717:       *            the quaternion to add to this.
 718:       * @return This Quaternion after addition.
 719:       */
 720:      public Quaternion addLocal(Quaternion q) {
 721:          this.x += q.x;
 722:          this.y += q.y;
 723:          this.z += q.z;
 724:          this.w += q.w;
 725:          return this;
 726:      }
 727:   
 728:      /**
 729:       * subtract subtracts the values of the parameter quaternion
 730:       * from those of this quaternion. The result is returned as a new
 731:       * quaternion.
 732:       * 
 733:       * @param q
 734:       *            the quaternion to subtract from this.
 735:       * @return the new quaternion.
 736:       */
 737:      public Quaternion subtract(Quaternion q) {
 738:          return new Quaternion(x - q.x, y - q.y, z - q.z, w - q.w);
 739:      }
 740:   
 741:      /**
 742:       * subtract subtracts the values of the parameter quaternion
 743:       * from those of this quaternion. The result is stored in this Quaternion.
 744:       * 
 745:       * @param q
 746:       *            the quaternion to subtract from this.
 747:       * @return This Quaternion after subtraction.
 748:       */
 749:      public Quaternion subtractLocal(Quaternion q) {
 750:          this.x -= q.x;
 751:          this.y -= q.y;
 752:          this.z -= q.z;
 753:          this.w -= q.w;
 754:          return this;
 755:      }
 756:   
 757:      /**
 758:       * mult multiplies this quaternion by a parameter quaternion.
 759:       * The result is returned as a new quaternion. It should be noted that
 760:       * quaternion multiplication is not cummulative so q * p != p * q.
 761:       * 
 762:       * @param q
 763:       *            the quaternion to multiply this quaternion by.
 764:       * @return the new quaternion.
 765:       */
 766:      public Quaternion mult(Quaternion q) {
 767:          return mult(q, null);
 768:      }
 769:   
 770:      /**
 771:       * mult multiplies this quaternion by a parameter quaternion
 772:       * (q). 'this' is not modified. It should be noted that quaternion
 773:       * multiplication is not cummulative so q * p != p * q.
 774:       * 
 775:       * It IS safe for q and res to be the same object.
 776:       * 
 777:       * @param q
 778:       *            the quaternion to multiply this quaternion by.
 779:       * @param res
 780:       *            the quaternion to store the result in (may be null). If
 781:       *            non-null, the input values of 'res' will be ignored and
 782:       *            replaced.
 783:       * @return If specified res is null, then a new Quaternion; otherwise
 784:       *         returns the populated 'res'.
 785:       */
 786:      public Quaternion mult(Quaternion q, Quaternion res) {
 787:          if (res == null)
 788:              res = new Quaternion();
 789:          float qw = q.w, qx = q.x, qy = q.y, qz = q.z;
 790:          res.x = x * qw + y * qz - z * qy + w * qx;
 791:          res.y = -x * qz + y * qw + z * qx + w * qy;
 792:          res.z = x * qy - y * qx + z * qw + w * qz;
 793:          res.w = -x * qx - y * qy - z * qz + w * qw;
 794:          return res;
 795:      }
 796:   
 797:      /**
 798:       * apply multiplies this quaternion by a parameter matrix
 799:       * internally.
 800:       * 
 801:       * @param matrix
 802:       *            the matrix to apply to this quaternion.
 803:       */
 804:      public void apply(Matrix3f matrix) {
 805:          float oldX = x, oldY = y, oldZ = z, oldW = w;
 806:          fromRotationMatrix(matrix);
 807:          float tempX = x, tempY = y, tempZ = z, tempW = w;
 808:   
 809:          x = oldX * tempW + oldY * tempZ - oldZ * tempY + oldW * tempX;
 810:          y = -oldX * tempZ + oldY * tempW + oldZ * tempX + oldW * tempY;
 811:          z = oldX * tempY - oldY * tempX + oldZ * tempW + oldW * tempZ;
 812:          w = -oldX * tempX - oldY * tempY - oldZ * tempZ + oldW * tempW;
 813:      }
 814:   
 815:      /**
 816:       * 
 817:       * fromAxes creates a Quaternion that represents
 818:       * the coordinate system defined by three axes. These axes are assumed to be
 819:       * orthogonal and no error checking is applied. Thus, the user must insure
 820:       * that the three axes being provided indeed represents a proper right
 821:       * handed coordinate system.
 822:       * 从矩阵的各列转换到四元组
 823:       * 
 824:       * @param axis
 825:       *            the array containing the three vectors representing the
 826:       *            coordinate system.
 827:       */
 828:      public Quaternion fromAxes(Vector3f[] axis) {
 829:          if (axis.length != 3)
 830:              throw new IllegalArgumentException(
 831:                      "Axis array must have three elements");
 832:          return fromAxes(axis[0], axis[1], axis[2]);
 833:      }
 834:   
 835:      /**
 836:       * 
 837:       * fromAxes creates a Quaternion that represents
 838:       * the coordinate system defined by three axes. These axes are assumed to be
 839:       * orthogonal and no error checking is applied. Thus, the user must insure
 840:       * that the three axes being provided indeed represents a proper right
 841:       * handed coordinate system.
 842:       * 从矩阵的各列转换到四元组
 843:       * 
 844:       * @param xAxis
 845:       *            vector representing the x-axis of the coordinate system.
 846:       * @param yAxis
 847:       *            vector representing the y-axis of the coordinate system.
 848:       * @param zAxis
 849:       *            vector representing the z-axis of the coordinate system.
 850:       */
 851:      public Quaternion fromAxes(Vector3f xAxis, Vector3f yAxis, Vector3f zAxis) {
 852:          return fromRotationMatrix(xAxis.x, yAxis.x, zAxis.x, xAxis.y, yAxis.y,
 853:                  zAxis.y, xAxis.z, yAxis.z, zAxis.z);
 854:      }
 855:   
 856:      /**
 857:       * 
 858:       * toAxes takes in an array of three vectors. Each vector
 859:       * corresponds to an axis of the coordinate system defined by the quaternion
 860:       * rotation.
 861:       * 从四元组转换到旋转矩阵,获取矩阵的各列
 862:       * 
 863:       * @param axis
 864:       *            the array of vectors to be filled.
 865:       */
 866:      public void toAxes(Vector3f axis[]) {
 867:          Matrix3f tempMat = toRotationMatrix();
 868:          axis[0] = tempMat.getColumn(0, axis[0]);
 869:          axis[1] = tempMat.getColumn(1, axis[1]);
 870:          axis[2] = tempMat.getColumn(2, axis[2]);
 871:      }
 872:   
 873:      /**
 874:       * mult multiplies this quaternion by a parameter vector. The
 875:       * result is returned as a new vector. 'this' is not modified.
 876:       * 四元数与向量相乘
 877:       * 
 878:       * @param v
 879:       *            the vector to multiply this quaternion by.
 880:       * @return the new vector.
 881:       */
 882:      public Vector3f mult(Vector3f v) {
 883:          return mult(v, null);
 884:      }
 885:   
 886:      /**
 887:       * mult multiplies this quaternion by a parameter vector. The
 888:       * result is stored in the supplied vector This method is very poorly named,
 889:       * since the specified vector is modified and, contrary to the other *Local
 890:       * methods in this and other jME classes, 'this' remains unchanged.
 891:       * 四元数与向量相乘
 892:       * 
 893:       * @param v
 894:       *            the vector which this Quaternion multiplies.
 895:       * @return v
 896:       */
 897:      public Vector3f multLocal(Vector3f v) {
 898:          float tempX, tempY;
 899:          tempX = w * w * v.x + 2 * y * w * v.z - 2 * z * w * v.y + x * x * v.x
 900:                  + 2 * y * x * v.y + 2 * z * x * v.z - z * z * v.x - y * y * v.x;
 901:          tempY = 2 * x * y * v.x + y * y * v.y + 2 * z * y * v.z + 2 * w * z
 902:                  * v.x - z * z * v.y + w * w * v.y - 2 * x * w * v.z - x * x
 903:                  * v.y;
 904:          v.z = 2 * x * z * v.x + 2 * y * z * v.y + z * z * v.z - 2 * w * y * v.x
 905:                  - y * y * v.z + 2 * w * x * v.y - x * x * v.z + w * w * v.z;
 906:          v.x = tempX;
 907:          v.y = tempY;
 908:          return v;
 909:      }
 910:   
 911:      /**
 912:       * Multiplies this Quaternion by the supplied quaternion. The result is
 913:       * stored in this Quaternion, which is also returned for chaining. Similar
 914:       * to this *= q.
 915:       * 四元数与四元数相乘
 916:       * 
 917:       * @param q
 918:       *            The Quaternion to multiply this one by.
 919:       * @return This Quaternion, after multiplication.
 920:       */
 921:      public Quaternion multLocal(Quaternion q) {
 922:          float x1 = x * q.w + y * q.z - z * q.y + w * q.x;
 923:          float y1 = -x * q.z + y * q.w + z * q.x + w * q.y;
 924:          float z1 = x * q.y - y * q.x + z * q.w + w * q.z;
 925:          w = -x * q.x - y * q.y - z * q.z + w * q.w;
 926:          x = x1;
 927:          y = y1;
 928:          z = z1;
 929:          return this;
 930:      }
 931:   
 932:      /**
 933:       * Multiplies this Quaternion by the supplied quaternion. The result is
 934:       * stored in this Quaternion, which is also returned for chaining. Similar
 935:       * to this *= q.
 936:       * 四元数与四元数相乘
 937:       * 
 938:       * @param qx
 939:       *            - quat x value
 940:       * @param qy
 941:       *            - quat y value
 942:       * @param qz
 943:       *            - quat z value
 944:       * @param qw
 945:       *            - quat w value
 946:       * 
 947:       * @return This Quaternion, after multiplication.
 948:       */
 949:      public Quaternion multLocal(float qx, float qy, float qz, float qw) {
 950:          float x1 = x * qw + y * qz - z * qy + w * qx;
 951:          float y1 = -x * qz + y * qw + z * qx + w * qy;
 952:          float z1 = x * qy - y * qx + z * qw + w * qz;
 953:          w = -x * qx - y * qy - z * qz + w * qw;
 954:          x = x1;
 955:          y = y1;
 956:          z = z1;
 957:          return this;
 958:      }
 959:   
 960:      /**
 961:       * mult multiplies this quaternion by a parameter vector. The
 962:       * result is returned as a new vector. 'this' is not modified.
 963:       * 四元数与向量相乘
 964:       * 
 965:       * @param v
 966:       *            the vector to multiply this quaternion by.
 967:       * @param store
 968:       *            the vector to store the result in. It IS safe for v and store
 969:       *            to be the same object.
 970:       * @return the result vector.
 971:       */
 972:      public Vector3f mult(Vector3f v, Vector3f store) {
 973:          if (store == null)
 974:              store = new Vector3f();
 975:          if (v.x == 0 && v.y == 0 && v.z == 0) {
 976:              store.set(0, 0, 0);
 977:          } else {
 978:              float vx = v.x, vy = v.y, vz = v.z;
 979:              store.x = w * w * vx + 2 * y * w * vz - 2 * z * w * vy + x * x * vx
 980:                      + 2 * y * x * vy + 2 * z * x * vz - z * z * vx - y * y * vx;
 981:              store.y = 2 * x * y * vx + y * y * vy + 2 * z * y * vz + 2 * w * z
 982:                      * vx - z * z * vy + w * w * vy - 2 * x * w * vz - x * x
 983:                      * vy;
 984:              store.z = 2 * x * z * vx + 2 * y * z * vy + z * z * vz - 2 * w * y
 985:                      * vx - y * y * vz + 2 * w * x * vy - x * x * vz + w * w
 986:                      * vz;
 987:          }
 988:          return store;
 989:      }
 990:   
 991:      /**
 992:       * mult multiplies this quaternion by a parameter scalar. The
 993:       * result is returned as a new quaternion.
 994:       * 标量乘
 995:       * 
 996:       * @param scalar
 997:       *            the quaternion to multiply this quaternion by.
 998:       * @return the new quaternion.
 999:       */
1000:      public Quaternion mult(float scalar) {
1001:          return new Quaternion(scalar * x, scalar * y, scalar * z, scalar * w);
1002:      }
1003:   
1004:      /**
1005:       * mult multiplies this quaternion by a parameter scalar. The
1006:       * result is stored locally.
1007:       * 标量乘
1008:       * 
1009:       * @param scalar
1010:       *            the quaternion to multiply this quaternion by.
1011:       * @return this.
1012:       */
1013:      public Quaternion multLocal(float scalar) {
1014:          w *= scalar;
1015:          x *= scalar;
1016:          y *= scalar;
1017:          z *= scalar;
1018:          return this;
1019:      }
1020:   
1021:      /**
1022:       * dot calculates and returns the dot product of this
1023:       * quaternion with that of the parameter quaternion.
1024:       * 点乘
1025:       * 
1026:       * @param q
1027:       *            the quaternion to calculate the dot product of.
1028:       * @return the dot product of this and the parameter quaternion.
1029:       */
1030:      public float dot(Quaternion q) {
1031:          return w * q.w + x * q.x + y * q.y + z * q.z;
1032:      }
1033:   
1034:      /**
1035:       * norm returns the norm of this quaternion. This is the dot
1036:       * product of this quaternion with itself.
1037:       * 模的平方(点乘自身)
1038:       * 
1039:       * @return the norm of the quaternion.
1040:       */
1041:      public float norm() {
1042:          return w * w + x * x + y * y + z * z;
1043:      }
1044:   
1045:      /**
1046:       * normalize normalizes the current Quaternion
1047:       * 规格化
1048:       */
1049:      public void normalize() {
1050:          float n = FastMath.invSqrt(norm());
1051:          x *= n;
1052:          y *= n;
1053:          z *= n;
1054:          w *= n;
1055:      }
1056:   
1057:      /**
1058:       * inverse returns the inverse of this quaternion as a new
1059:       * quaternion. If this quaternion does not have an inverse (if its normal is
1060:       * 0 or less), then null is returned.
1061:       * 四元数的逆
1062:       * 
1063:       * @return the inverse of this quaternion or null if the inverse does not
1064:       *         exist.
1065:       */
1066:      public Quaternion inverse() {
1067:          float norm = norm();
1068:          if (norm > 0.0) {
1069:              float invNorm = 1.0f / norm;
1070:              return new Quaternion(-x * invNorm, -y * invNorm, -z * invNorm, w
1071:                      * invNorm);
1072:          }
1073:          // return an invalid result to flag the error
1074:          return null;
1075:      }
1076:   
1077:      /**
1078:       * inverse calculates the inverse of this quaternion and
1079:       * returns this quaternion after it is calculated. If this quaternion does
1080:       * not have an inverse (if it's norma is 0 or less), nothing happens
1081:       * 四元数的逆
1082:       * 
1083:       * @return the inverse of this quaternion
1084:       */
1085:      public Quaternion inverseLocal() {
1086:          float norm = norm();
1087:          if (norm > 0.0) {
1088:              float invNorm = 1.0f / norm;
1089:              x *= -invNorm;
1090:              y *= -invNorm;
1091:              z *= -invNorm;
1092:              w *= invNorm;
1093:          }
1094:          return this;
1095:      }
1096:   
1097:      /**
1098:       * negate inverts the values of the quaternion.
1099:       * 负四元数
1100:       * 
1101:       */
1102:      public void negate() {
1103:          x *= -1;
1104:          y *= -1;
1105:          z *= -1;
1106:          w *= -1;
1107:      }
1108:   
1109:      /**
1110:       * 
1111:       * toString creates the string representation of this
1112:       * Quaternion. The values of the quaternion are displace (x, y,
1113:       * z, w), in the following manner: 
1114:       * com.jme.math.Quaternion: [x=1" y=2 z=3 w=1]
1115:       * 
1116:       * @return the string representation of this object.
1117:       * @see java.lang.Object#toString()
1118:       */
1119:      public String toString() {
1120:          return Quaternion.class.getName() + ": [x=" + x + " y=" + y + " z=" + z
1121:                  + " w=" + w + "]";
1122:      }
1123:   
1124:      /**
1125:       * equals determines if two quaternions are logically equal,
1126:       * that is, if the values of (x, y, z, w) are the same for both quaternions.
1127:       * 
1128:       * @param o
1129:       *            the object to compare for equality
1130:       * @return true if they are equal, false otherwise.
1131:       */
1132:      public boolean equals(Object o) {
1133:          if (!(o instanceof Quaternion)) {
1134:              return false;
1135:          }
1136:   
1137:          if (this == o) {
1138:              return true;
1139:          }
1140:   
1141:          Quaternion comp = (Quaternion) o;
1142:          if (Float.compare(x, comp.x) != 0)
1143:              return false;
1144:          if (Float.compare(y, comp.y) != 0)
1145:              return false;
1146:          if (Float.compare(z, comp.z) != 0)
1147:              return false;
1148:          if (Float.compare(w, comp.w) != 0)
1149:              return false;
1150:          return true;
1151:      }
1152:   
1153:      /**
1154:       * 
1155:       * hashCode returns the hash code value as an integer and is
1156:       * supported for the benefit of hashing based collection classes such as
1157:       * Hashtable, HashMap, HashSet etc.
1158:       * 
1159:       * @return the hashcode for this instance of Quaternion.
1160:       * @see java.lang.Object#hashCode()
1161:       */
1162:      public int hashCode() {
1163:          int hash = 37;
1164:          hash = 37 * hash + Float.floatToIntBits(x);
1165:          hash = 37 * hash + Float.floatToIntBits(y);
1166:          hash = 37 * hash + Float.floatToIntBits(z);
1167:          hash = 37 * hash + Float.floatToIntBits(w);
1168:          return hash;
1169:   
1170:      }
1171:   
1172:      /**
1173:       * readExternal builds a quaternion from an
1174:       * ObjectInput object. 
1175:       * NOTE: Used with serialization. Not to be called manually.
1176:       * 
1177:       * @param in
1178:       *            the ObjectInput value to read from.
1179:       * @throws IOException
1180:       *             if the ObjectInput value has problems reading a float.
1181:       * @see java.io.Externalizable
1182:       */
1183:      public void readExternal(ObjectInput in) throws IOException {
1184:          x = in.readFloat();
1185:          y = in.readFloat();
1186:          z = in.readFloat();
1187:          w = in.readFloat();
1188:      }
1189:   
1190:      /**
1191:       * writeExternal writes this quaternion out to a
1192:       * ObjectOutput object. NOTE: Used with serialization. Not to
1193:       * be called manually.
1194:       * 
1195:       * @param out
1196:       *            the object to write to.
1197:       * @throws IOException
1198:       *             if writing to the ObjectOutput fails.
1199:       * @see java.io.Externalizable
1200:       */
1201:      public void writeExternal(ObjectOutput out) throws IOException {
1202:          out.writeFloat(x);
1203:          out.writeFloat(y);
1204:          out.writeFloat(z);
1205:          out.writeFloat(w);
1206:      }
1207:   
1208:      private static final Vector3f tmpYaxis = new Vector3f();
1209:      private static final Vector3f tmpZaxis = new Vector3f();
1210:      private static final Vector3f tmpXaxis = new Vector3f();
1211:   
1212:      /**
1213:       * lookAt is a convienence method for auto-setting the
1214:       * quaternion based on a direction and an up vector. It computes the
1215:       * rotation to transform the z-axis to point into 'direction' and the y-axis
1216:       * to 'up'.
1217:       * 
1218:       * @param direction
1219:       *            where to look at in terms of local coordinates
1220:       * @param up
1221:       *            a vector indicating the local up direction. (typically {0, 1,
1222:       *            0} in jME.)
1223:       */
1224:      public void lookAt(Vector3f direction, Vector3f up) {
1225:          tmpZaxis.set(direction).normalizeLocal();
1226:          tmpXaxis.set(up).crossLocal(direction).normalizeLocal();
1227:          tmpYaxis.set(direction).crossLocal(tmpXaxis).normalizeLocal();
1228:          fromAxes(tmpXaxis, tmpYaxis, tmpZaxis);
1229:      }
1230:   
1231:      public void write(JMEExporter e) throws IOException {
1232:          OutputCapsule cap = e.getCapsule(this);
1233:          cap.write(x, "x", 0);
1234:          cap.write(y, "y", 0);
1235:          cap.write(z, "z", 0);
1236:          cap.write(w, "w", 1);
1237:      }
1238:   
1239:      public void read(JMEImporter e) throws IOException {
1240:          InputCapsule cap = e.getCapsule(this);
1241:          x = cap.readFloat("x", 0);
1242:          y = cap.readFloat("y", 0);
1243:          z = cap.readFloat("z", 0);
1244:          w = cap.readFloat("w", 1);
1245:      }
1246:   
1247:      public Class
  
  extends Quaternion> getClassTag() {
1248:          return this.getClass();
1249:      }
1250:   
1251:      /**
1252:       * @return A new quaternion that describes a rotation that would point you
1253:       *         in the exact opposite direction of this Quaternion.
1254:       *         反转
1255:       */
1256:      public Quaternion opposite() {
1257:          return opposite(null);
1258:      }
1259:   
1260:      /**
1261:       * FIXME: This seems to have singularity type issues with angle == 0,
1262:       * possibly others such as PI.
1263:       * 反转
1264:       * 
1265:       * @param store
1266:       *            A Quaternion to store our result in. If null, a new one is
1267:       *            created.
1268:       * @return The store quaternion (or a new Quaterion, if store is null) that
1269:       *         describes a rotation that would point you in the exact opposite
1270:       *         direction of this Quaternion.
1271:       */
1272:      public Quaternion opposite(Quaternion store) {
1273:          if (store == null)
1274:              store = new Quaternion();
1275:   
1276:          Vector3f axis = new Vector3f();
1277:          float angle = toAngleAxis(axis);
1278:   
1279:          store.fromAngleAxis(FastMath.PI + angle, axis);
1280:          return store;
1281:      }
1282:   
1283:      /**
1284:       * @return This Quaternion, altered to describe a rotation that would point
1285:       *         you in the exact opposite direction of where it is pointing
1286:       *         currently.
1287:       */
1288:      public Quaternion oppositeLocal() {
1289:          return opposite(this);
1290:      }
1291:   
1292:      @Override
1293:      public Quaternion clone() {
1294:          try {
1295:              return (Quaternion) super.clone();
1296:          } catch (CloneNotSupportedException e) {
1297:              throw new AssertionError(); // can not happen
1298:          }
1299:      }
1300:   
1301:      public float getX() {
1302:          return x;
1303:      }
1304:   
1305:      public void setX(float x) {
1306:          this.x = x;
1307:      }
1308:   
1309:      public float getY() {
1310:          return y;
1311:      }
1312:   
1313:      public void setY(float y) {
1314:          this.y = y;
1315:      }
1316:   
1317:      public float getZ() {
1318:          return z;
1319:      }
1320:   
1321:      public void setZ(float z) {
1322:          this.z = z;
1323:      }
1324:   
1325:      public float getW() {
1326:          return w;
1327:      }
1328:   
1329:      public void setW(float w) {
1330:          this.w = w;
1331:      }
1332:  }

 

clip_image048[9]

 1:  public Matrix3f toRotationMatrix(Matrix3f result) {
 2:   
 3:      float norm = norm();
 4:      // we explicitly test norm against one here, saving a division
 5:      // at the cost of a test and branch. Is it worth it?
 6:      float s = (norm == 1f) ? 2f : (norm > 0f) ? 2f / norm : 0;
 7:   
 8:      // compute xs/ys/zs first to save 6 multiplications, since xs/ys/zs
 9:      // will be used 2-4 times each.
10:      float xs = x * s;
11:      float ys = y * s;
12:      float zs = z * s;
13:      float xx = x * xs;
14:      float xy = x * ys;
15:      float xz = x * zs;
16:      float xw = w * xs;
17:      float yy = y * ys;
18:      float yz = y * zs;
19:      float yw = w * ys;
20:      float zz = z * zs;
21:      float zw = w * zs;
22:   
23:      // using s=2/norm (instead of 1/norm) saves 9 multiplications by 2 here
24:      result.m00 = 1 - (yy + zz);
25:      result.m01 = (xy - zw);
26:      result.m02 = (xz + yw);
27:      result.m10 = (xy + zw);
28:      result.m11 = 1 - (xx + zz);
29:      result.m12 = (yz - xw);
30:      result.m20 = (xz - yw);
31:      result.m21 = (yz + xw);
32:      result.m22 = 1 - (xx + yy);
33:   
34:      return result;
35:  }

 

 1:  /**
 2:   * getRotationColumn returns one of three columns specified by
 3:   * the parameter. This column is returned as a Vector3f object.
 4:   * The value is retrieved as if this quaternion was first normalized.
 5:   * 四元数转换到矩阵,获取指定的列构造的向量
 6:   * 
 7:   * @param i
 8:   *            the column to retrieve. Must be between 0 and 2.
 9:   * @param store
10:   *            the vector object to store the result in. if null, a new one
11:   *            is created.
12:   * @return the column specified by the index.
13:   */
14:  public Vector3f getRotationColumn(int i, Vector3f store) {
15:      if (store == null)
16:          store = new Vector3f();
17:   
18:      float norm = norm();
19:      if (norm != 1.0f) {
20:          norm = FastMath.invSqrt(norm);
21:      }
22:   
23:      float xx = x * x * norm;
24:      float xy = x * y * norm;
25:      float xz = x * z * norm;
26:      float xw = x * w * norm;
27:      float yy = y * y * norm;
28:      float yz = y * z * norm;
29:      float yw = y * w * norm;
30:      float zz = z * z * norm;
31:      float zw = z * w * norm;
32:   
33:      switch (i) {
34:      case 0:
35:          store.x = 1 - 2 * (yy + zz);
36:          store.y = 2 * (xy + zw);
37:          store.z = 2 * (xz - yw);
38:          break;
39:      case 1:
40:          store.x = 2 * (xy - zw);
41:          store.y = 1 - 2 * (xx + zz);
42:          store.z = 2 * (yz + xw);
43:          break;
44:      case 2:
45:          store.x = 2 * (xz + yw);
46:          store.y = 2 * (yz - xw);
47:          store.z = 1 - 2 * (xx + yy);
48:          break;
49:      default:
50:          logger.warning("Invalid column index.");
51:          throw new JmeException("Invalid column index. " + i);
52:      }
53:   
54:      return store;
55:  }

四元数的逆:

clip_image041[9]

clip_image042[9]

 1:  public Quaternion inverse() {
 2:      float norm = norm();
 3:      if (norm > 0.0) {
 4:          float invNorm = 1.0f / norm;
 5:          return new Quaternion(-x * invNorm, -y * invNorm, -z * invNorm, w
 6:                  * invNorm);
 7:      }
 8:      // return an invalid result to flag the error
 9:      return null;
10:  }

 

clip_image043[9]

 1:  public Quaternion multLocal(Quaternion q) {
 2:      float x1 = x * q.w + y * q.z - z * q.y + w * q.x;
 3:      float y1 = -x * q.z + y * q.w + z * q.x + w * q.y;
 4:      float z1 = x * q.y - y * q.x + z * q.w + w * q.z;
 5:      w = -x * q.x - y * q.y - z * q.z + w * q.w;
 6:      x = x1;
 7:      y = y1;
 8:      z = z1;
 9:      return this;
10:  }

 

clip_image046[9]

 1:  public Quaternion slerp(Quaternion q1, Quaternion q2, float t) {
 2:      // Create a local quaternion to store the interpolated quaternion
 3:      if (q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w) {
 4:          this.set(q1);
 5:          return this;
 6:      }
 7:   
 8:      float result = (q1.x * q2.x) + (q1.y * q2.y) + (q1.z * q2.z)
 9:              + (q1.w * q2.w);
10:   
11:      if (result < 0.0f) {
12:          // Negate the second quaternion and the result of the dot product
13:          q2.x = -q2.x;
14:          q2.y = -q2.y;
15:          q2.z = -q2.z;
16:          q2.w = -q2.w;
17:          result = -result;
18:      }
19:   
20:      // Set the first and second scale for the interpolation
21:      float scale0 = 1 - t;
22:      float scale1 = t;
23:   
24:      // Check if the angle between the 2 quaternions was big enough to
25:      // warrant such calculations
26:      if ((1 - result) > 0.1f) {// Get the angle between the 2 quaternions,
27:          // and then store the sin() of that angle
28:          float theta = FastMath.acos(result);
29:          float invSinTheta = 1f / FastMath.sin(theta);
30:   
31:          // Calculate the scale for q1 and q2, according to the angle and
32:          // it's sine value
33:          scale0 = FastMath.sin((1 - t) * theta) * invSinTheta;
34:          scale1 = FastMath.sin((t * theta)) * invSinTheta;
35:      }
36:   
37:      // Calculate the x, y, z and w values for the quaternion by using a
38:      // special
39:      // form of linear interpolation for quaternions.
40:      this.x = (scale0 * q1.x) + (scale1 * q2.x);
41:      this.y = (scale0 * q1.y) + (scale1 * q2.y);
42:      this.z = (scale0 * q1.z) + (scale1 * q2.z);
43:      this.w = (scale0 * q1.w) + (scale1 * q2.w);
44:   
45:      // Return the interpolated quaternion
46:      return this;
47:  }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值