123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Matrix.h>
- #include <Mathematics/Vector4.h>
- namespace WwiseGTE
- {
- // Template alias for convenience.
- template <typename Real>
- using Matrix4x4 = Matrix<4, 4, Real>;
- // Geometric operations.
- template <typename Real>
- Matrix4x4<Real> Inverse(Matrix4x4<Real> const& M, bool* reportInvertibility = nullptr)
- {
- Matrix4x4<Real> inverse;
- bool invertible;
- Real a0 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0);
- Real a1 = M(0, 0) * M(1, 2) - M(0, 2) * M(1, 0);
- Real a2 = M(0, 0) * M(1, 3) - M(0, 3) * M(1, 0);
- Real a3 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1);
- Real a4 = M(0, 1) * M(1, 3) - M(0, 3) * M(1, 1);
- Real a5 = M(0, 2) * M(1, 3) - M(0, 3) * M(1, 2);
- Real b0 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0);
- Real b1 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0);
- Real b2 = M(2, 0) * M(3, 3) - M(2, 3) * M(3, 0);
- Real b3 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1);
- Real b4 = M(2, 1) * M(3, 3) - M(2, 3) * M(3, 1);
- Real b5 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2);
- Real det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
- if (det != (Real)0)
- {
- Real invDet = (Real)1 / det;
- inverse = Matrix4x4<Real>
- {
- (+M(1, 1) * b5 - M(1, 2) * b4 + M(1, 3) * b3) * invDet,
- (-M(0, 1) * b5 + M(0, 2) * b4 - M(0, 3) * b3) * invDet,
- (+M(3, 1) * a5 - M(3, 2) * a4 + M(3, 3) * a3) * invDet,
- (-M(2, 1) * a5 + M(2, 2) * a4 - M(2, 3) * a3) * invDet,
- (-M(1, 0) * b5 + M(1, 2) * b2 - M(1, 3) * b1) * invDet,
- (+M(0, 0) * b5 - M(0, 2) * b2 + M(0, 3) * b1) * invDet,
- (-M(3, 0) * a5 + M(3, 2) * a2 - M(3, 3) * a1) * invDet,
- (+M(2, 0) * a5 - M(2, 2) * a2 + M(2, 3) * a1) * invDet,
- (+M(1, 0) * b4 - M(1, 1) * b2 + M(1, 3) * b0) * invDet,
- (-M(0, 0) * b4 + M(0, 1) * b2 - M(0, 3) * b0) * invDet,
- (+M(3, 0) * a4 - M(3, 1) * a2 + M(3, 3) * a0) * invDet,
- (-M(2, 0) * a4 + M(2, 1) * a2 - M(2, 3) * a0) * invDet,
- (-M(1, 0) * b3 + M(1, 1) * b1 - M(1, 2) * b0) * invDet,
- (+M(0, 0) * b3 - M(0, 1) * b1 + M(0, 2) * b0) * invDet,
- (-M(3, 0) * a3 + M(3, 1) * a1 - M(3, 2) * a0) * invDet,
- (+M(2, 0) * a3 - M(2, 1) * a1 + M(2, 2) * a0) * invDet
- };
- invertible = true;
- }
- else
- {
- inverse.MakeZero();
- invertible = false;
- }
- if (reportInvertibility)
- {
- *reportInvertibility = invertible;
- }
- return inverse;
- }
- template <typename Real>
- Matrix4x4<Real> Adjoint(Matrix4x4<Real> const& M)
- {
- Real a0 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0);
- Real a1 = M(0, 0) * M(1, 2) - M(0, 2) * M(1, 0);
- Real a2 = M(0, 0) * M(1, 3) - M(0, 3) * M(1, 0);
- Real a3 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1);
- Real a4 = M(0, 1) * M(1, 3) - M(0, 3) * M(1, 1);
- Real a5 = M(0, 2) * M(1, 3) - M(0, 3) * M(1, 2);
- Real b0 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0);
- Real b1 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0);
- Real b2 = M(2, 0) * M(3, 3) - M(2, 3) * M(3, 0);
- Real b3 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1);
- Real b4 = M(2, 1) * M(3, 3) - M(2, 3) * M(3, 1);
- Real b5 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2);
- return Matrix4x4<Real>
- {
- +M(1, 1) * b5 - M(1, 2) * b4 + M(1, 3) * b3,
- -M(0, 1) * b5 + M(0, 2) * b4 - M(0, 3) * b3,
- +M(3, 1) * a5 - M(3, 2) * a4 + M(3, 3) * a3,
- -M(2, 1) * a5 + M(2, 2) * a4 - M(2, 3) * a3,
- -M(1, 0) * b5 + M(1, 2) * b2 - M(1, 3) * b1,
- +M(0, 0) * b5 - M(0, 2) * b2 + M(0, 3) * b1,
- -M(3, 0) * a5 + M(3, 2) * a2 - M(3, 3) * a1,
- +M(2, 0) * a5 - M(2, 2) * a2 + M(2, 3) * a1,
- +M(1, 0) * b4 - M(1, 1) * b2 + M(1, 3) * b0,
- -M(0, 0) * b4 + M(0, 1) * b2 - M(0, 3) * b0,
- +M(3, 0) * a4 - M(3, 1) * a2 + M(3, 3) * a0,
- -M(2, 0) * a4 + M(2, 1) * a2 - M(2, 3) * a0,
- -M(1, 0) * b3 + M(1, 1) * b1 - M(1, 2) * b0,
- +M(0, 0) * b3 - M(0, 1) * b1 + M(0, 2) * b0,
- -M(3, 0) * a3 + M(3, 1) * a1 - M(3, 2) * a0,
- +M(2, 0) * a3 - M(2, 1) * a1 + M(2, 2) * a0
- };
- }
- template <typename Real>
- Real Determinant(Matrix4x4<Real> const& M)
- {
- Real a0 = M(0, 0) * M(1, 1) - M(0, 1) * M(1, 0);
- Real a1 = M(0, 0) * M(1, 2) - M(0, 2) * M(1, 0);
- Real a2 = M(0, 0) * M(1, 3) - M(0, 3) * M(1, 0);
- Real a3 = M(0, 1) * M(1, 2) - M(0, 2) * M(1, 1);
- Real a4 = M(0, 1) * M(1, 3) - M(0, 3) * M(1, 1);
- Real a5 = M(0, 2) * M(1, 3) - M(0, 3) * M(1, 2);
- Real b0 = M(2, 0) * M(3, 1) - M(2, 1) * M(3, 0);
- Real b1 = M(2, 0) * M(3, 2) - M(2, 2) * M(3, 0);
- Real b2 = M(2, 0) * M(3, 3) - M(2, 3) * M(3, 0);
- Real b3 = M(2, 1) * M(3, 2) - M(2, 2) * M(3, 1);
- Real b4 = M(2, 1) * M(3, 3) - M(2, 3) * M(3, 1);
- Real b5 = M(2, 2) * M(3, 3) - M(2, 3) * M(3, 2);
- Real det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
- return det;
- }
- template <typename Real>
- Real Trace(Matrix4x4<Real> const& M)
- {
- Real trace = M(0, 0) + M(1, 1) + M(2, 2) + M(3, 3);
- return trace;
- }
- // Multiply M and V according to the user-selected convention. If it is
- // GTE_USE_MAT_VEC, the function returns M*V. If it is GTE_USE_VEC_MAT,
- // the function returns V*M. This function is provided to hide the
- // preprocessor symbols in the GTEngine sample applications.
- template <typename Real>
- Vector4<Real> DoTransform(Matrix4x4<Real> const& M, Vector4<Real> const& V)
- {
- #if defined(GTE_USE_MAT_VEC)
- return M * V;
- #else
- return V * M;
- #endif
- }
- template <typename Real>
- Matrix4x4<Real> DoTransform(Matrix4x4<Real> const& A, Matrix4x4<Real> const& B)
- {
- #if defined(GTE_USE_MAT_VEC)
- return A * B;
- #else
- return B * A;
- #endif
- }
- // For GTE_USE_MAT_VEC, the columns of an invertible matrix form a basis
- // for the range of the matrix. For GTE_USE_VEC_MAT, the rows of an
- // invertible matrix form a basis for the range of the matrix. These
- // functions allow you to access the basis vectors. The caller is
- // responsible for ensuring that the matrix is invertible (although the
- // inverse is not calculated by these functions).
- template <typename Real>
- void SetBasis(Matrix4x4<Real>& M, int i, Vector4<Real> const& V)
- {
- #if defined(GTE_USE_MAT_VEC)
- return M.SetCol(i, V);
- #else
- return M.SetRow(i, V);
- #endif
- }
- template <typename Real>
- Vector4<Real> GetBasis(Matrix4x4<Real> const& M, int i)
- {
- #if defined(GTE_USE_MAT_VEC)
- return M.GetCol(i);
- #else
- return M.GetRow(i);
- #endif
- }
- // Special matrices. In the comments, the matrices are shown using the
- // GTE_USE_MAT_VEC multiplication convention.
- // The projection plane is Dot(N,X-P) = 0 where N is a 3-by-1 unit-length
- // normal vector and P is a 3-by-1 point on the plane. The projection is
- // oblique to the plane, in the direction of the 3-by-1 vector D.
- // Necessarily Dot(N,D) is not zero for this projection to make sense.
- // Given a 3-by-1 point U, compute the intersection of the line U+t*D with
- // the plane to obtain t = -Dot(N,U-P)/Dot(N,D); then
- //
- // projection(U) = P + [I - D*N^T/Dot(N,D)]*(U-P)
- //
- // A 4-by-4 homogeneous transformation representing the projection is
- //
- // +- -+
- // M = | D*N^T - Dot(N,D)*I -Dot(N,P)D |
- // | 0^T -Dot(N,D) |
- // +- -+
- //
- // where M applies to [U^T 1]^T by M*[U^T 1]^T. The matrix is chosen so
- // that M[3][3] > 0 whenever Dot(N,D) < 0; the projection is onto the
- // "positive side" of the plane.
- template <typename Real>
- Matrix4x4<Real> MakeObliqueProjection(Vector4<Real> const& origin,
- Vector4<Real> const& normal, Vector4<Real> const& direction)
- {
- Matrix4x4<Real> M;
- Real const zero = (Real)0;
- Real dotND = Dot(normal, direction);
- Real dotNO = Dot(origin, normal);
- #if defined(GTE_USE_MAT_VEC)
- M(0, 0) = direction[0] * normal[0] - dotND;
- M(0, 1) = direction[0] * normal[1];
- M(0, 2) = direction[0] * normal[2];
- M(0, 3) = -dotNO * direction[0];
- M(1, 0) = direction[1] * normal[0];
- M(1, 1) = direction[1] * normal[1] - dotND;
- M(1, 2) = direction[1] * normal[2];
- M(1, 3) = -dotNO * direction[1];
- M(2, 0) = direction[2] * normal[0];
- M(2, 1) = direction[2] * normal[1];
- M(2, 2) = direction[2] * normal[2] - dotND;
- M(2, 3) = -dotNO * direction[2];
- M(3, 0) = zero;
- M(3, 1) = zero;
- M(3, 2) = zero;
- M(3, 3) = -dotND;
- #else
- M(0, 0) = direction[0] * normal[0] - dotND;
- M(1, 0) = direction[0] * normal[1];
- M(2, 0) = direction[0] * normal[2];
- M(3, 0) = -dotNO * direction[0];
- M(0, 1) = direction[1] * normal[0];
- M(1, 1) = direction[1] * normal[1] - dotND;
- M(2, 1) = direction[1] * normal[2];
- M(3, 1) = -dotNO * direction[1];
- M(0, 2) = direction[2] * normal[0];
- M(1, 2) = direction[2] * normal[1];
- M(2, 2) = direction[2] * normal[2] - dotND;
- M(3, 2) = -dotNO * direction[2];
- M(0, 2) = zero;
- M(1, 3) = zero;
- M(2, 3) = zero;
- M(3, 3) = -dotND;
- #endif
- return M;
- }
- // The perspective projection of a point onto a plane is
- //
- // +- -+
- // M = | Dot(N,E-P)*I - E*N^T -(Dot(N,E-P)*I - E*N^T)*E |
- // | -N^t Dot(N,E) |
- // +- -+
- //
- // where E is the eye point, P is a point on the plane, and N is a
- // unit-length plane normal.
- template <typename Real>
- Matrix4x4<Real> MakePerspectiveProjection(Vector4<Real> const& origin,
- Vector4<Real> const& normal, Vector4<Real> const& eye)
- {
- Matrix4x4<Real> M;
- Real dotND = Dot(normal, eye - origin);
- #if defined(GTE_USE_MAT_VEC)
- M(0, 0) = dotND - eye[0] * normal[0];
- M(0, 1) = -eye[0] * normal[1];
- M(0, 2) = -eye[0] * normal[2];
- M(0, 3) = -(M(0, 0) * eye[0] + M(0, 1) * eye[1] + M(0, 2) * eye[2]);
- M(1, 0) = -eye[1] * normal[0];
- M(1, 1) = dotND - eye[1] * normal[1];
- M(1, 2) = -eye[1] * normal[2];
- M(1, 3) = -(M(1, 0) * eye[0] + M(1, 1) * eye[1] + M(1, 2) * eye[2]);
- M(2, 0) = -eye[2] * normal[0];
- M(2, 1) = -eye[2] * normal[1];
- M(2, 2) = dotND - eye[2] * normal[2];
- M(2, 3) = -(M(2, 0) * eye[0] + M(2, 1) * eye[1] + M(2, 2) * eye[2]);
- M(3, 0) = -normal[0];
- M(3, 1) = -normal[1];
- M(3, 2) = -normal[2];
- M(3, 3) = Dot(eye, normal);
- #else
- M(0, 0) = dotND - eye[0] * normal[0];
- M(1, 0) = -eye[0] * normal[1];
- M(2, 0) = -eye[0] * normal[2];
- M(3, 0) = -(M(0, 0) * eye[0] + M(0, 1) * eye[1] + M(0, 2) * eye[2]);
- M(0, 1) = -eye[1] * normal[0];
- M(1, 1) = dotND - eye[1] * normal[1];
- M(2, 1) = -eye[1] * normal[2];
- M(3, 1) = -(M(1, 0) * eye[0] + M(1, 1) * eye[1] + M(1, 2) * eye[2]);
- M(0, 2) = -eye[2] * normal[0];
- M(1, 2) = -eye[2] * normal[1];
- M(2, 2) = dotND - eye[2] * normal[2];
- M(3, 2) = -(M(2, 0) * eye[0] + M(2, 1) * eye[1] + M(2, 2) * eye[2]);
- M(0, 3) = -normal[0];
- M(1, 3) = -normal[1];
- M(2, 3) = -normal[2];
- M(3, 3) = Dot(eye, normal);
- #endif
- return M;
- }
- // The reflection of a point through a plane is
- // +- -+
- // M = | I-2*N*N^T 2*Dot(N,P)*N |
- // | 0^T 1 |
- // +- -+
- //
- // where P is a point on the plane and N is a unit-length plane normal.
- template <typename Real>
- Matrix4x4<Real> MakeReflection(Vector4<Real> const& origin,
- Vector4<Real> const& normal)
- {
- Matrix4x4<Real> M;
- Real const zero = (Real)0, one = (Real)1, two = (Real)2;
- Real twoDotNO = two * Dot(origin, normal);
- #if defined(GTE_USE_MAT_VEC)
- M(0, 0) = one - two * normal[0] * normal[0];
- M(0, 1) = -two * normal[0] * normal[1];
- M(0, 2) = -two * normal[0] * normal[2];
- M(0, 3) = twoDotNO * normal[0];
- M(1, 0) = M(0, 1);
- M(1, 1) = one - two * normal[1] * normal[1];
- M(1, 2) = -two * normal[1] * normal[2];
- M(1, 3) = twoDotNO * normal[1];
- M(2, 0) = M(0, 2);
- M(2, 1) = M(1, 2);
- M(2, 2) = one - two * normal[2] * normal[2];
- M(2, 3) = twoDotNO * normal[2];
- M(3, 0) = zero;
- M(3, 1) = zero;
- M(3, 2) = zero;
- M(3, 3) = one;
- #else
- M(0, 0) = one - two * normal[0] * normal[0];
- M(1, 0) = -two * normal[0] * normal[1];
- M(2, 0) = -two * normal[0] * normal[2];
- M(3, 0) = twoDotNO * normal[0];
- M(0, 1) = M(1, 0);
- M(1, 1) = one - two * normal[1] * normal[1];
- M(2, 1) = -two * normal[1] * normal[2];
- M(3, 1) = twoDotNO * normal[1];
- M(0, 2) = M(2, 0);
- M(1, 2) = M(2, 1);
- M(2, 2) = one - two * normal[2] * normal[2];
- M(3, 2) = twoDotNO * normal[2];
- M(0, 3) = zero;
- M(1, 3) = zero;
- M(2, 3) = zero;
- M(3, 3) = one;
- #endif
- return M;
- }
- }
|