Parcourir la source

Fixed Quaternion in the encoder.

Darryl Gough il y a 14 ans
Parent
commit
694bf6feae

+ 1 - 0
gameplay-encoder/gameplay-encoder.vcxproj

@@ -98,6 +98,7 @@
     <ClInclude Include="src\VertexElement.h" />
     <ClInclude Include="src\VertexElement.h" />
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
+    <None Include="src\Quaternion.inl" />
     <None Include="src\Vector2.inl" />
     <None Include="src\Vector2.inl" />
     <None Include="src\Vector3.inl" />
     <None Include="src\Vector3.inl" />
     <None Include="src\Vector4.inl" />
     <None Include="src\Vector4.inl" />

+ 3 - 0
gameplay-encoder/gameplay-encoder.vcxproj.filters

@@ -263,6 +263,9 @@
     <None Include="src\Vector4.inl">
     <None Include="src\Vector4.inl">
       <Filter>src</Filter>
       <Filter>src</Filter>
     </None>
     </None>
+    <None Include="src\Quaternion.inl">
+      <Filter>src</Filter>
+    </None>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <Filter Include="src">
     <Filter Include="src">

+ 81 - 37
gameplay-encoder/src/Quaternion.cpp

@@ -19,6 +19,10 @@ Quaternion::Quaternion(float* array)
     set(array);
     set(array);
 }
 }
 
 
+Quaternion::Quaternion(const Vector3& axis, float angle)
+{
+    set(axis, angle);
+}
 
 
 Quaternion::Quaternion(const Quaternion& copy)
 Quaternion::Quaternion(const Quaternion& copy)
 {
 {
@@ -31,14 +35,14 @@ Quaternion::~Quaternion()
 
 
 const Quaternion& Quaternion::identity()
 const Quaternion& Quaternion::identity()
 {
 {
-    static Quaternion* value = new Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
-    return *value;
+    static Quaternion value(0.0f, 0.0f, 0.0f, 1.0f);
+    return value;
 }
 }
 
 
 const Quaternion& Quaternion::zero()
 const Quaternion& Quaternion::zero()
 {
 {
-    static Quaternion* value = new Quaternion(0.0f, 0.0f, 0.0f, 0.0f);
-    return *value;
+    static Quaternion value(0.0f, 0.0f, 0.0f, 0.0f);
+    return value;
 }
 }
 
 
 bool Quaternion::isIdentity() const
 bool Quaternion::isIdentity() const
@@ -51,13 +55,6 @@ bool Quaternion::isZero() const
     return x == 0.0f && y == 0.0f && z == 0.0f && z == 0.0f;
     return x == 0.0f && y == 0.0f && z == 0.0f && z == 0.0f;
 }
 }
 
 
-void Quaternion::createFromRotationMatrix(const Matrix& m, Quaternion* dst)
-{
-    assert(dst);
-
-    m.decompose(NULL, dst, NULL);
-}
-
 void Quaternion::createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst)
 void Quaternion::createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst)
 {
 {
     assert(dst);
     assert(dst);
@@ -154,12 +151,12 @@ void Quaternion::normalize(Quaternion* dst) const
 
 
     float n = x * x + y * y + z * z + w * w;
     float n = x * x + y * y + z * z + w * w;
 
 
-    // already normalized
+    // Already normalized.
     if (n == 1.0f)
     if (n == 1.0f)
         return;
         return;
 
 
     n = sqrt(n);
     n = sqrt(n);
-    // too close to zero
+    // Too close to zero.
     if (n < 0.000001f)
     if (n < 0.000001f)
         return;
         return;
 
 
@@ -188,6 +185,11 @@ void Quaternion::set(float* array)
     w = array[3];
     w = array[3];
 }
 }
 
 
