从零开始游戏开发——2.2 矩阵

  在游戏开发中,矩阵具有十分重要的地位,但他也只是我们操作点和向量的一个工具,在这里我们使用列优先规则来存储矩阵。在这里矩阵最主要的两个作用是:1. 旋转一个向量或者变换一个坐标点的位置;2. 坐标空间变换。对于第一点,在第2.1向量章节中,我们直接使用了三角函数对向量进行旋转,矩阵则是提供了另一种表示方式。我们知道向量可以表示为坐标空间基向量和的形式,即向量p = ax + by + cz = (1, 0, 0)*a + (0, 1, 0)*b + (0, 0, 1) * c,(a, b, c)就是向量p在x, y, z空间中的坐标如下图,

 

 

 

 上面表达式可以写成矩阵相乘的形式:

我们让x、y坐标轴绕z旋转到x'、y'如上图,x'、y'的基向量分别为(cosθ, sinθ, 0)和(-sinθ, cosθ, 0),替换上面的公式的RUD基向量,即得到绕z轴旋转的矩阵为:

 其中

 同理可以得到绕y轴的矩阵为:

 ,其中

 绕x轴的矩阵为:

 ,其中 

当绕任意向量u旋转时,

 

 则此时旋转矩阵为:

 

也可以利用矩阵来计算反射矩阵,根据向量的反射可以得到:

从而得到反射矩阵如下(在《3D游戏引擎设计》一书中,此矩阵有些错误这里进行了修正):

 

  利用矩阵来计算缩放则比较简单,对3x3的矩阵M来讲,只需要将M(0,0)、M(1,1)、M(2,2)矩阵位置处的值进行缩放,即可对向量x,y,z方向进行缩放。上面利用3x3矩阵计算了出了旋转矩阵,当要对空间点位置进行移动时,需要用到矩阵和向量的第四维,此时的向量称为齐次坐标,此时的矩阵形式如下:

