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 ...
随机推荐
- axure的一些注意事项
1. 不要轻易用中继器的 载入时 事件, 感觉存在bug 2. 元件在显示和隐藏的动画过程中,不要去取他的x,y值,有几率会取成0,也不要去获取它的尺寸,只有在动画完成后才能获得 3. 装着一个中继器 ...
- C# 发送邮件中包含图片
List<string> To = new List<string>(); To.Add("jake_ge@askey.com.tw"); List< ...
- IDE-Sublime【3】-配置Node.js开发环境
一.下载Nodejs插件,下载地址为https://github.com/tanepiper/SublimeText-Nodejs,解压到当前文件夹,改名为Nodejs 二.打开Sublime Tex ...
- 洛谷 P1201 [USACO1.1]贪婪的送礼者Greedy Gift Givers Label:ExWater
题目描述 对于一群(NP个)要互送礼物的朋友,GY要确定每个人送出的钱比收到的多多少.在这一个问题中,每个人都准备了一些钱来送礼物,而这些钱将会被平均分给那些将收到他的礼物的人.然而,在任何一群朋友中 ...
- [BZOJ1131][POI2008] Sta 树的深度
Description 给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大 Input 给出一个数字N,代表有N个点.N<=1000000 下面N-1条边. Output ...
- 文档:网络通讯包结构(crc校验,加解密)
一直想把这个流程整理一下. 包结构: 包 对(datacrc+protoID+dataSize)组成的byte[] 进行crc计算而得到 对(数据内容)进行crc计算而得到 协议号 数据内容的字节长度 ...
- [Android] Shape背景制作半圆或半边框
实现原理使用layer-list对shape进行叠加显示. 直接上代码: <layer-list xmlns:android="http://schemas.android.com/a ...
- PNG-8和PNG-24的抉择
今天我做了一个图,因为需要透明,所以我存为了PNG8格式,结果发现图片变了,图片变得四周都不光滑了,四周都变得有锯齿了,而且阴影也不见了,后来存为PNG24,这些问题就消失了.我去百度搜索了关于PNG ...
- 安装zabbix-3.0.3+nginx-1.10.1+php-5.6.22
好久没有接触监控类的软件了,今天抽空搭建了下最新的版本 首先系统环境 zabbix-server-1 192.168.11.11 centos6.7 mysql-server 192.168 ...
- 游标cursor
if exists(select * from sys.objects where name='info_one') drop table info_one go create table info_ ...