+void Quaternion::set(const Vector3& axis, float angle)
+{
+    Quaternion::createFromAxisAngle(axis, angle, this);
+}
+
 void Quaternion::set(const Quaternion& q)
 void Quaternion::set(const Quaternion& q)
 {
 {
     this->x = q.x;
     this->x = q.x;
@@ -223,6 +225,17 @@ void Quaternion::lerp(const Quaternion& q1, const Quaternion& q2, float t, Quate
     assert(dst);
     assert(dst);
     assert(!(t < 0.0f || t > 1.0f));
     assert(!(t < 0.0f || t > 1.0f));
 
 
+    if (t == 0.0f)
+    {
+        memcpy(dst, &q1, sizeof(float) * 4);
+        return;
+    }
+    else if (t == 1.0f)
+    {
+        memcpy(dst, &q2, sizeof(float) * 4);
+        return;
+    }
+
     float t1 = 1.0f - t;
     float t1 = 1.0f - t;
 
 
     dst->x = t1 * q1.x + t * q2.x;
     dst->x = t1 * q1.x + t * q2.x;
@@ -232,21 +245,65 @@ void Quaternion::lerp(const Quaternion& q1, const Quaternion& q2, float t, Quate
 }
 }
 
 
 void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
 void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
+{
+    slerp(q1.x, q1.y, q1.z, q1.w, q2.x, q2.y, q2.z, q2.w, t, &dst->x, &dst->y, &dst->z, &dst->w);
+}
+
+void Quaternion::squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst)
+{
+    assert(dst);
+    assert(!(t < 0.0f || t > 1.0f));
+
+    Quaternion dstQ(0.0f, 0.0f, 0.0f, 1.0f);
+    Quaternion dstS(0.0f, 0.0f, 0.0f, 1.0f);
+
+    slerpForSquad(q1, q2, t, &dstQ);
+    slerpForSquad(s1, s2, t, &dstS);
+    slerpForSquad(dstQ, dstS, 2.0f * t * (1.0f - t), dst);
+}
+
+void Quaternion::slerp(float q1x, float q1y, float q1z, float q1w, float q2x, float q2y, float q2z, float q2w, float t, float* dstx, float* dsty, float* dstz, float* dstw)
 {
 {
     // Fast slerp implementation by kwhatmough:
     // Fast slerp implementation by kwhatmough:
     // It contains no division operations, no trig, no inverse trig
     // It contains no division operations, no trig, no inverse trig
     // and no sqrt. Not only does this code tolerate small constraint
     // and no sqrt. Not only does this code tolerate small constraint
     // errors in the input quaternions, it actually corrects for them.
     // errors in the input quaternions, it actually corrects for them.
-    assert(dst);
+    assert(dstx && dsty && dstz && dstw);
     assert(!(t < 0.0f || t > 1.0f));
     assert(!(t < 0.0f || t > 1.0f));
 
 
+    if (t == 0.0f)
+    {
+        *dstx = q1x;
+        *dsty = q1y;
+        *dstz = q1z;
+        *dstw = q1w;
+        return;
+    }
+    else if (t == 1.0f)
+    {
+        *dstx = q2x;
+        *dsty = q2y;
+        *dstz = q2z;
+        *dstw = q2w;
+        return;
+    }
+
+    if (q1x == q2x && q1y == q2y && q1z == q2z && q1w == q2w)
+    {
+        *dstx = q1x;
+        *dsty = q1y;
+        *dstz = q1z;
+        *dstw = q1w;
+        return;
+    }
+
     float halfY, alpha, beta;
     float halfY, alpha, beta;
     float u, f1, f2a, f2b;
     float u, f1, f2a, f2b;
     float ratio1, ratio2;
     float ratio1, ratio2;
     float halfSecHalfTheta, versHalfTheta;
     float halfSecHalfTheta, versHalfTheta;
     float sqNotU, sqU;
     float sqNotU, sqU;
 
 
-    float cosTheta = q1.w * q2.w + q1.x * q2.x + q1.y * q2.y + q1.z * q2.z;
+    float cosTheta = q1w * q2w + q1x * q2x + q1y * q2y + q1z * q2z;
 
 
     // As usual in all slerp implementations, we fold theta.
     // As usual in all slerp implementations, we fold theta.
     alpha = cosTheta >= 0 ? 1.0f : -1.0f;
     alpha = cosTheta >= 0 ? 1.0f : -1.0f;
@@ -287,34 +344,21 @@ void Quaternion::slerp(const Quaternion& q1, const Quaternion& q2, float t, Quat
     beta = f1 + f2b;
     beta = f1 + f2b;
 
 
     // Apply final coefficients to a and b as usual.
     // Apply final coefficients to a and b as usual.
-    float w = alpha * q1.w + beta * q2.w;
-    float x = alpha * q1.x + beta * q2.x;
-    float y = alpha * q1.y + beta * q2.y;
-    float z = alpha * q1.z + beta * q2.z;
+    float w = alpha * q1w + beta * q2w;
+    float x = alpha * q1x + beta * q2x;
+    float y = alpha * q1y + beta * q2y;
+    float z = alpha * q1z + beta * q2z;
 
 
     // This final adjustment to the quaternion's length corrects for
     // This final adjustment to the quaternion's length corrects for
-    // any small constraint error in the inputs q1 and q2. But as you
+    // any small constraint error in the inputs q1 and q2 But as you
     // can see, it comes at the cost of 9 additional multiplication
     // can see, it comes at the cost of 9 additional multiplication
     // operations. If this error-correcting feature is not required,
     // operations. If this error-correcting feature is not required,
     // the following code may be removed.
     // the following code may be removed.
     f1 = 1.5f - 0.5f * (w * w + x * x + y * y + z * z);
     f1 = 1.5f - 0.5f * (w * w + x * x + y * y + z * z);
-    dst->w = w * f1;
-    dst->x = x * f1;
-    dst->y = y * f1;
-    dst->z = z * f1;
-}
-
-void Quaternion::squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst)
-{
-    assert(dst);
-    assert(!(t < 0.0f || t > 1.0f));
-
-    Quaternion dstQ(0.0f, 0.0f, 0.0f, 1.0f);
-    Quaternion dstS(0.0f, 0.0f, 0.0f, 1.0f);
-
-    slerpForSquad(q1, q2, t, &dstQ);
-    slerpForSquad(s1, s2, t, &dstS);
-    slerpForSquad(dstQ, dstS, 2.0f * t * (1.0f - t), dst);
+    *dstw = w * f1;
+    *dstx = x * f1;
+    *dsty = y * f1;
+    *dstz = z * f1;
 }
 }
 
 
 void Quaternion::slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)
 void Quaternion::slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst)

