Opengl中矩阵和perspective/ortho的相互转换
2015-08-27 00:38
274 查看
[b]Opengl中矩阵和perspective/ortho的相互转换 [/b]
+BIT祝威+悄悄在此留下版了个权的信息说:
mat4
+BIT祝威+悄悄在此留下版了个权的信息说:
+BIT祝威+悄悄在此留下版了个权的信息说:
定义矩阵
Opengl变换需要用四维矩阵。我们来定义这样的矩阵。+BIT祝威+悄悄在此留下版了个权的信息说:
四维向量
首先,我们定义一个四维向量vec4。/// <summary> /// Represents a 4x4 matrix. /// </summary> public struct mat4 { public override string ToString() { if (cols == null) { return "<null>"; } var builder = new System.Text.StringBuilder(); for (int i = 0; i < cols.Length; i++) { builder.Append(cols[i]); builder.Append(" + "); } return builder.ToString(); //return base.ToString(); } #region Construction /// <summary> /// Initializes a new instance of the <see cref="mat4"/> struct. /// This matrix is the identity matrix scaled by <paramref name="scale"/>. /// </summary> /// <param name="scale">The scale.</param> public mat4(float scale) { cols = new[] { new vec4(scale, 0.0f, 0.0f, 0.0f), new vec4(0.0f, scale, 0.0f, 0.0f), new vec4(0.0f, 0.0f, scale, 0.0f), new vec4(0.0f, 0.0f, 0.0f, scale), }; } /// <summary> /// Initializes a new instance of the <see cref="mat4"/> struct. /// The matrix is initialised with the <paramref name="cols"/>. /// </summary> /// <param name="cols">The colums of the matrix.</param> public mat4(vec4[] cols) { this.cols = new[] { cols[0], cols[1], cols[2], cols[3] }; } public mat4(vec4 a, vec4 b, vec4 c, vec4 d) { this.cols = new[] { a, b, c, d }; } /// <summary> /// Creates an identity matrix. /// </summary> /// <returns>A new identity matrix.</returns> public static mat4 identity() { return new mat4 { cols = new[] { new vec4(1,0,0,0), new vec4(0,1,0,0), new vec4(0,0,1,0), new vec4(0,0,0,1) } }; } #endregion #region Index Access /// <summary> /// Gets or sets the <see cref="vec4"/> column at the specified index. /// </summary> /// <value> /// The <see cref="vec4"/> column. /// </value> /// <param name="column">The column index.</param> /// <returns>The column at index <paramref name="column"/>.</returns> public vec4 this[int column] { get { return cols[column]; } set { cols[column] = value; } } /// <summary> /// Gets or sets the element at <paramref name="column"/> and <paramref name="row"/>. /// </summary> /// <value> /// The element at <paramref name="column"/> and <paramref name="row"/>. /// </value> /// <param name="column">The column index.</param> /// <param name="row">The row index.</param> /// <returns> /// The element at <paramref name="column"/> and <paramref name="row"/>. /// </returns> public float this[int column, int row] { get { return cols[column][row]; } set { cols[column][row] = value; } } #endregion #region Conversion /// <summary> /// Returns the matrix as a flat array of elements, column major. /// </summary> /// <returns></returns> public float[] to_array() { return cols.SelectMany(v => v.to_array()).ToArray(); } /// <summary> /// Returns the <see cref="mat3"/> portion of this matrix. /// </summary> /// <returns>The <see cref="mat3"/> portion of this matrix.</returns> public mat3 to_mat3() { return new mat3(new[] { new vec3(cols[0][0], cols[0][1], cols[0][2]), new vec3(cols[1][0], cols[1][1], cols[1][2]), new vec3(cols[2][0], cols[2][1], cols[2][2])}); } #endregion #region Multiplication /// <summary> /// Multiplies the <paramref name="lhs"/> matrix by the <paramref name="rhs"/> vector. /// </summary> /// <param name="lhs">The LHS matrix.</param> /// <param name="rhs">The RHS vector.</param> /// <returns>The product of <paramref name="lhs"/> and <paramref name="rhs"/>.</returns> public static vec4 operator *(mat4 lhs, vec4 rhs) { return new vec4( lhs[0, 0] * rhs[0] + lhs[1, 0] * rhs[1] + lhs[2, 0] * rhs[2] + lhs[3, 0] * rhs[3], lhs[0, 1] * rhs[0] + lhs[1, 1] * rhs[1] + lhs[2, 1] * rhs[2] + lhs[3, 1] * rhs[3], lhs[0, 2] * rhs[0] + lhs[1, 2] * rhs[1] + lhs[2, 2] * rhs[2] + lhs[3, 2] * rhs[3], lhs[0, 3] * rhs[0] + lhs[1, 3] * rhs[1] + lhs[2, 3] * rhs[2] + lhs[3, 3] * rhs[3] ); } /// <summary> /// Multiplies the <paramref name="lhs"/> matrix by the <paramref name="rhs"/> matrix. /// </summary> /// <param name="lhs">The LHS matrix.</param> /// <param name="rhs">The RHS matrix.</param> /// <returns>The product of <paramref name="lhs"/> and <paramref name="rhs"/>.</returns> public static mat4 operator *(mat4 lhs, mat4 rhs) { mat4 result = new mat4( new vec4( lhs[0][0] * rhs[0][0] + lhs[1][0] * rhs[0][1] + lhs[2][0] * rhs[0][2] + lhs[3][0] * rhs[0][3], lhs[0][1] * rhs[0][0] + lhs[1][1] * rhs[0][1] + lhs[2][1] * rhs[0][2] + lhs[3][1] * rhs[0][3], lhs[0][2] * rhs[0][0] + lhs[1][2] * rhs[0][1] + lhs[2][2] * rhs[0][2] + lhs[3][2] * rhs[0][3], lhs[0][3] * rhs[0][0] + lhs[1][3] * rhs[0][1] + lhs[2][3] * rhs[0][2] + lhs[3][3] * rhs[0][3] ), new vec4( lhs[0][0] * rhs[1][0] + lhs[1][0] * rhs[1][1] + lhs[2][0] * rhs[1][2] + lhs[3][0] * rhs[1][3], lhs[0][1] * rhs[1][0] + lhs[1][1] * rhs[1][1] + lhs[2][1] * rhs[1][2] + lhs[3][1] * rhs[1][3], lhs[0][2] * rhs[1][0] + lhs[1][2] * rhs[1][1] + lhs[2][2] * rhs[1][2] + lhs[3][2] * rhs[1][3], lhs[0][3] * rhs[1][0] + lhs[1][3] * rhs[1][1] + lhs[2][3] * rhs[1][2] + lhs[3][3] * rhs[1][3] ), new vec4( lhs[0][0] * rhs[2][0] + lhs[1][0] * rhs[2][1] + lhs[2][0] * rhs[2][2] + lhs[3][0] * rhs[2][3], lhs[0][1] * rhs[2][0] + lhs[1][1] * rhs[2][1] + lhs[2][1] * rhs[2][2] + lhs[3][1] * rhs[2][3], lhs[0][2] * rhs[2][0] + lhs[1][2] * rhs[2][1] + lhs[2][2] * rhs[2][2] + lhs[3][2] * rhs[2][3], lhs[0][3] * rhs[2][0] + lhs[1][3] * rhs[2][1] + lhs[2][3] * rhs[2][2] + lhs[3][3] * rhs[2][3] ), new vec4( lhs[0][0] * rhs[3][0] + lhs[1][0] * rhs[3][1] + lhs[2][0] * rhs[3][2] + lhs[3][0] * rhs[3][3], lhs[0][1] * rhs[3][0] + lhs[1][1] * rhs[3][1] + lhs[2][1] * rhs[3][2] + lhs[3][1] * rhs[3][3], lhs[0][2] * rhs[3][0] + lhs[1][2] * rhs[3][1] + lhs[2][2] * rhs[3][2] + lhs[3][2] * rhs[3][3], lhs[0][3] * rhs[3][0] + lhs[1][3] * rhs[3][1] + lhs[2][3] * rhs[3][2] + lhs[3][3] * rhs[3][3] ) ); return result; } public static mat4 operator *(mat4 lhs, float s) { return new mat4(new[] { lhs[0]*s, lhs[1]*s, lhs[2]*s, lhs[3]*s }); } #endregion /// <summary> /// The columms of the matrix. /// </summary> private vec4[] cols; }
mat4
+BIT祝威+悄悄在此留下版了个权的信息说:
矩阵与ortho的转换
从ortho到矩阵
根据传入的参数可以获得一个代表平行投影的矩阵。/// <summary> /// Creates a matrix for an orthographic parallel viewing volume. /// </summary> /// <param name="left">The left.</param> /// <param name="right">The right.</param> /// <param name="bottom">The bottom.</param> /// <param name="top">The top.</param> /// <param name="zNear">The z near.</param> /// <param name="zFar">The z far.</param> /// <returns></returns> public static mat4 ortho(float left, float right, float bottom, float top, float zNear, float zFar) { var result = mat4.identity(); result[0, 0] = (2f) / (right - left); result[1, 1] = (2f) / (top - bottom); result[2, 2] = -(2f) / (zFar - zNear); result[3, 0] = -(right + left) / (right - left); result[3, 1] = -(top + bottom) / (top - bottom); result[3, 2] = -(zFar + zNear) / (zFar - zNear); return result; }
从矩阵到ortho
反过来,当我们手上有一个矩阵时,我们可以分析出这个矩阵是由ortho用怎样的参数计算得到的。(当然,并非所有矩阵都能用ortho计算出来)/// <summary> /// 如果此矩阵是glm.ortho()的结果,那么返回glm.ortho()的各个参数值。 /// </summary> /// <param name="matrix"></param> /// <param name="left"></param> /// <param name="right"></param> /// <param name="bottom"></param> /// <param name="top"></param> /// <param name="zNear"></param> /// <param name="zFar"></param> /// <returns></returns> public static bool TryParse(this mat4 matrix, out float left, out float right, out float bottom, out float top, out float zNear, out float zFar) { { float negHalfLeftRight = matrix[3, 0] / matrix[0, 0]; float halfRightMinusLeft = 1.0f / matrix[0][0]; left = -(halfRightMinusLeft + negHalfLeftRight); right = halfRightMinusLeft - negHalfLeftRight; } { float negHalfBottomTop = matrix[3, 1] / matrix[1, 1]; float halfTopMinusBottom = 1.0f / matrix[1, 1]; bottom = -(halfTopMinusBottom + negHalfBottomTop); top = halfTopMinusBottom - negHalfBottomTop; } { float halfNearFar = matrix[3, 2] / matrix[2, 2]; float negHalfFarMinusNear = 1.0f / matrix[2, 2]; zNear = negHalfFarMinusNear + halfNearFar; zFar = halfNearFar - negHalfFarMinusNear; } if (matrix[0, 0] == 0.0f || matrix[1, 1] == 0.0f || matrix[2, 2] == 0.0f) { return false; } if (matrix[1, 0] != 0.0f || matrix[2, 0] != 0.0f || matrix[0, 1] != 0.0f || matrix[2, 1] != 0.0f || matrix[0, 2] != 0.0f || matrix[1, 2] != 0.0f || matrix[0, 3] != 0.0f || matrix[1, 3] != 0.0f || matrix[2, 3] != 0.0f) { return false; } if (matrix[3, 3] != 1.0f) { return false; } return true; }
矩阵与perpspective的转换
从perspective到矩阵
根据传入的参数可以获得一个代表透视投影的矩阵。/// <summary> /// Creates a perspective transformation matrix. /// </summary> /// <param name="fovy">The field of view angle, in radians.</param> /// <param name="aspect">The aspect ratio.</param> /// <param name="zNear">The near depth clipping plane.</param> /// <param name="zFar">The far depth clipping plane.</param> /// <returns>A <see cref="mat4"/> that contains the projection matrix for the perspective transformation.</returns> public static mat4 perspective(float fovy, float aspect, float zNear, float zFar) { var result = mat4.identity(); float tangent = (float)Math.Tan(fovy / 2.0f); float height = zNear * tangent; float width = height * aspect; float l = -width, r = width, b = -height, t = height, n = zNear, f = zFar; result[0, 0] = 2.0f * n / (r - l);// = 2.0f * zNear / (2.0f * zNear * tangent * aspect) result[1, 1] = 2.0f * n / (t - b);// = 2.0f * zNear / (2.0f * zNear * tangent) //result[2, 0] = (r + l) / (r - l);// = 0.0f //result[2, 1] = (t + b) / (t - b);// = 0.0f result[2, 2] = -(f + n) / (f - n); result[2, 3] = -1.0f; result[3, 2] = -(2.0f * f * n) / (f - n); result[3, 3] = 0.0f; return result; }
从矩阵到perspective
反过来,当我们手上有一个矩阵时,我们可以分析出这个矩阵是由perpspective用怎样的参数计算得到的。(当然,并非所有矩阵都能用perpspective计算出来)/// <summary> /// 如果此矩阵是glm.perspective()的结果,那么返回glm.perspective()的各个参数值。 /// </summary> /// <param name="matrix"></param> /// <param name="fovy"></param> /// <param name="aspectRatio"></param> /// <param name="zNear"></param> /// <param name="zFar"></param> /// <returns></returns> public static bool TryParse(this mat4 matrix, out float fovy, out float aspectRatio, out float zNear, out float zFar) { float tanHalfFovy = 1.0f / matrix[1, 1]; fovy = 2 * (float)(Math.Atan(tanHalfFovy)); if (fovy < 0) { fovy = -fovy; } //aspectRatio = 1.0f / matrix[0, 0] / tanHalfFovy; aspectRatio = matrix[1, 1] / matrix[0, 0]; if (matrix[2, 2] == 1.0f) { zFar = 0.0f; zNear = 0.0f; } else if (matrix[2, 2] == -1.0f) { zNear = 0.0f; zFar = float.PositiveInfinity; } else { zNear = matrix[3, 2] / (matrix[2, 2] - 1); zFar = matrix[3, 2] / (matrix[2, 2] + 1); } if (matrix[0, 0] == 0.0f || matrix[1, 1] == 0.0f || matrix[2, 2] == 0.0f) { return false; } if (matrix[1, 0] != 0.0f || matrix[3, 0] != 0.0f || matrix[0, 1] != 0.0f || matrix[3, 1] != 0.0f || matrix[0, 2] != 0.0f || matrix[1, 2] != 0.0f || matrix[0, 3] != 0.0f || matrix[1, 3] != 0.0f || matrix[3, 3] != 0.0f) { return false; } if (matrix[2, 3] != -1.0f) { return false; } return true; }
+BIT祝威+悄悄在此留下版了个权的信息说:
总结
本篇就写这些,今后再写一些相关的内容。相关文章推荐
- Hadoop(二)——分布式集群搭建
- ubuntu opera31.0安装flash
- 怎么将linux下的项目转换成windows的VS2010下的项目?
- linux和openwrt下更新源
- 将Linux代码移植到Windows的简单方法
- Hadoop之Reduce侧的联结
- shell
- windows下apache搭建php开发环境
- linux日常管理
- linux防火墙
- ecshop模板构建说明
- ECSHOP调用分类文章
- 开发监控云组态软件的组成
- linux内核字节序转换宏
- 在linux下查看内核版本、gcc版本、操作系统多少位等参数
- Nginx Log
- vmware使用已有linux系统的物理磁盘分区
- CENTOS JAVA 安装
- 如何在64位版本Linux上开发运行32位应用程序
- Openshift 添加 cron 定时任务