zoukankan      html  css  js  c++  java
  • 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祝威+悄悄在此留下版了个权的信息说:

    总结

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

  • 相关阅读:
    正敲着代码,鼠标坏了!
    DB2 OLAP函数的使用(转)
    修剪矩形
    classpath和环境变量设置(转)
    MyEclipse断点调试JavaScript浅析(转)
    Onunload和onbeforeunload方法的异同
    db2中的coalesce函数(转)
    db2:根据TABLEID找table
    [转]DB2行列转换
    DB2删除数据时的小技巧
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/matrix-vs-projection.html
Copyright © 2011-2022 走看看