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 }
四维矩阵
然后,我们定义一个四维矩阵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 }
+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祝威+悄悄在此留下版了个权的信息说:
总结
本篇就写这些,今后再写一些相关的内容。