转载

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

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

定义矩阵

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

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

四维向量

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

Opengl中矩阵和perspective/ortho的相互转换
  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中的定义)

Opengl中矩阵和perspective/ortho的相互转换
  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             //aspectRatio = 1.0f / matrix[0, 0] / tanHalfFovy; 16             aspectRatio = matrix[1, 1] / matrix[0, 0]; 17             zNear = matrix[3, 2] / (1 - matrix[2, 2]); 18             zFar = matrix[3, 2] / (1 + matrix[2, 2]); 19  20             if (matrix[0, 0] == 0.0f || matrix[1, 1] == 0.0f || matrix[2, 2] == 0.0f) 21             { 22                 return false; 23             } 24  25             if (matrix[1, 0] != 0.0f || matrix[3, 0] != 0.0f 26                 || matrix[0, 1] != 0.0f || matrix[3, 1] != 0.0f 27                 || matrix[0, 2] != 0.0f || matrix[1, 2] != 0.0f 28                 || matrix[0, 3] != 0.0f || matrix[1, 3] != 0.0f || matrix[3, 3] != 0.0f) 29             { 30                 return false; 31             } 32  33             if (matrix[3, 2] != -1.0f) 34             { 35                 return false; 36             } 37  38             return true; 39         }

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

总结

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

正文到此结束
Loading...