+ 95 - 39
gameplay-encoder/src/Quaternion.h

@@ -20,41 +20,46 @@ class Matrix;
  * lerp (linear interpolation): the interpolation curve gives a straight line in quaternion space. It is simple and fast to compute. The only problem is that it does not provide constant angular velocity. Note that a constant velocity is not necessarily a requirement for a curve;
  * lerp (linear interpolation): the interpolation curve gives a straight line in quaternion space. It is simple and fast to compute. The only problem is that it does not provide constant angular velocity. Note that a constant velocity is not necessarily a requirement for a curve;
  * slerp (spherical linear interpolation): the interpolation curve forms a great arc on the quaternion unit sphere. Slerp provides constant angular velocity;
  * slerp (spherical linear interpolation): the interpolation curve forms a great arc on the quaternion unit sphere. Slerp provides constant angular velocity;
  * squad (spherical spline interpolation): interpolating between a series of rotations using slerp leads to the following problems:
  * squad (spherical spline interpolation): interpolating between a series of rotations using slerp leads to the following problems:
- * the curve is not smooth at the control points;
- * the angular velocity is not constant;
- * the angular velocity is not continuous at the control points.
+ * - the curve is not smooth at the control points;
+ * - the angular velocity is not constant;
+ * - the angular velocity is not continuous at the control points.
  *
  *
  * Since squad is continuously differentiable, it remedies the first and third problems mentioned above.
  * Since squad is continuously differentiable, it remedies the first and third problems mentioned above.
  * The slerp method provided here is intended for interpolation of principal rotations. It treats +q and -q as the same principal rotation and is at liberty to use the negative of either input. The resulting path is always the shorter arc.
  * The slerp method provided here is intended for interpolation of principal rotations. It treats +q and -q as the same principal rotation and is at liberty to use the negative of either input. The resulting path is always the shorter arc.
  *
  *
  * The lerp method provided here interpolates strictly in quaternion space. Note that the resulting path may pass through the origin if interpolating between a quaternion and its exact negative.
  * The lerp method provided here interpolates strictly in quaternion space. Note that the resulting path may pass through the origin if interpolating between a quaternion and its exact negative.
  *
  *
- * As an example, consider the following quaternions
+ * As an example, consider the following quaternions:
  *
  *
  * q1 = (0.6, 0.8, 0.0, 0.0),
  * q1 = (0.6, 0.8, 0.0, 0.0),
  * q2 = (0.0, 0.6, 0.8, 0.0),
  * q2 = (0.0, 0.6, 0.8, 0.0),
  * q3 = (0.6, 0.0, 0.8, 0.0), and
  * q3 = (0.6, 0.0, 0.8, 0.0), and
  * q4 = (-0.8, 0.0, -0.6, 0.0).
  * q4 = (-0.8, 0.0, -0.6, 0.0).
  * For the point p = (1.0, 1.0, 1.0), the following figures show the trajectories of p using lerp, slerp, and squad.
  * For the point p = (1.0, 1.0, 1.0), the following figures show the trajectories of p using lerp, slerp, and squad.
