OpenGL矩阵类(C++) 【转】
http://www.cnblogs.com/hefee/p/3816727.html
OpenGL矩阵类(C++)
概述
OpenGL固定功能管线提供4个不同类型的矩阵(GL_MODELVIEW、GL_PROJECTION、GL_TEXTURE与GL_COLOR),并且为这些矩阵提供变换函数:glLoadIdentity()、glTranslatef()、glRotatef()、glScalef()、glMultiMatrixf()、glFrustum()与glOrtho()。
这些内置矩阵与函数对于开发简单的OpenGL程序与理解矩阵变换很有帮助。不过,一旦你的应用程序变得复杂起来,更好的选择是为每一个可移动模型对象管理自己的矩阵实现。此外,在OpenGL可编程管线(GLSL)中,你不能够使用这些内置矩阵函数。如OpenGL v3.0+、OpenGL ES v2.0+与WebGL v1.0+。你必须拥有属于自己的矩阵实现,并且向OpenGL着色语言传递该矩阵数据。
该篇文章提供一个独立运行的、通用4×4矩阵类----C++写的Matrix4,并且描述如何将该矩阵类整合到OpenGL程序中。该矩阵类只依赖于相似的矩阵:定义于Vector.h的Vector3与Vector4。这些向量也包含在matrix.zip。
Matrix4创建&初始化

Matrix4使用行优先

