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 * M1Matrix4 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 * M1Matrix4 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 * M1Matrix4 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 * MmmatModelView = 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)^TMatrix4 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
|
// 设置投影矩阵并传递到OpenGLMatrix4 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对图像进行缩放. ...
随机推荐
- 如何在CentOS7上改变网络接口名
如何在CentOS7上改变网络接口名 传统上,Linux的网络接口被枚举为eth[0123...],但这些名称并不一定符合实际的硬件插槽,PCI位置,USB接口数量等,这引入了一个不可预知的命名问题( ...
- [洛谷P4588][TJOI2018]数学计算
题目大意:有一个数$x$和取模的数$mod$,初始为$1$,有两个操作: $m:x=x\times m$并输出$x\% mod$ $pos:x=x/第pos次操作乘的数$(保证合法),并输出$x\%m ...
- 全球顶尖的内容创作引擎,Unity为创造而生
5月11日晚,Unite Beijing 2018 Keynote主题演讲于国家会议中心圆满落幕.今年的Keynote主题演讲汇聚了12位重量级嘉宾,为参会者呈现出了一场属于Unity 2018的技术 ...
- [bzoj] 1878 HH的项链 || 莫队
原题 给定长为 n 的一个序列,接下来 m 次询问,每次询问区间 [ l , r ] 内有多少个不同的数. 莫队: 离线\(O(n\log(n))\). 将序列分块. 以左端点所在块为第一关键字,右端 ...
- php56升级后php7 mcrypt_encrypt 报错
mcrypt_encrypt(MCRYPT_BLOWFISH, $passphrase, $data, MCRYPT_MODE_CBC, $iv); openssl_encrypt($data, &q ...
- Tomcat学习笔记(二)
Servlet浅析 javax.servlet.Servlet是一个接口,所有的Servlet必须实现接口里面的方法. 该接口在tomcat/bin中的servlet-api.jar包中. Servl ...
- Codeforces Round #324 (Div. 2) B
B. Kolya and Tanya time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- Matlab 几种卷积的实现与比较(conv与filter,conv2与filter2)
Matlab 几种卷积的实现与比较(conv与filter,conv2与filter2) 最近在做控制算法实现的时候,对于其中参杂的各种差分.卷积很头疼,就在网上搜集了些资料,汇总于此,以做备 ...
- ping & traceroute 原理
说明: 忘记从哪里看到的原文了. 不过我应该进行了大刀阔斧的删选. ping 用类型码为0的ICMP发请 求,受到请求的主机则用类型码为8的ICMP回应. ping程序来计算间隔时间,并计算有多少个包 ...
- java基础练习 20
import java.util.Scanner; public class Twentieth { /*某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都 ...