Cafu Engine
Matrix.hpp
1 /*
2 Cafu Engine, http://www.cafu.de/
3 Copyright (c) Carsten Fuchs and other contributors.
4 This project is licensed under the terms of the MIT license.
5 */
6 
7 #ifndef CAFU_MATH_MATRIX_4X4_HPP_INCLUDED
8 #define CAFU_MATH_MATRIX_4X4_HPP_INCLUDED
9 
10 #include "Vector3.hpp"
11 
12 
13 namespace cf { namespace math { template<class T> class QuaternionT; } }
14 
15 
16 /// This class represents a generic 4x4 matrix.
17 /// It has special helper methods for affine geometric transformations in 3D, but can be used for general purposes.
18 /// Contrary to earlier test versions, it stores the fourth row explicitly, so that easy compatibility with
19 /// OpenGL matrices is given and no problems occur with general-case use (e.g. as projection matrix etc.).
20 /// @nosubgrouping
21 template<class T>
22 class Matrix4x4T
23 {
24  public:
25 
26  /// The default constructor for creating a "1" (identity) matrix.
28  {
29  for (unsigned int i = 0; i < 4; i++)
30  for (unsigned int j = 0; j < 4; j++)
31  m[i][j] = (i == j) ? T(1.0) : 0;
32  }
33 
34  /// Constructor for creating an arbitrary matrix.
35  Matrix4x4T(const float M[4][4])
36  {
37  for (unsigned int i = 0; i < 4; i++)
38  for (unsigned int j = 0; j < 4; j++)
39  m[i][j] = T(M[i][j]);
40  }
41 
42  /// Constructor for creating an arbitrary matrix.
43  Matrix4x4T(const double M[4][4])
44  {
45  for (unsigned int i = 0; i < 4; i++)
46  for (unsigned int j = 0; j < 4; j++)
47  m[i][j] = T(M[i][j]);
48  }
49 
50  /// Constructor for creating an arbitrary matrix.
51  Matrix4x4T(T m00, T m01, T m02, T m03,
52  T m10, T m11, T m12, T m13,
53  T m20, T m21, T m22, T m23,
54  T m30, T m31, T m32, T m33)
55  {
56  m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03;
57  m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13;
58  m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23;
59  m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33;
60  }
61 
62  /// Constructor for creating a matrix from a translation, a quaternion, and an optional scale.
63  ///
64  /// The resulting matrix is equal to the matrix product T*R*S of three matrices T, R and S, where
65  /// T is the translation matrix that corresponds to the given translation vector @c t,
66  /// R is the rotation matrix that is constructed from the given quaternion @c q, and
67  /// S is the scale matrix that corresponds to the given scale @c s.
68  ///
69  /// The resulting matrix is of the form:
70  /// @code
71  /// x1*s.x x2*s.y x3*s.z t.x
72  /// y1*s.x y2*s.y y3*s.z t.y
73  /// z1*s.x z2*s.y z3*s.z t.z
74  /// 0 0 0 1
75  /// @endcode
76  ///
77  /// @param t The translation that is expressed in the matrix.
78  /// @param q The quaternion that describes the rotation that is expressed in the matrix.
79  /// @param s The scale that is expressed in the matrix.
80  Matrix4x4T(const Vector3T<T>& t, const cf::math::QuaternionT<T>& q, const Vector3T<T>& s = Vector3T<T>(1, 1, 1));
81 
82  /// \name Named constructors
83  /// @{
84  static Matrix4x4T GetProjOrthoMatrix(T left, T right, T bottom, T top, T zNear, T zFar); ///< Returns a matrix for orthographic projection.
85  static Matrix4x4T GetProjFrustumMatrix(T left, T right, T bottom, T top, T zNear, T zFar); ///< Returns a matrix for perspective projection. If zFar <= zNear, the far plane is assumed to be at infinity (a useful special case for stencil shadow projections).
86  static Matrix4x4T GetProjPerspectiveMatrix(T fovY, T aspect, T zNear, T zFar); ///< Returns a matrix for perspective projection. If zFar <= zNear, the far plane is assumed to be at infinity (a useful special case for stencil shadow projections).
87  static Matrix4x4T GetProjPickMatrix(T x, T y, T width, T height, int viewport[4]); ///< Returns a matrix for picking, i.e. the same matrix that gluPickMatrix() uses.
88 
89  static Matrix4x4T GetTranslateMatrix(const Vector3T<T>& t); ///< Returns a translate matrix about t.
90  static Matrix4x4T GetScaleMatrix(T sx, T sy, T sz); ///< Returns a scale matrix with scale factors (sx sy sz).
91  static Matrix4x4T GetRotateXMatrix(T Angle); ///< Returns a rotation matrix about Angle degrees around the x-axis.
92  static Matrix4x4T GetRotateYMatrix(T Angle); ///< Returns a rotation matrix about Angle degrees around the y-axis.
93  static Matrix4x4T GetRotateZMatrix(T Angle); ///< Returns a rotation matrix about Angle degrees around the z-axis.
94  static Matrix4x4T GetRotateMatrix(T Angle, const Vector3T<T>& Axis); ///< Returns a rotation matrix about Angle degrees around Axis.
95  /// @}
96 
97 
98 
99  /// Returns the i-th row of this matrix.
100  T* operator [] (unsigned int i) { assert(i < 4); return m[i]; }
101 
102  /// Returns the i-th row of this matrix.
103  const T* operator [] (unsigned int i) const { assert(i < 4); return m[i]; }
104 
105  /// Computes M*Other, that is, the matrix product of this and the Other matrix.
106  /// @param Other The other matrix (right side).
107  /// @return The matrix product of this and the Other matrix.
108  Matrix4x4T operator * (const Matrix4x4T& Other) const;
109 
110  void Translate_MT(const Vector3dT& Trans); ///< Computes M=M*T, where T=GetTranslationMatrix(Trans). Assumes that the last row is (0 0 0 1).
111  void Translate_MT(T tx, T ty, T tz); ///< Computes M=M*T, where T=GetTranslationMatrix(Trans). Assumes that the last row is (0 0 0 1).
112  void Translate_TM(const Vector3dT& Trans); ///< Computes M=T*M, where T=GetTranslationMatrix(Trans). Assumes that the last row is (0 0 0 1).
113  void Scale_MS (T sx, T sy, T sz); ///< Computes M=M*S, where S=GetScaleMatrix (sx, sy, sz).
114  void Scale_SM (T sx, T sy, T sz); ///< Computes M=S*M, where S=GetScaleMatrix (sx, sy, sz).
115  void RotateX_MR (T Angle); ///< Computes M=M*R, where R=GetRotateXMatrix (Angle).
116  void RotateX_RM (T Angle); ///< Computes M=R*M, where R=GetRotateXMatrix (Angle).
117  void RotateY_MR (T Angle); ///< Computes M=M*R, where R=GetRotateYMatrix (Angle).
118  void RotateY_RM (T Angle); ///< Computes M=R*M, where R=GetRotateYMatrix (Angle).
119  void RotateZ_MR (T Angle); ///< Computes M=M*R, where R=GetRotateZMatrix (Angle).
120  void RotateZ_RM (T Angle); ///< Computes M=R*M, where R=GetRotateZMatrix (Angle).
121 
122  /// Computes M*v, where M is this matrix.
123  /// The w-component of v is assumed to be 0 (v being a direction vector, not a point).
124  /// The last row of M is assumed to be (0 0 0 1).
125  /// That means that only the rotation (and scale) of M is applied to v.
126  /// @param v A direction vector.
127  /// @return M*v. The w-component of the returned vector is implied to be 0.
128  Vector3dT Mul0(const Vector3dT& v) const
129  {
130  return Vector3dT(m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z,
131  m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z,
132  m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z);
133  }
134 
135  // Same as above, but with float.
136  /// @param v A direction vector.
137  /// @return M*v. The w-component of the returned vector is implied to be 0.
138  Vector3fT Mul0(const Vector3fT& v) const
139  {
140  return Vector3fT(float(m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z),
141  float(m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z),
142  float(m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z));
143  }
144 
145  /// Computes M*v, where M is this matrix.
146  /// The w-component of v is assumed to be 1 (v being a point, not a direction vector).
147  /// The last row of M is assumed to be (0 0 0 1).
148  /// That means that both the rotation (and scale) *and* the translation of M is applied to v.
149  /// @param v A point.
150  /// @return M*v. The w-component of the returned vector is implied to be 1.
151  Vector3dT Mul1(const Vector3dT& v) const
152  {
153  return Vector3dT(m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3],
154  m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3],
155  m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]);
156  }
157 
158  // Same as above, but with float.
159  /// @param v A point.
160  /// @return M*v. The w-component of the returned vector is implied to be 1.
161  Vector3fT Mul1(const Vector3fT& v) const
162  {
163  return Vector3fT(float(m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3]),
164  float(m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3]),
165  float(m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]));
166  }
167 
168  /// Computes M*v, where M is this matrix.
169  /// The w-component of v is assumed to be 1 (v being a point, not a direction vector).
170  /// The last row of M is assumed to be (0 0 0 1).
171  /// That means that both the rotation (and scale) *and* the translation of M is applied to v.
172  /// @param v A point.
173  /// @return M*v. The w-component of the returned vector is implied to be 1.
175  {
176  return Vector3T<T>(m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3],
177  m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3],
178  m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3]);
179  }
180 
181  /// Computes M*v, where M is this matrix.
182  /// The w-component of v is assumed to be 1 (v being a point, not a direction vector).
183  /// The last row of M is assumed to be (0 0 0 1).
184  /// That means that both the rotation (and scale) *and* the translation of M is applied to v.
185  /// @param v A point.
186  /// @param out The result of M*v.
187  void Mul_xyz1(const T v[3], T out[3]) const
188  {
189  // We need the Result variable in case that v == out.
190  const T Result[3] = { m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2] + m[0][3],
191  m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2] + m[1][3],
192  m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2] + m[2][3] };
193 
194  for (unsigned int i = 0; i < 3; i++) out[i] = Result[i];
195  }
196 
197  /// Computes M*v, where M is this matrix.
198  /// The w-component of v is assumed to be 1 (v being a point, not a direction vector).
199  /// The resulting 4-tuple is divided by the w-component so that only the xyz components must be returned.
200  /// @param v A point.
201  /// @return M*v. The w-component of the returned vector is implied to be 1.
203  {
204  const Vector3T<T> ProjPoint = Mul1(v);
205  const T v_w = m[3][0]*v.x + m[3][1]*v.y + m[3][2]*v.z + m[3][3];
206 
207  return (v_w != 0) ? scale(ProjPoint, 1 / v_w) : ProjPoint;
208  }
209 
210  /// Computes M*v, where M is this matrix.
211  /// @param v The four-component vector that is multiplied with M.
212  /// @param out The four-component result vector.
213  /// @return The four-component result vector M*v is returned via the out parameter.
214  void Mul(const T v[4], T out[4]) const
215  {
216  // We need the Result variable in case that v == out.
217  const T Result[4] = { m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2] + m[0][3]*v[3],
218  m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2] + m[1][3]*v[3],
219  m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2] + m[2][3]*v[3],
220  m[3][0]*v[0] + m[3][1]*v[1] + m[3][2]*v[2] + m[3][3]*v[3] };
221 
222  for (unsigned int i = 0; i < 4; i++) out[i] = Result[i];
223  }
224 
225  /// Returns whether this matrix is equal to Other.
226  /// The matrices are considered equal if the element-wise comparison yields no difference larger than Epsilon.
227  /// @param Other Matrix to compare to.
228  /// @param Epsilon Tolerance value.
229  bool IsEqual(const Matrix4x4T& Other, const T Epsilon = 0) const
230  {
231  for (unsigned int i = 0; i < 4; i++)
232  for (unsigned int j = 0; j < 4; j++)
233  if (fabs(m[i][j] - Other.m[i][j]) > Epsilon)
234  return false;
235 
236  return true;
237  }
238 
239  /// If this matrix represents a rigid transformation (rotation and translation only, no scale, shear, etc.),
240  /// this is a faster shortcut for GetInverse().Mul1(v).
241  /// It employs the transpose of the rotational part for inverting the rotation, and properly accounts for the translation.
242  /// @param v DOCTODO
244  {
245  v.x -= m[0][3];
246  v.y -= m[1][3];
247  v.z -= m[2][3];
248 
249  return Vector3T<T>(m[0][0]*v.x + m[1][0]*v.y + m[2][0]*v.z,
250  m[0][1]*v.x + m[1][1]*v.y + m[2][1]*v.z,
251  m[0][2]*v.x + m[1][2]*v.y + m[2][2]*v.z);
252  }
253 
254  /// Computes the inverse of this matrix.
255  /// @param Result Whether the inversion was successful.
256  /// @return If this matrix is invertible, the inverse is returned by this method and *Result, if not at NULL, is set to true.
257  /// Otherwise, an undefined matrix is returned and *Result, if not at NULL, is set to false.
258  Matrix4x4T GetInverse(bool* Result = NULL) const;
259 
260  /// Returns the transpose of this matrix.
261  /// @return The transpose of this matrix.
262  Matrix4x4T GetTranspose() const;
263 
264 
265 
266  /// The matrix values.
267  T m[4][4];
268 };
269 
270 
271 /// Typedef for a Matrix4x4T of floats.
273 typedef Matrix4x4T<float> MatrixT; // The original MatrixT type for backwards-compatibility with old code.
274 
275 /// Typedef for a Matrix4x4T of doubles.
277 
278 #endif
Vector3T< T > ProjectPoint(const Vector3T< T > &v) const
Computes M*v, where M is this matrix.
Definition: Matrix.hpp:202
Matrix4x4T GetTranspose() const
Returns the transpose of this matrix.
Definition: Matrix.cpp:457
Vector3fT Mul0(const Vector3fT &v) const
Definition: Matrix.hpp:138
static Matrix4x4T GetRotateZMatrix(T Angle)
Returns a rotation matrix about Angle degrees around the z-axis.
Definition: Matrix.cpp:152
bool IsEqual(const Matrix4x4T &Other, const T Epsilon=0) const
Returns whether this matrix is equal to Other.
Definition: Matrix.hpp:229
void RotateY_RM(T Angle)
Computes M=R*M, where R=GetRotateYMatrix (Angle).
Definition: Matrix.cpp:313
void RotateZ_RM(T Angle)
Computes M=R*M, where R=GetRotateZMatrix (Angle).
Definition: Matrix.cpp:347
Vector3dT Mul0(const Vector3dT &v) const
Computes M*v, where M is this matrix.
Definition: Matrix.hpp:128
static Matrix4x4T GetProjPerspectiveMatrix(T fovY, T aspect, T zNear, T zFar)
Returns a matrix for perspective projection. If zFar <= zNear, the far plane is assumed to be at infi...
Definition: Matrix.cpp:59
void RotateX_MR(T Angle)
Computes M=M*R, where R=GetRotateXMatrix (Angle).
Definition: Matrix.cpp:262
static Matrix4x4T GetRotateYMatrix(T Angle)
Returns a rotation matrix about Angle degrees around the y-axis.
Definition: Matrix.cpp:137
Matrix4x4T(const double M[4][4])
Constructor for creating an arbitrary matrix.
Definition: Matrix.hpp:43
static Matrix4x4T GetTranslateMatrix(const Vector3T< T > &t)
Returns a translate matrix about t.
Definition: Matrix.cpp:98
Matrix4x4T(const float M[4][4])
Constructor for creating an arbitrary matrix.
Definition: Matrix.hpp:35
void Mul_xyz1(const T v[3], T out[3]) const
Computes M*v, where M is this matrix.
Definition: Matrix.hpp:187
T y
The y-component of this vector.
Definition: Vector3.hpp:41
This class represents a generic 4x4 matrix.
Definition: MapElement.hpp:30
Vector3fT Mul1(const Vector3fT &v) const
Definition: Matrix.hpp:161
void RotateX_RM(T Angle)
Computes M=R*M, where R=GetRotateXMatrix (Angle).
Definition: Matrix.cpp:279
static Matrix4x4T GetProjFrustumMatrix(T left, T right, T bottom, T top, T zNear, T zFar)
Returns a matrix for perspective projection. If zFar <= zNear, the far plane is assumed to be at infi...
Definition: Matrix.cpp:40
This class represents a polymorphic 3-dimensional vector.
Definition: Misc.hpp:11
T m[4][4]
The matrix values.
Definition: Matrix.hpp:267
Vector3dT Mul1(const Vector3dT &v) const
Computes M*v, where M is this matrix.
Definition: Matrix.hpp:151
Matrix4x4T()
The default constructor for creating a "1" (identity) matrix.
Definition: Matrix.hpp:27
static Matrix4x4T GetScaleMatrix(T sx, T sy, T sz)
Returns a scale matrix with scale factors (sx sy sz).
Definition: Matrix.cpp:110
Vector3T< T > InvXForm(Vector3T< T > v) const
If this matrix represents a rigid transformation (rotation and translation only, no scale...
Definition: Matrix.hpp:243
void RotateZ_MR(T Angle)
Computes M=M*R, where R=GetRotateZMatrix (Angle).
Definition: Matrix.cpp:330
void Scale_SM(T sx, T sy, T sz)
Computes M=S*M, where S=GetScaleMatrix (sx, sy, sz).
Definition: Matrix.cpp:251
static Matrix4x4T GetRotateMatrix(T Angle, const Vector3T< T > &Axis)
Returns a rotation matrix about Angle degrees around Axis.
Definition: Matrix.cpp:167
T * operator[](unsigned int i)
Returns the i-th row of this matrix.
Definition: Matrix.hpp:100
static Matrix4x4T GetProjPickMatrix(T x, T y, T width, T height, int viewport[4])
Returns a matrix for picking, i.e. the same matrix that gluPickMatrix() uses.
Definition: Matrix.cpp:83
void Scale_MS(T sx, T sy, T sz)
Computes M=M*S, where S=GetScaleMatrix (sx, sy, sz).
Definition: Matrix.cpp:240
static Matrix4x4T GetRotateXMatrix(T Angle)
Returns a rotation matrix about Angle degrees around the x-axis.
Definition: Matrix.cpp:122
void RotateY_MR(T Angle)
Computes M=M*R, where R=GetRotateYMatrix (Angle).
Definition: Matrix.cpp:296
T z
The z-component of this vector.
Definition: Vector3.hpp:42
This class represents a quaternion.
Definition: Angles.hpp:18
Vector3T< T > Mul_xyz1(const Vector3T< T > &v) const
Computes M*v, where M is this matrix.
Definition: Matrix.hpp:174
T x
The x-component of this vector.
Definition: Vector3.hpp:40
void Mul(const T v[4], T out[4]) const
Computes M*v, where M is this matrix.
Definition: Matrix.hpp:214
Matrix4x4T GetInverse(bool *Result=NULL) const
Computes the inverse of this matrix.
Definition: Matrix.cpp:364
Matrix4x4T operator*(const Matrix4x4T &Other) const
Computes M*Other, that is, the matrix product of this and the Other matrix.
Definition: Matrix.cpp:189
void Translate_TM(const Vector3dT &Trans)
Computes M=T*M, where T=GetTranslationMatrix(Trans). Assumes that the last row is (0 0 0 1)...
Definition: Matrix.cpp:232
void Translate_MT(const Vector3dT &Trans)
Computes M=M*T, where T=GetTranslationMatrix(Trans). Assumes that the last row is (0 0 0 1)...
Definition: Matrix.cpp:214
static Matrix4x4T GetProjOrthoMatrix(T left, T right, T bottom, T top, T zNear, T zFar)
Returns a matrix for orthographic projection.
Definition: Matrix.cpp:30
Matrix4x4T(T m00, T m01, T m02, T m03, T m10, T m11, T m12, T m13, T m20, T m21, T m22, T m23, T m30, T m31, T m32, T m33)
Constructor for creating an arbitrary matrix.
Definition: Matrix.hpp:51