Преглед изворни кода

Fixes #671: Implements missing Matrix methods for billboard and reflection.

Ken Whatmough пре 13 година
родитељ
комит
b483ccd466
2 измењених фајлова са 119 додато и 23 уклоњено
  1. 66 0
      gameplay/src/Matrix.cpp
  2. 53 23
      gameplay/src/Matrix.h

+ 66 - 0
gameplay/src/Matrix.cpp

@@ -1,5 +1,6 @@
 #include "Base.h"
 #include "Matrix.h"
+#include "Plane.h"
 #include "Quaternion.h"
 #include "MathUtil.h"
 
@@ -164,6 +165,71 @@ void Matrix::createOrthographicOffCenter(float left, float right, float bottom,
     dst->m[14] = (-(zFarPlane + zNearPlane)) * f_n;
     dst->m[15] = 1.0f;
 }
+    
+void Matrix::createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                             const Vector3& cameraUpVector, Matrix* dst)
+{
+    createBillboardHelper(objectPosition, cameraPosition, cameraUpVector, NULL, dst);
+}
+
+void Matrix::createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                             const Vector3& cameraUpVector, const Vector3& cameraForwardVector,
+                             Matrix* dst)
+{
+    createBillboardHelper(objectPosition, cameraPosition, cameraUpVector, &cameraForwardVector, dst);
+}
+
+void Matrix::createBillboardHelper(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                   const Vector3& cameraUpVector, const Vector3* cameraForwardVector,
+                                   Matrix* dst)
+{
+    Vector3 delta(objectPosition, cameraPosition);
+    bool isSufficientDelta = delta.lengthSquared() > MATH_EPSILON;
+
+    dst->setIdentity();
+    dst->m[3] = objectPosition.x;
+    dst->m[7] = objectPosition.y;
+    dst->m[11] = objectPosition.z;
+
+    // As per the contracts for the 2 variants of createBillboard, we need
+    // either a safe default or a sufficient distance between object and camera.
+    if (cameraForwardVector || isSufficientDelta)
+    {
+        Vector3 target = isSufficientDelta ? cameraPosition : (objectPosition - *cameraForwardVector);
+
+        // A billboard is the inverse of a lookAt rotation
+        Matrix lookAt;
+        createLookAt(objectPosition, target, cameraUpVector, &lookAt);
+        dst->m[0] = lookAt.m[0];
+        dst->m[1] = lookAt.m[4];
+        dst->m[2] = lookAt.m[8];
+        dst->m[4] = lookAt.m[1];
+        dst->m[5] = lookAt.m[5];
+        dst->m[6] = lookAt.m[9];
+        dst->m[8] = lookAt.m[2];
+        dst->m[9] = lookAt.m[6];
+        dst->m[10] = lookAt.m[10];
+    }
+}
+    
+void Matrix::createReflection(const Plane& plane, Matrix* dst)
+{
+    Vector3 normal(plane.getNormal());
+    float k = -2.0f * plane.getDistance();
+
+    dst->setIdentity();
+
+    dst->m[0] -= 2.0f * normal.x * normal.x;
+    dst->m[5] -= 2.0f * normal.y * normal.y;
+    dst->m[10] -= 2.0f * normal.z * normal.z;
+    dst->m[1] = dst->m[4] = -2.0f * normal.x * normal.y;
+    dst->m[2] = dst->m[8] = -2.0f * normal.x * normal.z;
+    dst->m[6] = dst->m[9] = -2.0f * normal.y * normal.z;
+    
+    dst->m[3] = k * normal.x;
+    dst->m[7] = k * normal.y;
+    dst->m[11] = k * normal.z;
+}
 
 void Matrix::createScale(const Vector3& scale, Matrix* dst)
 {

+ 53 - 23
gameplay/src/Matrix.h

@@ -7,6 +7,8 @@
 namespace gameplay
 {
 
+class Plane;
+
 /**
  * Defines a 4 x 4 floating point matrix representing a 3D transformation.
  *
@@ -211,29 +213,51 @@ public:
     static void createOrthographicOffCenter(float left, float right, float bottom, float top,
                                             float zNearPlane, float zFarPlane, Matrix* dst);
 
-//    /*
-//     * Creates a spherical billboard that rotates around a specified object position.
-//     *
-//     * This method computes the facing direction of the billboard from the object position
-//     * and camera position. When the object and camera positions are too close, the matrix
-//     * will not be accurate. To avoid this problem, the method uses the optional camera
-//     * forward vector if the positions are too close.
-//     *
-//     * @param objectPosition The position of the object the billboard will rotate around.
-//     * @param cameraPosition The position of the camera.
-//     * @param cameraUpVector The up vector of the camera.
-//     * @param dst A matrix to store the result in.
-//     */
-//    static void createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
-//                                const Vector3& cameraUpVector, Matrix* dst);
-//
-//    /*
-//     * Fills in an existing Matrix so that it reflects the coordinate system about a specified Plane.
-//     *
-//     * @param plane The Plane about which to create a reflection.
-//     * @param dst A matrix to store the result in.
-//     */
-//    static void createReflection(const Plane& plane, Matrix* dst);
+    /*
+     * Creates a spherical billboard that rotates around a specified object position.
+     *
+     * This method computes the facing direction of the billboard from the object position
+     * and camera position. When the object and camera positions are too close, the matrix
+     * will not be accurate. To avoid this problem, this method defaults to the identity
+     * rotation if the positions are too close. (See the other overload of createBillboard
+     * for an alternative approach).
+     *
+     * @param objectPosition The position of the object the billboard will rotate around.
+     * @param cameraPosition The position of the camera.
+     * @param cameraUpVector The up vector of the camera.
+     * @param dst A matrix to store the result in.
+     */
+    static void createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                const Vector3& cameraUpVector, Matrix* dst);
+
+    /*
+     * Creates a spherical billboard that rotates around a specified object position with
+     * provision for a safe default orientation.
+     *
+     * This method computes the facing direction of the billboard from the object position
+     * and camera position. When the object and camera positions are too close, the matrix
+     * will not be accurate. To avoid this problem, this method uses the specified camera
+     * forward vector if the positions are too close. (See the other overload of createBillboard
+     * for an alternative approach).
+     *
+     * @param objectPosition The position of the object the billboard will rotate around.
+     * @param cameraPosition The position of the camera.
+     * @param cameraUpVector The up vector of the camera.
+     * @param cameraForwardVector The forward vector of the camera, used if the positions
+     *                            are too close.
+     * @param dst A matrix to store the result in.
+     */
+    static void createBillboard(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                const Vector3& cameraUpVector, const Vector3& cameraForwardVector,
+                                Matrix* dst);
+
+    /*
+     * Fills in an existing Matrix so that it reflects the coordinate system about a specified Plane.
+     *
+     * @param plane The Plane about which to create a reflection.
+     * @param dst A matrix to store the result in.
+     */
+    static void createReflection(const Plane& plane, Matrix* dst);
 
     /**
      * Creates a scale matrix.
@@ -887,6 +911,12 @@ public:
      * @return This matrix, after the multiplication occurs.
      */
     inline Matrix& operator*=(const Matrix& m);
+    
+private:
+
+    static void createBillboardHelper(const Vector3& objectPosition, const Vector3& cameraPosition,
+                                      const Vector3& cameraUpVector, const Vector3* cameraForwardVector,
+                                      Matrix* dst);
 };
 
 /**