Opengl中矩阵和perspective/ortho的相互转换
Opengl中矩阵和perspective/ortho的相互转换
定义矩阵
Opengl变换需要用四维矩阵。我们来定义这样的矩阵。
四维向量
首先,我们定义一个四维向量vec4。
/// <summary>
/// Represents a four dimensional vector.
/// </summary>
public struct vec4
{
public float x;
public float y;
public float z;
public float w; public float this[int index]
{
get
{
if (index == ) return x;
else if (index == ) return y;
else if (index == ) return z;
else if (index == ) return w;
else throw new Exception("Out of range.");
}
set
{
if (index == ) x = value;
else if (index == ) y = value;
else if (index == ) z = value;
else if (index == ) w = value;
else throw new Exception("Out of range.");
}
} public vec4(float s)
{
x = y = z = w = s;
} public vec4(float x, float y, float z, float w)
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
} public vec4(vec4 v)
{
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.w = v.w;
} public vec4(vec3 xyz, float w)
{
this.x = xyz.x;
this.y = xyz.y;
this.z = xyz.z;
this.w = w;
} public static vec4 operator +(vec4 lhs, vec4 rhs)
{
return new vec4(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z, lhs.w + rhs.w);
} public static vec4 operator +(vec4 lhs, float rhs)
{
return new vec4(lhs.x + rhs, lhs.y + rhs, lhs.z + rhs, lhs.w + rhs);
} public static vec4 operator -(vec4 lhs, float rhs)
{
return new vec4(lhs.x - rhs, lhs.y - rhs, lhs.z - rhs, lhs.w - rhs);
} public static vec4 operator -(vec4 lhs, vec4 rhs)
{
return new vec4(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z, lhs.w - rhs.w);
} public static vec4 operator *(vec4 self, float s)
{
return new vec4(self.x * s, self.y * s, self.z * s, self.w * s);
} public static vec4 operator *(float lhs, vec4 rhs)
{
return new vec4(rhs.x * lhs, rhs.y * lhs, rhs.z * lhs, rhs.w * lhs);
} public static vec4 operator *(vec4 lhs, vec4 rhs)
{
return new vec4(rhs.x * lhs.x, rhs.y * lhs.y, rhs.z * lhs.z, rhs.w * lhs.w);
} public static vec4 operator /(vec4 lhs, float rhs)
{
return new vec4(lhs.x / rhs, lhs.y / rhs, lhs.z / rhs, lhs.w / rhs);
} public float[] to_array()
{
return new[] { x, y, z, w };
} /// <summary>
/// 归一化向量
/// </summary>
/// <param name="vector"></param>
/// <returns></returns>
public void Normalize()
{
var frt = (float)Math.Sqrt(this.x * this.x + this.y * this.y + this.z * this.z); this.x = x / frt;
this.y = y / frt;
this.z = z / frt;
this.w = w / frt;
} public override string ToString()
{
return string.Format("{0:0.00},{1:0.00},{2:0.00},{3:0.00}", x, y, z, w);
}
}
vec4
四维矩阵
然后,我们定义一个四维矩阵mat4。它用4个vec4表示,每个vec4代表一个列向量。(这是glm中的定义)
/// <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 = ; 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[], cols[], cols[], cols[] };
} 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(,,,),
new vec4(,,,),
new vec4(,,,),
new vec4(,,,)
}
};
} #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[][], cols[][], cols[][]),
new vec3(cols[][], cols[][], cols[][]),
new vec3(cols[][], cols[][], cols[][])});
} #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[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[],
lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[],
lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[],
lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[] + lhs[, ] * rhs[]
);
} /// <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[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][]
),
new vec4(
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][]
),
new vec4(
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][]
),
new vec4(
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][],
lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][] + lhs[][] * rhs[][]
)
); return result;
} public static mat4 operator *(mat4 lhs, float s)
{
return new mat4(new[]
{
lhs[]*s,
lhs[]*s,
lhs[]*s,
lhs[]*s
});
} #endregion /// <summary>
/// The columms of the matrix.
/// </summary>
private vec4[] cols;
}
mat4
矩阵与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[, ] = (2f) / (right - left);
result[, ] = (2f) / (top - bottom);
result[, ] = -(2f) / (zFar - zNear);
result[, ] = -(right + left) / (right - left);
result[, ] = -(top + bottom) / (top - bottom);
result[, ] = -(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[, ] / matrix[, ];
float halfRightMinusLeft = 1.0f / matrix[][];
left = -(halfRightMinusLeft + negHalfLeftRight);
right = halfRightMinusLeft - negHalfLeftRight;
} {
float negHalfBottomTop = matrix[, ] / matrix[, ];
float halfTopMinusBottom = 1.0f / matrix[, ];
bottom = -(halfTopMinusBottom + negHalfBottomTop);
top = halfTopMinusBottom - negHalfBottomTop;
} {
float halfNearFar = matrix[, ] / matrix[, ];
float negHalfFarMinusNear = 1.0f / matrix[, ];
zNear = negHalfFarMinusNear + halfNearFar;
zFar = halfNearFar - negHalfFarMinusNear;
} if (matrix[, ] == 0.0f || matrix[, ] == 0.0f || matrix[, ] == 0.0f)
{
return false;
} if (matrix[, ] != 0.0f || matrix[, ] != 0.0f
|| matrix[, ] != 0.0f || matrix[, ] != 0.0f
|| matrix[, ] != 0.0f || matrix[, ] != 0.0f
|| matrix[, ] != 0.0f || matrix[, ] != 0.0f || matrix[, ] != 0.0f)
{
return false;
} if (matrix[, ] != 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[, ] = 2.0f * n / (r - l);// = 2.0f * zNear / (2.0f * zNear * tangent * aspect)
result[, ] = 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[, ] = -(f + n) / (f - n);
result[, ] = -1.0f;
result[, ] = -(2.0f * f * n) / (f - n);
result[, ] = 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[, ];
fovy = * (float)(Math.Atan(tanHalfFovy));
if (fovy < ) { fovy = -fovy; }
//aspectRatio = 1.0f / matrix[0, 0] / tanHalfFovy;
aspectRatio = matrix[, ] / matrix[, ];
if (matrix[, ] == 1.0f)
{
zFar = 0.0f;
zNear = 0.0f;
}
else if (matrix[, ] == -1.0f)
{
zNear = 0.0f;
zFar = float.PositiveInfinity;
}
else
{
zNear = matrix[, ] / (matrix[, ] - );
zFar = matrix[, ] / (matrix[, ] + );
} if (matrix[, ] == 0.0f || matrix[, ] == 0.0f || matrix[, ] == 0.0f)
{
return false;
} if (matrix[, ] != 0.0f || matrix[, ] != 0.0f
|| matrix[, ] != 0.0f || matrix[, ] != 0.0f
|| matrix[, ] != 0.0f || matrix[, ] != 0.0f
|| matrix[, ] != 0.0f || matrix[, ] != 0.0f || matrix[, ] != 0.0f)
{
return false;
} if (matrix[, ] != -1.0f)
{
return false;
} return true;
}
总结
本篇就写这些,今后再写一些相关的内容。
Opengl中矩阵和perspective/ortho的相互转换的更多相关文章
- OpenGL中平移、旋转、缩放矩阵堆栈操作
在OpenGL中,图元的几何变换均为线性变换,通过矩阵变换实现.OpenGL中的坐标用齐次坐标表示,即(x,y,z)表示成(x',y',z',h),其中x=x'/h; y=y'/h; z=z'/h. ...
- OpenGL中glRotatef()函数究竟对矩阵做了什么
OpenGL中glRotatef()函数究竟对矩阵做了什么 我们知道OpenGL中维持着两套矩阵,一个是模型视图矩阵(model view matrix),另一个是投影矩阵(projection ma ...
- OpenGL中glFrustum()和gluPerspective()的相互转换
OpenGL中在窗口的大小发生变化的时候会触发resize()函数,这里会传入一个新的宽和高,在resize()函数中我们会设置投影矩阵,在可以使用OpenGL基础函数glFrustum()函数和gl ...
- (转)思考:矩阵及变换,以及矩阵在DirectX和OpenGL中的运用问题:左乘/右乘,行优先/列优先,...
转自:http://www.cnblogs.com/soroman/archive/2008/03/21/1115571.html 思考:矩阵及变换,以及矩阵在DirectX和OpenGL中的运用1. ...
- OpenGL中的矩阵相乘
OpenGL中的矩阵相乘 1, 在OpenGL中所有的视图变换,模型变换 都是4×4矩阵,每个后续的glMultiMatrix*(N),或者变换函数,glTranslate* (),glRotate* ...
- 关于opengl中的矩阵平移,矩阵旋转,推导过程理解 OpenGL计算机图形学的一些必要矩阵运算知识
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/12166896.html 为什么引入齐次坐标的变换矩阵可以表示平移呢? - Yu Mao的回答 ...
- CSharpGL(6)在OpenGL中绘制UI元素
CSharpGL(6)在OpenGL中绘制UI元素 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharpGL源码中包含10多个独立的Demo,更适合入 ...
- 【opengl】OpenGL中三维物体显示在二维屏幕上显示的变换过程
转自:http://blog.sina.com.cn/s/blog_957b9fdb0100zesv.html 为了说明在三维物体到二维图象之间,需要经过什么样的变换,我们引入了相机(Camera)模 ...
- OpenGL中移动单位中的‘单位’指什么
opengl 比如 用到glm::translate(x,y,z) 表示 移动x,y,z个单位, 那么这个这个单位是指什么呢?这里的单位不是指像素,是根据投影矩阵的变化而变化的,默认情况下投影矩阵Pr ...
随机推荐
- jQuery 追加元素的方法如append、prepend、before,after(转)
1.jQuery append() 方法 jQuery append() 方法在被选元素的结尾插入内容. 实例 复制代码代码如下: $("p").append("Some ...
- iOS之 状态栏字体颜色的设置
前一段时间接手一个项目后,熟悉的过程中发现了不少问题,其中有一个就是关于状态栏的问题. 我们都知道:状态栏字体颜色在不同界面不一样的,原因是系统设置的时候把状态栏的字体颜色的界面控制器设置的yes. ...
- AutoCAD .net 开发 SelectionFilter Foreach Linq 性能比较
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- NOIP2016普及总结
---恢复内容开始--- 当时我说如果不出意外有385,结果就这么跪在了第二题,惨啊 本来以为发挥算正常,结果这发挥太不正常了 [T1] 水题啊[趴 注意下细节就好考你会不会写代码. [T2] 这题大 ...
- select2插件不兼容ie7,ie7下样子显示错位问题
1.源文件(未修改) select2.min.css.select2.min.js 2.ie7下显示样式: 3.ie8下显示样式: 4.经查看发现ie7下对一些属性的解析和ie8不同,需对ie7另作h ...
- ZooKeeper个人笔记客户端watcher和AsycCallback回调
每一个Watcher具有如下属性: 1.KeeperState 2.EventType 3.path 4.process(WatchedEvent evnet)回掉方法 Watcher干嘛的?用户监听 ...
- HDU 4801 Pocket Cube
题目链接 去年现场,虎哥1Y的,现在刷刷题,找找状态... 一共6种转法,把3个面放到顶部,左旋和右旋,感觉写的还不错....都写成常数了. #include <stdio.h> #inc ...
- MSSQL数据库表加锁
所指定的表级锁定提示有如下几种: 1. HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁. 2. NOLOCK:不添加共享锁和排它锁,当这个选项生效后,可 ...
- java实现面向对象和javaScript基于对象的区别&java垃圾回收机制和其他编程语言的比较
java javaScript javaGC和C语言内存分配和内存释放
- redis 的理解
1.Redis使用 C语言开发的.Redis 约定此版本号,为偶数的版本是稳定版(如:2.4版 2.6版),奇数版是非稳定版(如:2.5版 2.7版) 2.Redis 数据库中的所有的数据都存储在内存 ...