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

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

定义矩阵

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

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

四维向量

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

  1     /// 
  2     /// Represents a four dimensional vector.
  3     /// 
  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         /// 
106         /// 归一化向量
107         /// 
108         /// 
109         /// 
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     /// 
  2     /// Represents a 4x4 matrix.
  3     /// 
  4     public struct mat4
  5     {
  6         public override string ToString()
  7         {
  8             if (cols == null)
  9             { return ""; }
 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         /// 
 22         /// Initializes a new instance of the  struct.
 23         /// This matrix is the identity matrix scaled by .
 24         /// 
 25         /// The scale.
 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         /// 
 38         /// Initializes a new instance of the  struct.
 39         /// The matrix is initialised with the .
 40         /// 
 41         /// The colums of the matrix.
 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         /// 
 56         /// Creates an identity matrix.
 57         /// 
 58         /// A new identity matrix.
 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         /// 
 78         /// Gets or sets the  column at the specified index.
 79         /// 
 80         /// 
 81         /// The  column.
 82         /// 
 83         /// The column index.
 84         /// The column at index .
 85         public vec4 this[int column]
 86         {
 87             get { return cols[column]; }
 88             set { cols[column] = value; }
 89         }
 90 
 91         /// 
 92         /// Gets or sets the element at  and .
 93         /// 
 94         /// 
 95         /// The element at  and .
 96         /// 
 97         /// The column index.
 98         /// The row index.
 99         /// 
100         /// The element at  and .
101         /// 
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         /// 
113         /// Returns the matrix as a flat array of elements, column major.
114         /// 
115         /// 
116         public float[] to_array()
117         {
118             return cols.SelectMany(v => v.to_array()).ToArray();
119         }
120 
121         /// 
122         /// Returns the  portion of this matrix.
123         /// 
124         /// The  portion of this matrix.
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         /// 
138         /// Multiplies the  matrix by the  vector.
139         /// 
140         /// The LHS matrix.
141         /// The RHS vector.
142         /// The product of  and .
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         /// 
154         /// Multiplies the  matrix by the  matrix.
155         /// 
156         /// The LHS matrix.
157         /// The RHS matrix.
158         /// The product of  and .
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         /// 
205         /// The columms of the matrix.
206         /// 
207         private vec4[] cols;
208     }
mat4

 

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

矩阵与ortho的转换

从ortho到矩阵

根据传入的参数可以获得一个代表平行投影的矩阵。

 1         /// 
 2         /// Creates a matrix for an orthographic parallel viewing volume.
 3         /// 
 4         /// The left.
 5         /// The right.
 6         /// The bottom.
 7         /// The top.
 8         /// The z near.
 9         /// The z far.
10         /// 
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         /// 
 2         /// 如果此矩阵是glm.ortho()的结果,那么返回glm.ortho()的各个参数值。
 3         /// 
 4         /// 
 5         /// 
 6         /// 
 7         /// 
 8         /// 
 9         /// 
10         /// 
11         /// 
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         /// 
 2         /// Creates a perspective transformation matrix.
 3         /// 
 4         /// The field of view angle, in radians.
 5         /// The aspect ratio.
 6         /// The near depth clipping plane.
 7         /// The far depth clipping plane.
 8         /// A  that contains the projection matrix for the perspective transformation.
 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         /// 
 2         /// 如果此矩阵是glm.perspective()的结果,那么返回glm.perspective()的各个参数值。
 3         /// 
 4         /// 
 5         /// 
 6         /// 
 7         /// 
 8         /// 
 9         /// 
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的相互转换)