草庐IT

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

Primary Code 2023-03-28 原文

  在游戏开发中,矩阵具有十分重要的地位,但他也只是我们操作点和向量的一个工具,在这里我们使用列优先规则来存储矩阵。在这里矩阵最主要的两个作用是: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游戏引擎设计:实时计算机图形学的应用方法》

 

有关从零开始游戏开发——2.2 矩阵的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  3. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  4. ruby - 在 Windows 机器上使用 Ruby 进行开发是否会适得其反? - 2

    这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby​​-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub

  5. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  6. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  7. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  8. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  9. Observability:从零开始创建 Java 微服务并监控它 (二) - 2

    这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/

  10. 微信小程序开发入门与实战(Behaviors使用) - 2

    @作者:SYFStrive @博客首页:HomePage📜:微信小程序📌:个人社区(欢迎大佬们加入)👉:社区链接🔗📌:觉得文章不错可以点点关注👉:专栏连接🔗💃:感谢支持,学累了可以先看小段由小胖给大家带来的街舞👉微信小程序(🔥)目录自定义组件-behaviors    1、什么是behaviors    2、behaviors的工作方式    3、创建behavior    4、导入并使用behavior    5、behavior中所有可用的节点    6、同名字段的覆盖和组合规则总结最后自定义组件-behaviors    1、什么是behaviorsbehaviors是小程序中,用于实现

随机推荐