- *
- * @image "http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/math/doc-files/LERP.PNG"
- * @image "http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/math/doc-files/SLERP.PNG"
- * @image "http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/math/doc-files/SQUAD.PNG"
  */
  */
 class Quaternion
 class Quaternion
 {
 {
+    friend class Curve;
+
 public:
 public:
 
 
-    /** The x-value of the quaternion's vector component. */
+    /**
+     * The x-value of the quaternion's vector component.
+     */
     float x;
     float x;
-    /** The y-value of the quaternion's vector component. */
+    /**
+     * The y-value of the quaternion's vector component.
+     */
     float y;
     float y;
-    /** The z-value of the quaternion's vector component. */
+    /**
+     * The z-value of the quaternion's vector component.
+     */
     float z;
     float z;
-    /** The scalar component of the quaternion. */
+    /**
+     * The scalar component of the quaternion.
+     */
     float w;
     float w;
 
 
-
     /**
     /**
      * Constructs a quaternion initialized to (0, 0, 0, 1).
      * Constructs a quaternion initialized to (0, 0, 0, 1).
      */
      */
@@ -73,14 +78,22 @@ public:
     /**
     /**
      * Constructs a new quaternion from the values in the specified array.
      * Constructs a new quaternion from the values in the specified array.
      *
      *
-     * @param array
+     * @param array The values for the new quaternion.
      */
      */
     Quaternion(float* array);
     Quaternion(float* array);
 
 
+    /**
+     * Constructs a quaternion equal to the rotation from the specified axis and angle.
+     *
+     * @param axis A vector describing the axis of rotation.
+     * @param angle The angle of rotation (in radians).
+     */
+    Quaternion(const Vector3& axis, float angle);
+
     /**
     /**
      * Constructs a new quaternion that is a copy of the specified one.
      * Constructs a new quaternion that is a copy of the specified one.
      *
      *
-     * @param copy The quaternion to copy
+     * @param copy The quaternion to copy.
      */
      */
     Quaternion(const Quaternion& copy);
     Quaternion(const Quaternion& copy);
 
 
@@ -92,7 +105,7 @@ public:
     /**
     /**
      * Returns the identity quaternion.
      * Returns the identity quaternion.
      *
      *
-     * @return The quaternion.
+     * @return The identity quaternion.
      */
      */
     static const Quaternion& identity();
     static const Quaternion& identity();
 
 
@@ -104,34 +117,25 @@ public:
     static const Quaternion& zero();
     static const Quaternion& zero();
 
 
     /**
     /**
-     * Determines if this quaterion is equal to the identity quaternion.
+     * Determines if this quaternion is equal to the identity quaternion.
      *
      *
-     * @return true if the identity, false otherwise.
+     * @return true if it is the identity quaternion, false otherwise.
      */
      */
     bool isIdentity() const;
     bool isIdentity() const;
 
 
     /**
     /**
-     * Determines if this quaterion is all zeros.
+     * Determines if this quaternion is all zeros.
      *
      *
-     * @return true if zeros, false otherwise.
+     * @return true if this quaternion is all zeros, false otherwise.
      */
      */
     bool isZero() const;
     bool isZero() const;
 
 
-    /**
-     * Create a quaternion equal to the rotational part of the specified matrix
-     * and stores the result in dst.
-     *
-     * @param m The matrix.
-     * @param dst A quaternion to store the conjugate in.
-     */
-    static void createFromRotationMatrix(const Matrix& m, Quaternion* dst);
-
     /**
     /**
      * Creates this quaternion equal to the rotation from the specified axis and angle
      * Creates this quaternion equal to the rotation from the specified axis and angle
-     * and store the result in dst.
+     * and stores the result in dst.
      *
      *
      * @param axis A vector describing the axis of rotation.
      * @param axis A vector describing the axis of rotation.
-     * @param angle The angle of rotation, in radians.
+     * @param angle The angle of rotation (in radians).
      * @param dst A quaternion to store the conjugate in.
      * @param dst A quaternion to store the conjugate in.
      */
      */
     static void createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst);
     static void createFromAxisAngle(const Vector3& axis, float angle, Quaternion* dst);
@@ -226,6 +230,14 @@ public:
      */
      */
     void set(float* array);
     void set(float* array);
 
 
+    /**
+     * Sets the quaternion equal to the rotation from the specified axis and angle.
+     * 
+     * @param axis The axis of rotation.
+     * @param angle The angle of rotation (in radians).
+     */
+    void set(const Vector3& axis, float angle);
+
     /**
     /**
      * Sets the elements of this quaternion to a copy of the specified quaternion.
      * Sets the elements of this quaternion to a copy of the specified quaternion.
      *
      *
@@ -256,10 +268,10 @@ public:
      * @param q1 The first quaternion.
      * @param q1 The first quaternion.
      * @param q2 The second quaternion.
      * @param q2 The second quaternion.
      * @param t The interpolation coefficient.
      * @param t The interpolation coefficient.
-     * @param dst A quaternion to store the result in
+     * @param dst A quaternion to store the result in.
      */
      */
     static void lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
     static void lerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
-
+    
     /**
     /**
      * Interpolates between two quaternions using spherical linear interpolation.
      * Interpolates between two quaternions using spherical linear interpolation.
      *
      *
@@ -273,10 +285,10 @@ public:
      * @param q1 The first quaternion.
      * @param q1 The first quaternion.
      * @param q2 The second quaternion.
      * @param q2 The second quaternion.
      * @param t The interpolation coefficient.
      * @param t The interpolation coefficient.
-     * @param dst A quaternion to store the result in
+     * @param dst A quaternion to store the result in.
      */
      */
     static void slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
     static void slerp(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
-
+    
     /**
     /**
      * Interpolates over a series of quaternions using spherical spline interpolation.
      * Interpolates over a series of quaternions using spherical spline interpolation.
      *
      *
@@ -289,20 +301,64 @@ public:
      *
      *
      * @param q1 The first quaternion.
      * @param q1 The first quaternion.
      * @param q2 The second quaternion.
      * @param q2 The second quaternion.
-     * @param s1 The first control point
-     * @param s2 The second control point
+     * @param s1 The first control point.
+     * @param s2 The second control point.
      * @param t The interpolation coefficient.
      * @param t The interpolation coefficient.
-     * @param dst A quaternion to store the result in
+     * @param dst A quaternion to store the result in.
      */
      */
     static void squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst);
     static void squad(const Quaternion& q1, const Quaternion& q2, const Quaternion& s1, const Quaternion& s2, float t, Quaternion* dst);
 
 
+    /**
+     * Calculates the quaternion product of this quaternion with the given quaternion.
+     * 
+     * Note: this does not modify this quaternion.
+     * 
+     * @param q The quaternion to multiply.
+     * @return The quaternion product.
+     */
+    inline Quaternion operator*(const Quaternion& q) const;
+
+    /**
+     * Multiplies this quaternion with the given quaternion.
+     * 
+     * @param q The quaternion to multiply.
+     * @return This quaternion, after the multiplication occurs.
+     */
+    inline Quaternion& operator*=(const Quaternion& q);
 
 
 private:
 private:
 
 
-    static void slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
+    /**
+     * Interpolates between two quaternions using spherical linear interpolation.
+     *
+     * Spherical linear interpolation provides smooth transitions between different
+     * orientations and is often useful for animating models or cameras in 3D.
+     *
+     * Note: For accurate interpolation, the input quaternions must be at (or close to) unit length.
+     * This method does not automatically normalize the input quaternions, so it is up to the
+     * caller to ensure they call normalize beforehand, if necessary.
+     *
+     * @param q1x The x component of the first quaternion.
+     * @param q1y The y component of the first quaternion.
+     * @param q1z The z component of the first quaternion.
+     * @param q1w The w component of the first quaternion.
+     * @param q2x The x component of the second quaternion.
+     * @param q2y The y component of the second quaternion.
+     * @param q2z The z component of the second quaternion.
+     * @param q2w The w component of the second quaternion.
+     * @param t The interpolation coefficient.
+     * @param dstx A pointer to store the x component of the slerp in.
+     * @param dsty A pointer to store the y component of the slerp in.
+     * @param dstz A pointer to store the z component of the slerp in.
+     * @param dstw A pointer to store the w component of the slerp in.
+     */
+    static void slerp(float q1x, float q1y, float q1z, float q1w, float q2x, float q2y, float q2z, float q2w, float t, float* dstx, float* dsty, float* dstz, float* dstw);
 
 
+    static void slerpForSquad(const Quaternion& q1, const Quaternion& q2, float t, Quaternion* dst);
 };
 };
 
 
 }
 }
 
 
+#include "Quaternion.inl"
+
 #endif
 #endif

+ 19 - 0
gameplay-encoder/src/Quaternion.inl

@@ -0,0 +1,19 @@
+#include "Quaternion.h"
+
+namespace gameplay
+{
+
+inline Quaternion Quaternion::operator*(const Quaternion& q) const
+{
+    Quaternion result(*this);
+    result.multiply(q);
+    return result;
+}
+
+inline Quaternion& Quaternion::operator*=(const Quaternion& q)
+{
+    multiply(q);
+    return *this;
+}
+
+}