quaternion.adoc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. = Quaternion
  2. :revnumber: 2.0
  3. :revdate: 2020/07/15
  4. == Quaternion
  5. See link:{link-javadoc}/com/jme3/math/Quaternion.html[Javadoc]
  6. === Definition
  7. Quaternions define a subset of a hypercomplex number system. Quaternions are defined by (i^2^ = j^2^ = k^2^ = ijk = -1). jME makes use of Quaternions because they allow for compact representations of rotations, or correspondingly, orientations, in 3D space. With only four float values, we can represent an object's orientation, where a rotation matrix would require nine. They also require fewer arithmetic operations for concatenation.
  8. Additional benefits of the Quaternion is reducing the chance of link:http://en.wikipedia.org/wiki/Gimbal_lock[Gimbal Lock] and allowing for easily interpolation between two rotations (spherical linear interpolation or slerp).
  9. While Quaternions are quite difficult to fully understand, there are an exceeding number of convenience methods to allow you to use them without having to understand the math behind it. Basically, these methods involve nothing more than setting the Quaternion's x,y,z,w values using other means of representing rotations. The Quaternion is then contained in xref:scene/spatial.adoc[Spatial] as its local rotation component.
  10. Quaternion *q* has the form
  11. *q* = <_w,x,y,z_> = _w + xi + yj + zk_
  12. or alternatively, it can be written as:
  13. *q* = *s* + *v*, where *s* represents the scalar part corresponding to the w-component of *q*, and *v* represents the vector part of the (x, y, z) components of *q*.
  14. Multiplication of Quaternions uses the distributive law and adheres to the following rules with multiplying the imaginary components (i, j, k):
  15. `i^2^ = j^2^ = k^2^ = -1`+
  16. `ij = -ji = k`+
  17. `jk = -kj = i`+
  18. `ki = -ik = j`
  19. However, Quaternion multiplication is _not_ commutative, so we have to pay attention to order.
  20. *q~1~q~2~* = s~1~s~2~ - *v~1~* dot *v~2~* + s~1~*v~2~* + s~2~*v~1~* + *v~1~* X *v~2~*
  21. Quaternions also have conjugates where the conjugate of *q* is (s - *v*)
  22. These basic operations allow us to convert various rotation representations to Quaternions.
  23. === Angle Axis
  24. You might wish to represent your rotations as Angle Axis pairs. That is, you define a axis of rotation and the angle with which to rotate about this axis. Quaternion defines a method `fromAngleAxis` (and `fromAngleNormalAxis`) to create a Quaternion from this pair. This is actually used quite a bit in jME demos to continually rotate objects. You can also obtain a Angle Axis rotation from an existing Quaternion using `toAngleAxis`.
  25. ==== Example - Rotate a Spatial Using fromAngleAxis
  26. [source,java]
  27. ----
  28. //rotate about the Y-Axis by approximately 1 pi
  29. Vector3f axis = Vector3f.UNIT_Y; // this equals (0, 1, 0) and does not require to create a new object
  30. float angle = 3.14f;
  31. s.getLocalRotation().fromAngleAxis(angle, axis);
  32. ----
  33. === Three Angles
  34. You can also represent a rotation by defining three angles. The angles represent the rotation about the individual axes. Passing in a three-element array of floats defines the angles where the first element is X, second Y and third is Z. The method provided by Quaternion is `fromAngles` and can also fill an array using `toAngles`
  35. ==== Example - Rotate a Spatial Using fromAngles
  36. [source,java]
  37. ----
  38. //rotate 1 radian on the x, 3 on the y and 0 on z
  39. float[] angles = {1, 3, 0};
  40. s.getLocalRotation().fromAngles(angles);
  41. ----
  42. === Three Axes
  43. If you have three axes that define your rotation, where the axes define the left axis, up axis and directional axis respectively) you can make use of `fromAxes` to generate the Quaternion. It should be noted that this will generate a new xref:math/matrix.adoc[Matrix] object that is then garbage collected, thus, this method should not be used if it will be called many times. Again, `toAxes` will populate a <<tutorials:concepts/terminology.adoc#vectors,Vector3f>> array.
  44. ==== Example - Rotate a Spatial Using fromAxes
  45. [source,java]
  46. ----
  47. //rotate a spatial to face up ~45 degrees
  48. Vector3f[] axes = new Vector3f[3];
  49. axes[0] = new Vector3f(-1, 0, 0); //left
  50. axes[1] = new Vector3f(0, 0.5f, 0.5f); //up
  51. axes[2] = new Vector3f(0, 0.5f, 0.5f); //dir
  52. s.getLocalRotation().fromAxes(axes);
  53. ----
  54. === Rotation Matrix
  55. Commonly you might find yourself with a xref:math/matrix.adoc[Matrix] defining a xref:tutorials:concepts/rotate.adoc[rotation]. In fact, it's very common to contain a rotation in a Matrix, create a Quaternion, rotate the Quaternion, and then get the Matrix back. Quaternion contains a `fromRotationMatrix` method that will create the appropriate Quaternion based on the given Matrix. The `toRotationMatrix` will populate a given Matrix.
  56. ==== Example - Rotate a Spatial Using a Rotation Matrix
  57. [source,java]
  58. ----
  59. Matrix3f mat = new Matrix3f();
  60. mat.setColumn(0, new Vector3f(1,0,0));
  61. mat.setColumn(1, new Vector3f(0,-1,0));
  62. mat.setColumn(2, new Vector3f(0,0,1));
  63. s.getLocalRotation().fromRotationMatrix(mat);
  64. ----
  65. As you can see there are many ways to build a Quaternion. This allows you to work with rotations in a way that is conceptually easier to picture, but still build Quaternions for internal representation.
  66. === Slerp
  67. One of the biggest advantages to using Quaternions is allowing interpolation between two rotations. That is, if you have an initial Quaternion representing the original orientation of an object, and you have a final Quaternion representing the orientation you want the object to face, you can do this very smoothly with slerp. Simply supply the time, where time is [0, 1] and 0 is the initial rotation and 1 is the final rotation.
  68. ==== Example - Use Slerp to Rotate Between two Quaternions
  69. [source,java]
  70. ----
  71. Quaternion q1;
  72. Quaternion q2;
  73. //the rotation half-way between these two
  74. Quaternion q3 = q1.slerp(q2, 0.5f);
  75. ----
  76. ---
  77. * See xref:tutorials:concepts/rotate.adoc[3D-Rotations] for troubleshooting and extra information on using quaternions.