OpenGL使用列优先
Matrix4类包含用于存放4×4方阵的16个元素的浮点数据类型数组,同时拥有3个构造函数用以实例化Matrix4类对象。
注意,Matrix4类使用行优先标记法,而不是OpenGL使用的列优先顺序。不过,行优先与列优先顺序只是将多维数组保存在线性(1D)内存中的不同方式,矩阵算法与操作并没有不同。
使用默认构造函数(不带任何参数的),Matrix4对象创建一个单位矩阵。另外3个构造函数使用16个参数或一个具有16个元素的数组。你也可以使用拷贝构造函数与赋值操作符(=)初始化Matrix4对象。
顺便说一下,Matrix4对象的拷贝构造函数与赋值构造函数将由C++编译器自动为你产生。
下面为以多种方式构造Matrix4对象的示例代码。首先,在使用Matrix4.h类的代码中包含Matrices.h文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#include "Matrices.h" // 为了使用 Matrix2, Matrix3, Matrix4 .. // 使用默认构造函数创建一个单位矩阵 Matrix4 m1; // 使用16个元素创建一个矩阵 Matrix4 m2(1, 1, 1, 1, // 第一行 1, 1, 1, 1, // 第二行 1, 1, 1, 1, // 第三行 1, 1, 1, 1); // 第四行 // 使用数组创建一个矩阵 float a[16] = {2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2}; Matrix4 m3(a); // 使用构造函数创建一个矩阵 Matrix4 m4(m3); Matrix4 m5 = m3; ... |
Matrix4存取器(赋值与取值)
赋值
Matrix4类提供set()方法赋值所有16个元素。
1
2
3
4
5
6
7
|
Matrix4 m1; // 使用16个浮点数给矩阵赋值 m1.set(1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1); // 使用数组给矩阵赋值 float a1[] = {2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2}; m1.set(a1); |
你也可以每次使用setRow()或setColumn()设置行或列元素。setRow()与setColumn()的第一个参数以0为基准的(0,1,2或3)。第二个参数为数组指针。
1
2
3
4
5
6
7
8
|
Matrix4 m2; float a2[4] = {2,2,2,2}; // 使用行索引与数组设置一行 m2.setRow(0, a2); // 第一行 // 使用列索引与数组设置一列 m2.setColumn(2, a2); // 第三列 |
单位矩阵
Matrix4类拥有一个特殊的赋值函数identity()以创建一个单位矩阵。
1
2
3
|
// 设置单位矩阵 Matrix4 m3; m3.identity(); |
获取
Matrix4::get()方法返回16个元素数组的指针。getTranspose()返回转置后的矩阵元素。它可用于向OpenGL传递矩阵数据。更详细信息请参考实例。
1
2
3
4
5
6
|
// 以数组指针方式获取矩阵元素 Matrix4 m4; const float * a = m4.get(); // 向OpenGL传递矩阵 glLoadMatrixf(m4.getTranspose()); |
访问单独的元素
矩阵的独立元素也可以通过下标操作符[]访问。
1
2
3
4
|
Matrix4 m5; float f = m5[0]; // 获取第一个元素 m5[1] = 2.0f; // 设置第2个元素 |
打印Matrix4
为了调试,Matrix4也提供一个使用std::ostream操作符<<的便捷打印函数。
1
2
3
|
// 打印矩阵 Matrix4 m6; std::cout << m6 << std::endl; |
矩阵运算
Matrix4提供在2个矩阵间的基本算术运算。
加法&减法
你可以进行两个矩阵相见与相加。
1
2
3
4
5
6
7
8
9
|
Matrix4 m1, m2, m3; // 加法 m3 = m1 + m2; m3 += m1; // m3 = m3 + m2的简洁操作 // 减法 m3 = m1 - m2; m3 -= m1; // m3 = m3 - m1的简洁操作 |
乘法
你可以将2个矩阵乘在一起,也可以进行3D/4D向量的乘法,用于使用矩阵对向量进行变换。注意,矩阵乘法不可交换。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
Matrix4 m1, m2, m3; // 矩阵乘法 m3 = m1 * m2; m3 *= m1; // m3 = m3 * m1的简洁写法 // 标量乘法 m3 = 2 * m1; // 缩放所有元素 // 向量乘法 Vector3 v1, v2; v2 = m1 * v1; v2 = v1 * m1; // 前向乘 |
比较
Matrix4类提供比较2个矩阵所有元素的操作。
1
2
3
4
5
6
7
|
Matrix4 m1, m2; // 绝对比较 if (m1 == m2) std::cout << "equal" << std::endl; if (m1 != m2) std::cout << "not equal" << std::endl; |
矩阵变换函数
OpenGL为矩阵变换提供许多函数:glTranslatef()、glRotatef()与glScalef()。Matrix4类提供变换矩阵的等价函数:translate()、rotate()与scale()。此外,Matrix4提供invert()用于计算逆矩阵。
Matrix4::translate(x,y,z)
translate()将当前矩阵平移(x,y,z)。首先,它生成一个平移矩阵M,接着将它与当前矩阵对象相乘产生最终变换矩阵:M=M•M
注意,该函数等价于OpenGL的glTranslatef(),不过OpenGL使用右乘而不是左乘(平移矩阵又乘回当前矩阵。)M=M•MT。如果你进行多次变换,你会发现结果会有很明显的不同,因为矩阵乘法是不可互换的。
对于应用多个变换,请参考“ModelView矩阵的更多实例”。
1
2
3
|
// M1 = Mt * M1 Matrix4 m1; m1.translate(1, 2, 3); // move to (x, y, z) |
Matrix4::rotate(angle, x, y, z)
rotate()用于将3D模型绕轴(x、y、z)旋转任意度数(角度)。该函数生成一旋转矩阵MR,然后将它与当前矩阵对象相乘,生成最终旋转变换矩阵:M=MR•M。
它等价于glRotatef(),使用右乘生成最终变换矩阵:M=M•MR
rotate()可以在任意轴上旋转。Matrix4类提供额外的3个函数进行基准轴旋转操作:rotateX()、rotateY()与rotateZ()。
1
2
3
4
|
// M1 = Mr * M1 Matrix4 m1; m1.rotate(45, 1,0,0); // 绕X轴旋转45度 m1.rotateX(45); // 与rotate(45, 1, 0, 0)相同 |
Matrix4::scale(x,y,z)
scale()通过将当前矩阵对象与缩放矩阵相乘:M=Ms•M,在轴(x,y,z)上生成一个不均匀的缩放变换矩阵。
再次注意,OpenGL的glScalef()执行右乘:M=M•Ms。
Matrix4类也提供均匀缩放函数。
1
2
3
4
|
// M1 = Ms * M1 Matrix4 m1; m1.scale(1,2,3); // 非均匀缩放 m1.scale(4); // 均匀缩放 (所有轴都一样) |
Matrix::invert()
invert()函数计算当前矩阵的逆矩阵。该你矩阵通常用于将法向量从模型对象空间变换到观察空间。法向量与顶点的变换不同。法向量通过乘以GL_MODELVIEW矩阵的逆矩阵变换到观察空间:n'=nTM-1 = (M-1)Tn。详细解释参考这里。
如果矩阵仅仅为欧氏变换(旋转与平移)或仿射变换(再加上缩放与剪切),逆矩阵的变换就非常简单。Matrix4::invert()将判断合适的求逆方法,不过你可以调用更具体的求逆函数:invertEuclidean()、invertAffine()、invertProjective()或invertGeneral()。请参考Matrices.cpp中的详细描述。
1
2
|
Matrix4 m1; m1.invert(); // 矩阵求逆 |
实例:模型视图矩阵
下载源文件与二进制文件:matrix.zip。
该实例展示如何将Matrix4类应用到OpenGL中。GL_MODELVIEW矩阵是视图矩阵与模型矩阵的组合,不过我们单独保存它们,并且在需要时向OpenGL的GL_MODELVIEW传递二者的乘积。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
Matrix4 matModel, matView, matModelView; glMatrixMode(GL_MODELVIEW); ... // orbital camera (view) matView.identity(); // 变换顺序 matView.rotate(-camAngleY, 0,1,0); // 1: 绕Y轴旋转 matView.rotate(-camAngleX, 1,0,0); // 2: 绕X轴旋转 matView.translate(0, 0, -camDist); // 3: 沿Z轴移动 // 模型变换:绕Y轴旋转45度,然后向上移动2个单位 matModel.identity(); matModel.rotate(45, 0,1,0); // 第一次变换 matModel.translate(0, 2, 0); // 第二次变换 // 生成模型视图矩阵: Mmv = Mv * Mm matModelView = matView * matModel; // 在绘制之前传给OpenGL // 注意: 需要进行转置操作 glLoadMatrixf(matModelView.getTranspose()); // 绘制 ... |
等价OpenGL实现如下。结果与上面的相同
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//注意: 变换顺序相反,因为OpenGL使用右乘 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // 相机轨迹(视图) glTranslatef(0, 0, -camDist); // 3: 沿Z轴移动 glRotatef(-camAngleX, 1,0,0); // 2: 绕X轴旋转 glRotatef(-camAngleY, 0,1,0); // 1: 绕Y轴旋转 // 模型变换: 绕Y轴旋转45度,然后向上移动2个单位 glTranslatef(0, 2, 0); // 第二次变换 glRotatef(45, 0,1,0); // 第一次变换 // 绘制 ... |
模型视图矩阵的逆矩阵用于从模型对象空间到观察空间的法向量变换。在可编程渲染管线中,你需要向GLSL着色器传递它。
1
2
3
4
|
// 为法向量构建逆矩阵: (M^-1)^T Matrix4 matNormal = matModelView; // 获取模型视图矩阵 matNormal.invert(); // 获取法向量变换的逆矩阵 matNormal.transpose(); // 转置矩阵 |
实例:投影矩阵
该实例展示如何产生投影矩阵,等价于glFrustum()与glOrtho()。更详细描述请参考源代码。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
// 设置投影矩阵并传递到OpenGL Matrix4 matProject = setFrustum(-1, 1, -1, 1, 1, 100); glMatrixMode(GL_PROJECTION); glLoadMatrixf(matProject.getTranspose()); ... /////////////////////////////////////////////////////////////////////////////// // glFrustum() /////////////////////////////////////////////////////////////////////////////// Matrix4 setFrustum( float l, float r, float b, float t, float n, float f) { Matrix4 mat; mat[0] = 2 * n / (r - l); mat[2] = (r + l) / (r - l); mat[5] = 2 * n / (t - b); mat[6] = (t + b) / (t - b); mat[10] = -(f + n) / (f - n); mat[11] = -(2 * f * n) / (f - n); mat[14] = -1; mat[15] = 0; return mat; } /////////////////////////////////////////////////////////////////////////////// // gluPerspective() /////////////////////////////////////////////////////////////////////////////// Matrix4 setFrustum( float fovY, float aspect, float front, float back) { float tangent = tanf(fovY/2 * DEG2RAD); // fovY的半角 float height = front * tangent; // 近平面半高 float width = height * aspect; // 近平面半宽 // 参数: left, right, bottom, top, near, far return setFrustum(-width, width, -height, height, front, back); } /////////////////////////////////////////////////////////////////////////////// // glOrtho() /////////////////////////////////////////////////////////////////////////////// Matrix4 setOrthoFrustum( float l, float r, float b, float t, float n, float f) { Matrix4 mat; mat[0] = 2 / (r - l); mat[3] = -(r + l) / (r - l); mat[5] = 2 / (t - b); mat[7] = -(t + b) / (t - b); mat[10] = -2 / (f - n); mat[11] = -(f + n) / (f - n); return mat; } ... |
英文原文:http://www.songho.ca/opengl/gl_matrix.html
OpenGL矩阵类(C++) 【转】的更多相关文章
- OpenGL矩阵类(C++)
概述 创建&初始化 存取器 矩阵运算 变换函数 实例:模型视图矩阵 实例:投影矩阵 概述 OpenGL固定功能管线提供4个不同类型的矩阵(GL_MODELVIEW.GL_PROJECTION. ...
- NPOI操作EXCEL(六)——矩阵类表头EXCEL模板的解析
哈哈~~~很高兴还活着.总算加班加点的把最后一类EXCEL模板的解析做完了... 前面几篇文章介绍了博主最近项目中对于复杂excel表头的解析,写得不好,感谢园友们的支持~~~ 今天再简单讲诉一下另一 ...
- [Java]编写自己的Matrix矩阵类
用java实现一个简单的矩阵类,可以实现简单的矩阵计算功能. class Matrix 1.向量点乘 public static double dot(double[] x,double[] y) 2 ...
- 精解Mat类(一):基本数据类型-固定大小的 矩阵类(Matx) 向量类(Vector)
一.基础数据类型 1.(基础)固定大小矩阵类 matx 说明: ① 基础矩阵是我个人增加的描述,相对于Mat矩阵类(存储图像信息的大矩阵)而言. ② 固定大小矩阵类必须在编译期间就知晓其维 ...
- 矩阵类的python实现
科学计算离不开矩阵的运算.当然,python已经有非常好的现成的库:numpy. 我写这个矩阵类,并不是打算重新造一个轮子,只是作为一个练习,记录在此. 注:这个类的函数还没全部实现,慢慢在完善吧. ...
- C++实现矩阵类和向量类
C++期末作业内容,写完之后觉得过于臃肿,又重新搞了个新的.新的当作业交,旧的拿来给同学参考. [问题描述]请仿照复数类,设计一个矩阵类,设计矩阵类的构成元素 1.编写构造函数完成初始化 2.编写成员 ...
- opengl矩阵向量
如何创建一个物体.着色.加入纹理,给它们一些细节的表现,但因为它们都还是静态的物体,仍是不够有趣.我们可以尝试着在每一帧改变物体的顶点并且重配置缓冲区从而使它们移动,但这太繁琐了,而且会消耗很多的处理 ...
- 实用矩阵类(Matrix)(带测试)
引言: 无意间看到国外一个网站写的Matrix类,实现了加减乘除基本运算以及各自的const版本等等,功能还算比较完善,,于是记录下来,以备后用: #ifndef MATRIX_H #define M ...
- [Android] 使用Matrix矩阵类对图像进行缩放、旋转、对照度、亮度处理
前一篇文章讲述了Android拍照.截图.保存并显示在ImageView控件中,该篇文章继续讲述Android图像处理技术,主要操作包含:通过打开相冊里的图片,使用Matrix对图像进行缩放. ...
随机推荐
- BZOJ2157 旅游 【树剖 或 LCT】
题目 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径. ...
- 为基于busybox根文件系统的ARM嵌入式Linux交叉编译dropbear使能SSH
原创作品,允许转载,转载时请务必以超链接形式标明文章.作者信息和本声明,否则将追究法律责任. 最近使用busybox为基于ARM的板卡定制了一个极简单的根文件系统,由于busybox仅支持telnet ...
- table隔行变色【转】
table tr:nth-child(odd){background:#F4F4F4;} table td:nth-child(even){color:#C00;} table tr:nth-chil ...
- 51nod 1273 旅行计划——思维题
某个国家有N个城市,编号0 至 N-1,他们之间用N - 1条道路连接,道路是双向行驶的,沿着道路你可以到达任何一个城市.你有一个旅行计划,这个计划是从编号K的城市出发,每天到达一个你没有去过的城市, ...
- 汕头市队赛 SRM13 T3
这道题可以贪心 维护一个答案队列 枚举位置 每次将比当前位置大的队尾全部替代掉 记录删了多少了就好了 #include<cstdio> #include<iostream> # ...
- 汕头市队赛 SRM1X T1
木之本樱 背景 “西瓜是可以种在树上的!”——木之本樱 描述 空地上,一排排的西瓜树拔地而起. 魔法世界里,空地是无限大的.所有的树排成了n条直线,每条直线也是向左右两端无限延伸的. 由于自己姓木(之 ...
- C++中的 Round(),floor(),ceil()
2.1 2.6 -2.1 -2.6floor : 不大于自变量的最大整数 2 ...
- Synthesis of memory barriers
A framework is provided for automatic inference of memory fences in concurrent programs. A method is ...
- 基于V4L2的视频驱动开发【转】
转自:http://blog.chinaunix.net/uid-10747583-id-298573.html Tags:V4L2驱动框架.API.操作流程…… 原文地址:http://www.ee ...
- python接口自动化10-token登录【转载】
本篇转自博客:上海-悠悠 原文地址:http://www.cnblogs.com/yoyoketang/tag/python%E6%8E%A5%E5%8F%A3%E8%87%AA%E5%8A%A8%E ...