矩阵中的(b0, b1, b2)即为在x、y、z方向的偏移。用了这个4x4的矩阵,可以将向量从一个坐标空间转换到另一个坐标空间,这在渲染中是最常用的操作。在美术设计师给到一个模型时,模型中点的位置是相对于模型自己的坐标空间,而游戏世界需要渲染一个模型,会将整个模型放置于世界中的某个位置并带有旋转和缩放,游戏世界所在的空间为世界空间,要渲染一个模型,还需要一个摄像机和投影平面,通过摄像机去看一个物体是需要转换到相机空间的,最后还需要投影到摄像机的近裁剪面,在这里模型转换到世界空间的矩阵为M,世界空间转换到相机空间矩阵为V,相机空间进行投影计算矩阵为P,这就是以后会常听到的MVP矩阵。要真正渲染一个顶点Q,由于矩阵是列优先的,利用矩阵乘法计算坐标空间转换为右乘计算Q' = P * V * M * Q。这些用到的矩阵的实现,会在后面章节详细介绍。下面是4x4矩阵的实现代码:

  1 #ifndef _MATRIX_4_X_4_HPP
  2 #define _MATRIX_4_X_4_HPP
  3 
  4 #include "Vector3.hpp"
  5 
  6 using namespace std;
  7 template <typename T>
  8 class Matrix4x4
  9 {
 10 public:
 11     Matrix4x4(
 12             T m00, T m01, T m02, T m03,
 13             T m10, T m11, T m12, T m13,
 14             T m20, T m21, T m22, T m23,
 15             T m30, T m31, T m32, T m33
 16     );
 17     Matrix4x4(T m[16]);
 18     Matrix4x4();
 19 
 20     Matrix4x4 &MakeIdentity();
 21     void MakeRotation(const Vector3<T> &v, T radian);
 22     void MakeTransition(const Vector3<T> & v);
 23     void MakeTransition(T x, T y, T z);
 24     void MakeScale(const Vector3<T> & v);
 25     void MakeScale(T x, T y, T z);
 26     void MakeReflect(const Vector3<T> &normal);
 27     bool GetInverse(Matrix4x4<T> &out) const;
 28     void GetTransposed(Matrix4x4<T> &o) const;
 29     Vector3<T> Transform(const Vector3<T> &v) const;
 30     Matrix4x4<T> operator*(const Matrix4x4 &m) const;
 31     T operator[](int i) const;
 32     T operator[](int i);
 33     T operator()(int row, int col) const;
 34     T operator()(int row, int col);
 35 
 36     union
 37     {
 38         struct
 39         {
 40             T m00, m01, m02, m03;
 41             T m10, m11, m12, m13;
 42             T m20, m21, m22, m23;
 43             T m30, m31, m32, m33;
 44         };
 45 
 46         T m[16];     
 47     };
 48 };
 49 
 50 
 51 template <typename T>
 52 Matrix4x4<T>::Matrix4x4(
 53         T m00, T m01, T m02, T m03,
 54         T m10, T m11, T m12, T m13,
 55         T m20, T m21, T m22, T m23,
 56         T m30, T m31, T m32, T m33
 57 ):m00(m00), m01(m01), m02(m02), m03(m03),
 58     m10(m10), m11(m11), m12(m12), m13(m13),
 59     m20(m20), m21(m21), m22(m22), m23(m23),
 60     m30(m30), m31(m31), m32(m32), m33(m33)
 61 {
 62 }
 63 
 64 template <typename T>
 65 Matrix4x4<T>::Matrix4x4(T m[16])
 66 {
 67     memcpy(this->m, m, sizeof(this->m));
 68 }
 69 
 70 template <typename T>
 71 Matrix4x4<T>::Matrix4x4()
 72     : m00(1), m01(0), m02(0), m03(0),
 73         m10(0), m11(1), m12(0), m13(0),
 74         m20(0), m21(0), m22(1), m23(0),
 75         m30(0), m31(0), m32(0), m33(1)
 76 {
 77 }
 78 
 79 
 80 template <typename T>
 81 Matrix4x4<T> &Matrix4x4<T>::MakeIdentity()
 82 {
 83     memset(m, 0, sizeof(m));
 84     m[0] = m[5] = m[10] = m[15] = static_cast<T>(1);
 85     return *this;
 86 }
 87 
 88 
 89 template <typename T>
 90 void Matrix4x4<T>::MakeRotation(const Vector3<T> &v, T radian)
 91 {
 92     T c = cos(radian);
 93     T s = sin(radian);
 94     T x2 = v.x * v.x;
 95     T y2 = v.y * v.y;
 96     T z2 = v.z * v.z;
 97     T xy = v.x * v.y;
 98     T xz = v.x * v.z;
 99     T yz = v.y * v.z;
100 
101     m00 = c + (1 - c) * x2;         m01 = -v.z * s + (1 - c) * xy;      m02 = v.y * s + (1 - c) * xz;
102     m10 = v.z * s + (1 - c) * xy;   m11 = c + (1 - c) * y2;             m12 = -v.x * s + (1 - c) * yz;
103     m20 = -v.y * s + (1 - c) * xz;  m21 = v.x * s + (1 - c) * yz;       m22 = c + (1 - c) * z2;
104 }
105 
106 template <typename T>
107 void Matrix4x4<T>::MakeTransition(const Vector3<T> & v)
108 {
109     m03 = v.x;
110     m13 = v.y;
111     m23 = v.z;
112 }
113 
114 template <typename T>
115 void Matrix4x4<T>::MakeTransition(T x, T y, T z)
116 {
117     m03 = x;
118     m13 = y;
119     m23 = z;
120 }
121 
122 template <typename T>
123 void Matrix4x4<T>::MakeScale(T x, T y, T z)
124 {
125     m00 = x;
126     m11 = y;
127     m22 = z;
128 }
129 
130 template <typename T>
131 void Matrix4x4<T>::MakeScale(const Vector3<T> &v)
132 {
133     m00 = v.x;
134     m11 = v.y;
135     m22 = v.z;
136 }
137 
138 template <typename T>
139 void Matrix4x4<T>::MakeReflect(const Vector3<T> &n)
140 {
141     T x2 = n.x * n.x;
142     T y2 = n.y * n.y;
143     T z2 = n.z * n.z;
144 
145     T xy = n.x * n.y;
146     T xz = n.x * n.z;
147     T yz = n.y * n.z;
148 
149     m00 = 1 - 2 * x2;       m01 = -2 * xy;      m02 = -2 * xz;
150     m10 = -2 * xy;          m11 = 1 - 2 * y2;   m12 = -2 * yz;
151     m20 = -2 * xz;          m21 = -2 * yz;      m22 = 1 - 2 * z2;
152 }
153 
154 template <typename T>
155 bool Matrix4x4<T>::GetInverse(Matrix4x4<T> &out) const
156 {
157     const Matrix4x4 &m = *this;
158 
159     T d = (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) -
160               (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
161               (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)) +
162               (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) -
163               (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
164               (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0));
165 
166     if (d > -0.00001 && d < 0.00001)
167         return false;
168 
169     d = 1 / d;
170 
171     out(0, 0) = d * (m(1, 1) * (m(2, 2) * m(3, 3) - m(2, 3) * m(3, 2)) +
172                      m(1, 2) * (m(2, 3) * m(3, 1) - m(2, 1) * m(3, 3)) +
173                      m(1, 3) * (m(2, 1) * m(3, 2) - m(2, 2) * m(3, 1)));
174     out(0, 1) = d * (m(2, 1) * (m(0, 2) * m(3, 3) - m(0, 3) * m(3, 2)) +
175                      m(2, 2) * (m(0, 3) * m(3, 1) - m(0, 1) * m(3, 3)) +
176                      m(2, 3) * (m(0, 1) * m(3, 2) - m(0, 2) * m(3, 1)));
177     out(0, 2) = d * (m(3, 1) * (m(0, 2) * m(1, 3) - m(0, 3) * m(1, 2)) +
178                      m(3, 2) * (m(0, 3) * m(1, 1) - m(0, 1) * m(1, 3)) +
179                      m(3, 3) * (m(0, 1) * m(1, 2) - m(0, 2) * m(1, 1)));
180     out(0, 3) = d * (m(0, 1) * (m(1, 3) * m(2, 2) - m(1, 2) * m(2, 3)) +
181                      m(0, 2) * (m(1, 1) * m(2, 3) - m(1, 3) * m(2, 1)) +
182                      m(0, 3) * (m(1, 2) * m(2, 1) - m(1, 1) * m(2, 2)));
183     out(1, 0) = d * (m(1, 2) * (m(2, 0) * m(3, 3) - m(2, 3) * m(3, 0)) +
184                      m(1, 3) * (m(2, 2) * m(3, 0) - m(2, 0) * m(3, 2)) +
185                      m(1, 0) * (m(2, 3) * m(3, 2) - m(2, 2) * m(3, 3)));
186     out(1, 1) = d * (m(2, 2) * (m(0, 0) * m(3, 3) - m(0, 3) * m(3, 0)) +
187                      m(2, 3) * (m(0, 2) * m(3, 0) - m(0, 0) * m(3, 2)) +
188                      m(2, 0) * (m(0, 3) * m(3, 2) - m(0, 2) * m(3, 3)));
189     out(1, 2) = d * (m(3, 2) * (m(0, 0) * m(1, 3) - m(0, 3) * m(1, 0)) +
190                      m(3, 3) * (m(0, 2) * m(1, 0) - m(0, 0) * m(1, 2)) +
191                      m(3, 0) * (m(0, 3) * m(1, 2) - m(0, 2) * m(1, 3)));
192     out(1, 3) = d * (m(0, 2) * (m(1, 3) * m(2, 0) - m(1, 0) * m(2, 3)) +
193                      m(0, 3) * (m(1, 0) * m(2, 2) - m(1, 2) * m(2, 0)) +
194                      m(0, 0) * (m(1, 2) * m(2, 3) - m(1, 3) * m(2, 2)));
195     out(2, 0) = d * (m(1, 3) * (m(2, 0) * m(3, 1) - m(2, 1) * m(3, 0)) +
196                      m(1, 0) * (m(2, 1) * m(3, 3) - m(2, 3) * m(3, 1)) +
197                      m(1, 1) * (m(2, 3) * m(3, 0) - m(2, 0) * m(3, 3)));
198     out(2, 1) = d * (m(2, 3) * (m(0, 0) * m(3, 1) - m(0, 1) * m(3, 0)) +
199                      m(2, 0) * (m(0, 1) * m(3, 3) - m(0, 3) * m(3, 1)) +
200                      m(2, 1) * (m(0, 3) * m(3, 0) - m(0, 0) * m(3, 3)));
201     out(2, 2) = d * (m(3, 3) * (m(0, 0) * m(1, 1) - m(0, 1) * m(1, 0)) +
202                      m(3, 0) * (m(0, 1) * m(1, 3) - m(0, 3) * m(1, 1)) +
203                      m(3, 1) * (m(0, 3) * m(1, 0) - m(0, 0) * m(1, 3)));
204     out(2, 3) = d * (m(0, 3) * (m(1, 1) * m(2, 0) - m(1, 0) * m(2, 1)) +
205                      m(0, 0) * (m(1, 3) * m(2, 1) - m(1, 1) * m(2, 3)) +
206                      m(0, 1) * (m(1, 0) * m(2, 3) - m(1, 3) * m(2, 0)));
207     out(3, 0) = d * (m(1, 0) * (m(2, 2) * m(3, 1) - m(2, 1) * m(3, 2)) +
208                      m(1, 1) * (m(2, 0) * m(3, 2) - m(2, 2) * m(3, 0)) +
209                      m(1, 2) * (m(2, 1) * m(3, 0) - m(2, 0) * m(3, 1)));
210     out(3, 1) = d * (m(2, 0) * (m(0, 2) * m(3, 1) - m(0, 1) * m(3, 2)) +
211                      m(2, 1) * (m(0, 0) * m(3, 2) - m(0, 2) * m(3, 0)) +
212                      m(2, 2) * (m(0, 1) * m(3, 0) - m(0, 0) * m(3, 1)));
213     out(3, 2) = d * (m(3, 0) * (m(0, 2) * m(1, 1) - m(0, 1) * m(1, 2)) +
214                      m(3, 1) * (m(0, 0) * m(1, 2) - m(0, 2) * m(1, 0)) +
215                      m(3, 2) * (m(0, 1) * m(1, 0) - m(0, 0) * m(1, 1)));
216     out(3, 3) = d * (m(0, 0) * (m(1, 1) * m(2, 2) - m(1, 2) * m(2, 1)) +
217                      m(0, 1) * (m(1, 2) * m(2, 0) - m(1, 0) * m(2, 2)) +
218                      m(0, 2) * (m(1, 0) * m(2, 1) - m(1, 1) * m(2, 0)));
219 
220     return true;
221 }
222 
223 template <typename T>
224 void Matrix4x4<T>::GetTransposed(Matrix4x4<T> &o) const
225 {
226     o[0] = m[0];
227     o[1] = m[4];
228     o[2] = m[8];
229     o[3] = m[12];
230 
231     o[4] = m[1];
232     o[5] = m[5];
233     o[6] = m[9];
234     o[7] = m[13];
235 
236     o[8] = m[2];
237     o[9] = m[6];
238     o[10] = m[10];
239     o[11] = m[14];
240 
241     o[12] = m[3];
242     o[13] = m[7];
243     o[14] = m[11];
244     o[15] = m[15];
245 }
246 
247 template <typename T>
248 Vector3<T> Matrix4x4<T>::Transform(const Vector3<T> &v) const
249 {
250     T w = (m30 * v.x + m31 * v.y + m32 * v.z + m33);
251     T invW = w > 0 ? static_cast<T>(1.0) / w : static_cast<T>(1.0);
252     return Vector3<T>(
253         (m00 * v.x + m01 * v.y + m02 * v.z + m03) * invW,
254         (m10 * v.x + m11 * v.y + m12 * v.z + m13) * invW,
255         (m20 * v.x + m21 * v.y + m22 * v.z + m23) * invW
256     );
257 }
258 
259 template <typename T>
260 Matrix4x4<T> Matrix4x4<T>::operator*(const Matrix4x4<T> &m) const
261 {
262     return Matrix4x4<T>(
263         m00 * m.m00 + m01 * m.m10 + m02 * m.m20 + m03 * m.m30,
264         m00 * m.m01 + m01 * m.m11 + m02 * m.m21 + m03 * m.m31,
265         m00 * m.m02 + m01 * m.m12 + m02 * m.m22 + m03 * m.m32,
266         m00 * m.m03 + m01 * m.m13 + m02 * m.m23 + m03 * m.m33,
267 
268         m10 * m.m00 + m11 * m.m10 + m12 * m.m20 + m13 * m.m30,
269         m10 * m.m01 + m11 * m.m11 + m12 * m.m21 + m13 * m.m31,
270         m10 * m.m02 + m11 * m.m12 + m12 * m.m22 + m13 * m.m32,
271         m10 * m.m03 + m11 * m.m13 + m12 * m.m23 + m13 * m.m33,
272 
273         m20 * m.m00 + m21 * m.m10 + m22 * m.m20 + m23 * m.m30,
274         m20 * m.m01 + m21 * m.m11 + m22 * m.m21 + m23 * m.m31,
275         m20 * m.m02 + m21 * m.m12 + m22 * m.m22 + m23 * m.m32,
276         m20 * m.m03 + m21 * m.m13 + m22 * m.m23 + m23 * m.m33,
277 
278         m30 * m.m00 + m31 * m.m10 + m32 * m.m20 + m33 * m.m30,
279         m30 * m.m01 + m31 * m.m11 + m32 * m.m21 + m33 * m.m31,
280         m30 * m.m02 + m31 * m.m12 + m32 * m.m22 + m33 * m.m32,
281         m30 * m.m03 + m31 * m.m13 + m32 * m.m23 + m33 * m.m33
282     );
283 }
284 
285 template <typename T>
286 T Matrix4x4<T>::operator[](int i) const
287 {
288     assert(i >= 0 && i < 16);
289     return m[i];
290 }
291 
292 template <typename T>
293 T Matrix4x4<T>::operator[](int i)
294 {
295     assert(i >= 0 && i < 16);
296     return m[i];
297 }
298 
299 
300 template <typename T>
301 T Matrix4x4<T>::operator()(int row, int col) const
302 {
303     assert(row >=0 && row < 4 && col >= 0 && row < 4);
304     return row << 2 + col;
305 }
306 template <typename T>
307 T Matrix4x4<T>::operator()(int row, int col)
308 {
309     assert(row >=0 && row < 4 && col >= 0 && row < 4);
310     return row << 2 + col;
311 }
312 
313 template <typename T>
314 ostream &operator<<(ostream &out, const Matrix4x4<T> &m)
315 {
316     for (int i = 0; i < 16; ++i)
317     {
318         out << m[i];
319         if ((i + 1) % 4 == 0)
320             out << endl;
321         else if (i != 15)
322             out << ",";
323 
324     }
325     return out;
326 }
327 
328 typedef Matrix4x4<float> Matrix4x4f;
329 typedef Matrix4x4<double> Matrix4x4d;
330 
331 #endif

参考文献:

《3D数学基础:图形与游戏开发》

《3D游戏与计算机图形学中的数学方法》

《3D游戏引擎设计:实时计算机图形学的应用方法》

 

posted @ 2022-07-02 17:07  毅安  阅读(221)  评论(0编辑  收藏  举报