Opengl中矩阵和perspective/ortho的相互转换
定义矩阵
Opengl变换需要用四维矩阵。我们来定义这样的矩阵。
+BIT祝威+悄悄在此留下版了个权的信息说:四维向量
首先,我们定义一个四维向量vec4。
1 /// <summary>vec4
2 /// Represents a four dimensional vector.
3 /// </summary>
4 public struct vec4
5 {
6 public float x;
7 public float y;
8 public float z;
9 public float w;
10
11 public float this[int index]
12 {
13 get
14 {
15 if (index == 0) return x;
16 else if (index == 1) return y;
17 else if (index == 2) return z;
18 else if (index == 3) return w;
19 else throw new Exception("Out of range.");
20 }
21 set
22 {
23 if (index == 0) x = value;
24 else if (index == 1) y = value;
25 else if (index == 2) z = value;
26 else if (index == 3) w = value;
27 else throw new Exception("Out of range.");
28 }
29 }
30
31 public vec4(float s)
32 {
33 x = y = z = w = s;
34 }
35
36 public vec4(float x, float y, float z, float w)
37 {
38 this.x = x;
39 this.y = y;
40 this.z = z;
41 this.w = w;
42 }
43
44 public vec4(vec4 v)
45 {
46 this.x = v.x;
47 this.y = v.y;
48 this.z = v.z;
49 this.w = v.w;
50 }
51
52 public vec4(vec3 xyz, float w)
53 {
54 this.x = xyz.x;
55 this.y = xyz.y;
56 this.z = xyz.z;
57 this.w = w;
58 }
59
60 public static vec4 operator +(vec4 lhs, vec4 rhs)
61 {
62 return new vec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
63 }
64
65 public static vec4 operator +(vec4 lhs, float rhs)
66 {
67 return new vec4(lhs.x + rhs, lhs.y + rhs, lhs.z + rhs, lhs.w + rhs);
68 }
69
70 public static vec4 operator -(vec4 lhs, float rhs)
71 {
72 return new vec4(lhs.x - rhs, lhs.y - rhs, lhs.z - rhs, lhs.w - rhs);
73 }
74
75 public static vec4 operator -(vec4 lhs, vec4 rhs)
76 {
77 return new vec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w);
78 }
79
80 public static vec4 operator *(vec4 self, float s)
81 {
82 return new vec4(self.x * s, self.y * s, self.z * s, self.w * s);
83 }
84
85 public static vec4 operator *(float lhs, vec4 rhs)
86 {
87 return new vec4(rhs.x * lhs, rhs.y * lhs, rhs.z * lhs, rhs.w * lhs);
88 }
89
90 public static vec4 operator *(vec4 lhs, vec4 rhs)
91 {
92 return new vec4(rhs.x * lhs.x, rhs.y * lhs.y, rhs.z * lhs.z, rhs.w * lhs.w);
93 }
94
95 public static vec4 operator /(vec4 lhs, float rhs)
96 {
97 return new vec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs);
98 }
99
100 public float[] to_array()
101 {
102 return new[] { x, y, z, w };
103 }
104
105 /// <summary>
106 /// 归一化向量
107 /// </summary>
108 /// <param name="vector"></param>
109 /// <returns></returns>
110 public void Normalize()
111 {
112 var frt = (float)Math.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
113
114 this.x = x / frt;
115 this.y = y / frt;
116 this.z = z / frt;
117 this.w = w / frt;
118 }
119
120 public override string ToString()
121 {
122 return string.Format("{0:0.00},{1:0.00},{2:0.00},{3:0.00}", x, y, z, w);
123 }
124 }
四维矩阵
然后,我们定义一个四维矩阵mat4。它用4个vec4表示,每个vec4代表一个列向量。(这是glm中的定义)
1 /// <summary>mat4
2 /// Represents a 4x4 matrix.
3 /// </summary>
4 public struct mat4
5 {
6 public override string ToString()
7 {
8 if (cols == null)
9 { return "<null>"; }
10 var builder = new System.Text.StringBuilder();
11 for (int i = 0; i < cols.Length; i++)
12 {
13 builder.Append(cols[i]);
14 builder.Append(" + ");
15 }
16 return builder.ToString();
17 //return base.ToString();
18 }
19 #region Construction
20
21 /// <summary>
22 /// Initializes a new instance of the <see cref="mat4"/> struct.
23 /// This matrix is the identity matrix scaled by <paramref name="scale"/>.
24 /// </summary>
25 /// <param name="scale">The scale.</param>
26 public mat4(float scale)
27 {
28 cols = new[]
29 {
30 new vec4(scale, 0.0f, 0.0f, 0.0f),
31 new vec4(0.0f, scale, 0.0f, 0.0f),
32 new vec4(0.0f, 0.0f, scale, 0.0f),
33 new vec4(0.0f, 0.0f, 0.0f, scale),
34 };
35 }
36
37 /// <summary>
38 /// Initializes a new instance of the <see cref="mat4"/> struct.
39 /// The matrix is initialised with the <paramref name="cols"/>.
40 /// </summary>
41 /// <param name="cols">The colums of the matrix.</param>
42 public mat4(vec4[] cols)
43 {
44 this.cols = new[] { cols[0], cols[1], cols[2], cols[3] };
45 }
46
47 public mat4(vec4 a, vec4 b, vec4 c, vec4 d)
48 {
49 this.cols = new[]
50 {
51 a, b, c, d
52 };
53 }
54
55 /// <summary>
56 /// Creates an identity matrix.
57 /// </summary>
58 /// <returns>A new identity matrix.</returns>
59 public static mat4 identity()
60 {
61 return new mat4
62 {
63 cols = new[]
64 {
65 new vec4(1,0,0,0),
66 new vec4(0,1,0,0),
67 new vec4(0,0,1,0),
68 new vec4(0,0,0,1)
69 }
70 };
71 }
72
73 #endregion
74
75 #region Index Access
76
77 /// <summary>
78 /// Gets or sets the <see cref="vec4"/> column at the specified index.
79 /// </summary>
80 /// <value>
81 /// The <see cref="vec4"/> column.
82 /// </value>
83 /// <param name="column">The column index.</param>
84 /// <returns>The column at index <paramref name="column"/>.</returns>
85 public vec4 this[int column]
86 {
87 get { return cols[column]; }
88 set { cols[column] = value; }
89 }
90
91 /// <summary>
92 /// Gets or sets the element at <paramref name="column"/> and <paramref name="row"/>.
93 /// </summary>
94 /// <value>
95 /// The element at <paramref name="column"/> and <paramref name="row"/>.
96 /// </value>
97 /// <param name="column">The column index.</param>
98 /// <param name="row">The row index.</param>
99 /// <returns>
100 /// The element at <paramref name="column"/> and <paramref name="row"/>.
101 /// </returns>
102 public float this[int column, int row]
103 {
104 get { return cols[column][row]; }
105 set { cols[column][row] = value; }
106 }
107
108 #endregion
109
110 #region Conversion
111
112 /// <summary>
113 /// Returns the matrix as a flat array of elements, column major.
114 /// </summary>
115 /// <returns></returns>
116 public float[] to_array()
117 {
118 return cols.SelectMany(v => v.to_array()).ToArray();
119 }
120
121 /// <summary>
122 /// Returns the <see cref="mat3"/> portion of this matrix.
123 /// </summary>
124 /// <returns>The <see cref="mat3"/> portion of this matrix.</returns>
125 public mat3 to_mat3()
126 {
127 return new mat3(new[] {
128 new vec3(cols[0][0], cols[0][1], cols[0][2]),
129 new vec3(cols[1][0], cols[1][1], cols[1][2]),
130 new vec3(cols[2][0], cols[2][1], cols[2][2])});
131 }
132
133 #endregion
134
135 #region Multiplication
136
137 /// <summary>
138 /// Multiplies the <paramref name="lhs"/> matrix by the <paramref name="rhs"/> vector.
139 /// </summary>
140 /// <param name="lhs">The LHS matrix.</param>
141 /// <param name="rhs">The RHS vector.</param>
142 /// <returns>The product of <paramref name="lhs"/> and <paramref name="rhs"/>.</returns>
143 public static vec4 operator *(mat4 lhs, vec4 rhs)
144 {
145 return new vec4(
146 lhs[0, 0] * rhs[0] + lhs[1, 0] * rhs[1] + lhs[2, 0] * rhs[2] + lhs[3, 0] * rhs[3],
147 lhs[0, 1] * rhs[0] + lhs[1, 1] * rhs[1] + lhs[2, 1] * rhs[2] + lhs[3, 1] * rhs[3],
148 lhs[0, 2] * rhs[0] + lhs[1, 2] * rhs[1] + lhs[2, 2] * rhs[2] + lhs[3, 2] * rhs[3],
149 lhs[0, 3] * rhs[0] + lhs[1, 3] * rhs[1] + lhs[2, 3] * rhs[2] + lhs[3, 3] * rhs[3]
150 );
151 }
152
153 /// <summary>
154 /// Multiplies the <paramref name="lhs"/> matrix by the <paramref name="rhs"/> matrix.
155 /// </summary>
156 /// <param name="lhs">The LHS matrix.</param>
157 /// <param name="rhs">The RHS matrix.</param>
158 /// <returns>The product of <paramref name="lhs"/> and <paramref name="rhs"/>.</returns>
159 public static mat4 operator *(mat4 lhs, mat4 rhs)
160 {
161 mat4 result = new mat4(
162 new vec4(
163 lhs[0][0] * rhs[0][0] + lhs[1][0] * rhs[0][1] + lhs[2][0] * rhs[0][2] + lhs[3][0] * rhs[0][3],
164 lhs[0][1] * rhs[0][0] + lhs[1][1] * rhs[0][1] + lhs[2][1] * rhs[0][2] + lhs[3][1] * rhs[0][3],
165 lhs[0][2] * rhs[0][0] + lhs[1][2] * rhs[0][1] + lhs[2][2] * rhs[0][2] + lhs[3][2] * rhs[0][3],
166 lhs[0][3] * rhs[0][0] + lhs[1][3] * rhs[0][1] + lhs[2][3] * rhs[0][2] + lhs[3][3] * rhs[0][3]
167 ),
168 new vec4(
169 lhs[0][0] * rhs[1][0] + lhs[1][0] * rhs[1][1] + lhs[2][0] * rhs[1][2] + lhs[3][0] * rhs[1][3],
170 lhs[0][1] * rhs[1][0] + lhs[1][1] * rhs[1][1] + lhs[2][1] * rhs[1][2] + lhs[3][1] * rhs[1][3],
171 lhs[0][2] * rhs[1][0] + lhs[1][2] * rhs[1][1] + lhs[2][2] * rhs[1][2] + lhs[3][2] * rhs[1][3],
172 lhs[0][3] * rhs[1][0] + lhs[1][3] * rhs[1][1] + lhs[2][3] * rhs[1][2] + lhs[3][3] * rhs[1][3]
173 ),
174 new vec4(
175 lhs[0][0] * rhs[2][0] + lhs[1][0] * rhs[2][1] + lhs[2][0] * rhs[2][2] + lhs[3][0] * rhs[2][3],
176 lhs[0][1] * rhs[2][0] + lhs[1][1] * rhs[2][1] + lhs[2][1] * rhs[2][2] + lhs[3][1] * rhs[2][3],
177 lhs[0][2] * rhs[2][0] + lhs[1][2] * rhs[2][1] + lhs[2][2] * rhs[2][2] + lhs[3][2] * rhs[2][3],
178 lhs[0][3] * rhs[2][0] + lhs[1][3] * rhs[2][1] + lhs[2][3] * rhs[2][2] + lhs[3][3] * rhs[2][3]
179 ),
180 new vec4(
181 lhs[0][0] * rhs[3][0] + lhs[1][0] * rhs[3][1] + lhs[2][0] * rhs[3][2] + lhs[3][0] * rhs[3][3],
182 lhs[0][1] * rhs[3][0] + lhs[1][1] * rhs[3][1] + lhs[2][1] * rhs[3][2] + lhs[3][1] * rhs[3][3],
183 lhs[0][2] * rhs[3][0] + lhs[1][2] * rhs[3][1] + lhs[2][2] * rhs[3][2] + lhs[3][2] * rhs[3][3],
184 lhs[0][3] * rhs[3][0] + lhs[1][3] * rhs[3][1] + lhs[2][3] * rhs[3][2] + lhs[3][3] * rhs[3][3]
185 )
186 );
187
188 return result;
189 }
190
191 public static mat4 operator *(mat4 lhs, float s)
192 {
193 return new mat4(new[]
194 {
195 lhs[0]*s,
196 lhs[1]*s,
197 lhs[2]*s,
198 lhs[3]*s
199 });
200 }
201
202 #endregion
203
204 /// <summary>
205 /// The columms of the matrix.
206 /// </summary>
207 private vec4[] cols;
208 }
+BIT祝威+悄悄在此留下版了个权的信息说:
矩阵与ortho的转换
从ortho到矩阵
根据传入的参数可以获得一个代表平行投影的矩阵。
1 /// <summary>
2 /// Creates a matrix for an orthographic parallel viewing volume.
3 /// </summary>
4 /// <param name="left">The left.</param>
5 /// <param name="right">The right.</param>
6 /// <param name="bottom">The bottom.</param>
7 /// <param name="top">The top.</param>
8 /// <param name="zNear">The z near.</param>
9 /// <param name="zFar">The z far.</param>
10 /// <returns></returns>
11 public static mat4 ortho(float left, float right, float bottom, float top, float zNear, float zFar)
12 {
13 var result = mat4.identity();
14 result[0, 0] = (2f) / (right - left);
15 result[1, 1] = (2f) / (top - bottom);
16 result[2, 2] = -(2f) / (zFar - zNear);
17 result[3, 0] = -(right + left) / (right - left);
18 result[3, 1] = -(top + bottom) / (top - bottom);
19 result[3, 2] = -(zFar + zNear) / (zFar - zNear);
20 return result;
21 }
从矩阵到ortho
反过来,当我们手上有一个矩阵时,我们可以分析出这个矩阵是由ortho用怎样的参数计算得到的。(当然,并非所有矩阵都能用ortho计算出来)
1 /// <summary>
2 /// 如果此矩阵是glm.ortho()的结果,那么返回glm.ortho()的各个参数值。
3 /// </summary>
4 /// <param name="matrix"></param>
5 /// <param name="left"></param>
6 /// <param name="right"></param>
7 /// <param name="bottom"></param>
8 /// <param name="top"></param>
9 /// <param name="zNear"></param>
10 /// <param name="zFar"></param>
11 /// <returns></returns>
12 public static bool TryParse(this mat4 matrix,
13 out float left, out float right, out float bottom, out float top, out float zNear, out float zFar)
14 {
15 {
16 float negHalfLeftRight = matrix[3, 0] / matrix[0, 0];
17 float halfRightMinusLeft = 1.0f / matrix[0][0];
18 left = -(halfRightMinusLeft + negHalfLeftRight);
19 right = halfRightMinusLeft - negHalfLeftRight;
20 }
21
22 {
23 float negHalfBottomTop = matrix[3, 1] / matrix[1, 1];
24 float halfTopMinusBottom = 1.0f / matrix[1, 1];
25 bottom = -(halfTopMinusBottom + negHalfBottomTop);
26 top = halfTopMinusBottom - negHalfBottomTop;
27 }
28
29 {
30 float halfNearFar = matrix[3, 2] / matrix[2, 2];
31 float negHalfFarMinusNear = 1.0f / matrix[2, 2];
32 zNear = negHalfFarMinusNear + halfNearFar;
33 zFar = halfNearFar - negHalfFarMinusNear;
34 }
35
36 if (matrix[0, 0] == 0.0f || matrix[1, 1] == 0.0f || matrix[2, 2] == 0.0f)
37 {
38 return false;
39 }
40
41 if (matrix[1, 0] != 0.0f || matrix[2, 0] != 0.0f
42 || matrix[0, 1] != 0.0f || matrix[2, 1] != 0.0f
43 || matrix[0, 2] != 0.0f || matrix[1, 2] != 0.0f
44 || matrix[0, 3] != 0.0f || matrix[1, 3] != 0.0f || matrix[2, 3] != 0.0f)
45 {
46 return false;
47 }
48
49 if (matrix[3, 3] != 1.0f)
50 {
51 return false;
52 }
53
54 return true;
55 }
矩阵与perpspective的转换
从perspective到矩阵
根据传入的参数可以获得一个代表透视投影的矩阵。
1 /// <summary>
2 /// Creates a perspective transformation matrix.
3 /// </summary>
4 /// <param name="fovy">The field of view angle, in radians.</param>
5 /// <param name="aspect">The aspect ratio.</param>
6 /// <param name="zNear">The near depth clipping plane.</param>
7 /// <param name="zFar">The far depth clipping plane.</param>
8 /// <returns>A <see cref="mat4"/> that contains the projection matrix for the perspective transformation.</returns>
9 public static mat4 perspective(float fovy, float aspect, float zNear, float zFar)
10 {
11 var result = mat4.identity();
12 float tangent = (float)Math.Tan(fovy / 2.0f);
13 float height = zNear * tangent;
14 float width = height * aspect;
15 float l = -width, r = width, b = -height, t = height, n = zNear, f = zFar;
16 result[0, 0] = 2.0f * n / (r - l);// = 2.0f * zNear / (2.0f * zNear * tangent * aspect)
17 result[1, 1] = 2.0f * n / (t - b);// = 2.0f * zNear / (2.0f * zNear * tangent)
18 //result[2, 0] = (r + l) / (r - l);// = 0.0f
19 //result[2, 1] = (t + b) / (t - b);// = 0.0f
20 result[2, 2] = -(f + n) / (f - n);
21 result[2, 3] = -1.0f;
22 result[3, 2] = -(2.0f * f * n) / (f - n);
23 result[3, 3] = 0.0f;
24
25 return result;
26 }
从矩阵到perspective
反过来,当我们手上有一个矩阵时,我们可以分析出这个矩阵是由perpspective用怎样的参数计算得到的。(当然,并非所有矩阵都能用perpspective计算出来)
1 /// <summary>
2 /// 如果此矩阵是glm.perspective()的结果,那么返回glm.perspective()的各个参数值。
3 /// </summary>
4 /// <param name="matrix"></param>
5 /// <param name="fovy"></param>
6 /// <param name="aspectRatio"></param>
7 /// <param name="zNear"></param>
8 /// <param name="zFar"></param>
9 /// <returns></returns>
10 public static bool TryParse(this mat4 matrix,
11 out float fovy, out float aspectRatio, out float zNear, out float zFar)
12 {
13 float tanHalfFovy = 1.0f / matrix[1, 1];
14 fovy = 2 * (float)(Math.Atan(tanHalfFovy));
15 if (fovy < 0) { fovy = -fovy; }
16 //aspectRatio = 1.0f / matrix[0, 0] / tanHalfFovy;
17 aspectRatio = matrix[1, 1] / matrix[0, 0];
18 if (matrix[2, 2] == 1.0f)
19 {
20 zFar = 0.0f;
21 zNear = 0.0f;
22 }
23 else if (matrix[2, 2] == -1.0f)
24 {
25 zNear = 0.0f;
26 zFar = float.PositiveInfinity;
27 }
28 else
29 {
30 zNear = matrix[3, 2] / (matrix[2, 2] - 1);
31 zFar = matrix[3, 2] / (matrix[2, 2] + 1);
32 }
33
34 if (matrix[0, 0] == 0.0f || matrix[1, 1] == 0.0f || matrix[2, 2] == 0.0f)
35 {
36 return false;
37 }
38
39 if (matrix[1, 0] != 0.0f || matrix[3, 0] != 0.0f
40 || matrix[0, 1] != 0.0f || matrix[3, 1] != 0.0f
41 || matrix[0, 2] != 0.0f || matrix[1, 2] != 0.0f
42 || matrix[0, 3] != 0.0f || matrix[1, 3] != 0.0f || matrix[3, 3] != 0.0f)
43 {
44 return false;
45 }
46
47 if (matrix[2, 3] != -1.0f)
48 {
49 return false;
50 }
51
52 return true;
53 }
+BIT祝威+悄悄在此留下版了个权的信息说:
总结
本篇就写这些,今后再写一些相关的内容。