从零开始游戏开发——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游戏引擎设计:实时计算机图形学的应用方法》
本文来自博客园,作者:毅安,转载请注明原文链接:https://www.cnblogs.com/primarycode/p/16415167.html,文章内容同步更新微信公众号:“游戏开发实战”或“GamePrimaryCode”