Opengl中矩阵和perspective/ortho的相互转换

Opengl中矩阵和perspective/ortho的相互转换

定义矩阵

Opengl变换需要用四维矩阵。我们来定义这样的矩阵。

+BIT祝威+悄悄在此留下版了个权的信息说:

四维向量

首先,我们定义一个四维向量vec4。

  1     /// <summary>
  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     }
vec4

四维矩阵

然后,我们定义一个四维矩阵mat4。它用4个vec4表示,每个vec4代表一个列向量。(这是glm中的定义)

  1     /// <summary>
  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     }
mat4

 

+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祝威+悄悄在此留下版了个权的信息说:

总结

本篇就写这些,今后再写一些相关的内容。

你可能感兴趣的:(Opengl中矩阵和perspective/ortho的相互转换)