OpenGL系列教程之五:OpenGL矩阵类

相关主题:OpenGL变换,OpenGL投影矩阵,四元数

下载:matrix.zipmatrix_rowmajor.zip




概述


OpenGL为渲染管线准备了4种不同类型的矩阵(GL_MODELVIEW,GL_PROJECTION, GL_TEXTURE and GL_COLOR)并且为这些矩阵提供了变换的操作:glLoadIdentity(),glTranslatef(),glRotatef(),glScalef(),glMultMatrixf(),glFrustum()和glOrtho().

这些内置的矩阵和操作对于开发简单的OpenGL应用程序非常有用并且非常有利于理解矩阵变换。但是当你的应用程序变的复杂的时候,最好是自己为所有需要移动的对象实现你自己的矩阵和操作。除此之外,你也不可以在可编程的管线(GLSL),像OpenGL v3.0+, OpenGL ES v2.0+ 和 WebGL v1.0+中使用这些内置的矩阵和操作。你必须实现你自己的矩阵并且将矩阵中的数据传递到着色器中。

这篇文章提供了一种使用C++编写的独立,通用的的4*4矩阵类Matrix4,并且描述了如果将这个类集成到OpenGL应用程序中。这个类只依赖于定义在Vectors.h中的Vector3和Vector4。这些向量类也包含在 matrix.zip中。




构造&初始化


Matrix4类包含一个16个浮点型元素的数组来存储4*4的矩阵,它有3个构造函数来实例化这个Matrix4类的对象。


以行为主的Matrix4



OpenGL中使用的以列为主的矩阵


注意这个Matrix4类使用以行为主的标记次序而不是像OpenGL那样使用以列为主的标记次序。然儿,以行为主的次序和以列为主的次序只是两种不同的将多维数组中的数据存储的一维数组中的方式,这对矩阵的算法和矩阵的操作结果是没有影响的。

缺省的构造函数(没有参数)将会创建一个单位矩阵。其他两个构造函数接受16个参数或者包含16个参数的数组。你也可以使用复制构造或赋值操作符(=)来初始化一个Matrix4类的实例。

顺便说一下,复制构造和赋值操作符(=)会由C++编译器自动生成。

下面是一个使用不同方式构造Matrix4对象的例子。首先,需要在使用Matrix4类的文件中包含Matrices.h头文件。

[cpp]  view plain  copy
  1. #include "Matrices.h"   // 为 Matrix2, Matrix3, Matrix4准备的  
  2. ...  
  3.   
  4. // 使用缺省的构造函数构造一个单位矩阵  
  5. Matrix4 m1;  
  6.   
  7. // 使用16个元素构造一个矩阵  
  8. Matrix4 m2(1, 1, 1, 1,   // 第一行  
  9.            1, 1, 1, 1,   // 第二行  
  10.            1, 1, 1, 1,   // 第三行  
  11.            1, 1, 1, 1);  // 第四行  
  12.   
  13. // 使用一个数组够造一个矩阵  
  14. float a[16] = {2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2};  
  15. Matrix4 m3(a);  
  16.   
  17. //使用复制构造和赋值操作符构造一个矩阵  
  18. Matrix4 m4(m3);  
  19. Matrix4 m5 = m3;  




Matrix4存取操作(Setters/Getters)



Setters

Matrix4类提供set()函数来设置所有的16个元素。

[cpp]  view plain  copy
  1. Matrix4 m1;  
  2.   
  3. // 使用16个元素来设置矩阵  
  4. m1.set(1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1);  
  5.   
  6. // 使用数组来设置矩阵  
  7. float a1[] = {2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2};  
  8. m1.set(a1);  


你也可以使用setRow()和setColumn()函数一次来设置一行或一列的值,setRow()和setColumn()函数的第一个参数是一个基于0的索引,第二个参数是指向数组的指针。

[cpp]  view plain  copy
  1. Matrix4 m2;  
  2. float a2[4] = {2,2,2,2};  
  3.   
  4. // 使用索引和数组设置一行的值  
  5. m2.setRow(0, a2);      // 1st row  
  6.   
  7. // 使用索引和数组设置一列的值  
  8. m2.setColumn(2, a2);   // 3rd column  



单位矩阵

Matrix4类有一个特殊的setter,identify()函数用来生成一个单位矩阵

[cpp]  view plain  copy
  1. // 设置一个单位矩阵  
  2. Matrix4 m3;  
  3. m3.identity();  



Getters

Matrix4::get()方法返回一个指向拥有16个元素的数组。getTranspose()返回转置后的矩阵元素。它专门用来将矩阵中的数据传递到OpenGL中,更多详细的细节参考例子。

[cpp]  view plain  copy
  1. // 得到矩阵中的元素并赋值个一个数组  
  2. Matrix4 m4;  
  3. const float* a = m4.get();  
  4.   
  5. //将矩阵传递给OpenGL   
  6. glLoadMatrixf(m4.getTranspose());  



访问单个元素

矩阵中的单个元素可以通过[]操作符来访问:

[cpp]  view plain  copy
  1. Matrix4 m5;  
  2. float f = m5[0];    // 得到第一个元素  
  3.   
  4. m5[1] = 2.0f;       // 设置第二个元素  



打印Matrix4

Matrix4也提供了一个便利的打印输出函数std::cout<<来方便调试:

[cpp]  view plain  copy
  1. Matrix4 m6;  
  2. std::cout << m6 << std::endl;  




矩阵算法

Matrix4类提供了两个矩阵之间的基本算法。



加法和减法

你可以将两个矩阵相加和相减

[cpp]  view plain  copy
  1. Matrix4 m1, m2, m3;  
  2.   
  3. //相加   
  4. m3 = m1 + m2;  
  5. m3 += m1;       //等价于: m3 = m3 + m1  
  6.   
  7. // subtract  
  8. m3 = m1 - m2;  
  9. m3 -= m1;       // 等价于: m3 = m3 - m1  



乘法

你可以将两个矩阵相乘,也有与3维和4维向量相乘以便使用矩阵将向量进行变换。注意矩阵相乘不满足交换律。

[cpp]  view plain  copy
  1. Matrix4 m1, m2, m3;  
  2.   
  3. // 矩阵相乘  
  4. m3 = m1 * m2;  
  5. m3 *= m1;       // 等价于: m3 = m3 * m1  
  6.   
  7. // 缩放操作  
  8. m3 = 2 * m1;    // 将所有元素缩放  
  9.   
  10. // 与向量相乘  
  11. Vector3 v1, v2;  
  12. v2 = m1 * v1;  
  13. v2 = v1 * m1;   // 前乘  



比较

Matrix4类提供了比较操作符来比较两个矩阵中的所有元素:

[cpp]  view plain  copy
  1. Matrix4 m1, m2;  
  2.   
  3. //精确比较   
  4. if(m1 == m2)  
  5.     std::cout << "equal" << std::endl;  
  6. if(m1 != m2)  
  7. std::cout << "not equal" << std::endl;  




Matrix4变换函数


OpenGL有几个变换函数:glTranslatef(),glRotatef()和glScalef()。Matrix4也提供了几个相同的函数来进行矩阵变换:translate(),rotate()andscale()。除此之外,Matrix4还提供了invert()函数计算矩阵的转置矩阵。



Matrix4::translate(x,y,z)

平移矩阵

translate()函数产生经过(x,y,z)变换后的矩阵。首先,它创建一个变换矩阵MT,然后乘以当前矩阵来产生最终的矩阵:

注意这个函数等价于OpenGL中的glTranslatef(),但是OpenGL使用后乘而不是前乘:,如果你执行多个变换,结果将会不一样因为矩阵相乘不满足交换律。

[cpp]  view plain  copy
  1. // M1 = Mt * M1  
  2. Matrix4 m1;  
  3. m1.translate(1, 2, 3);   // 移动到(x, y, z)  



Matrix4::rotate(angle,x,y,z)

旋转矩阵

rotate()可以被用来通过指定一个轴(x,y,z)和绕轴旋转的角度来旋转三维模型。这个函数生成一个旋转矩阵MR,然后乘以当前矩阵生成一个最终经过旋转变换后的矩阵:

它等价于glRotatef(),但是OpenGL使用后乘操作来生成最终的变换后的矩阵:

rotate()可以用来绕任意的轴旋转。Matrix4类提供了额外的3个函数绕指定轴旋转rotateX(),rotateY(),rotateZ()。


[cpp]  view plain  copy
  1. // M1 = Mr * M1  
  2. Matrix4 m1;  
  3. m1.rotate(45, 1,0,0);   // 绕X轴旋转45度  
  4. m1.rotateX(45);         // 和rotate(45, 1,0,0)一样  



Matrix4::scale(x,y,z)

缩放矩阵

scale()在每一个轴上产生一个不均等的缩放效果的矩阵:

注意:OpenGL中glScalef()执行后乘操作:

Matrix4类也提供了均等的缩放函数。


[cpp]  view plain  copy
  1. // M1 = Ms * M1  
  2. Matrix4 m1;  
  3. m1.scale(1,2,3);    // 非均等的缩放  
  4. m1.scale(4);        // 均等的缩放,在所有轴上是一样的  




Matrix::invert()

invert()函数计算当前矩阵的反转矩阵,这个反转矩阵主要用来将法向量从物体坐标系变换到人眼坐标系中。法向量和顶点的变换不一样。法向量变换是使用GL_MODELVIEW的反转乘以法向量:详细的细节参考这儿。

如果矩阵只是欧式变换(旋转和平移),或者放射变换(旋转,平移,缩放,裁剪),反转矩阵的计算会很简单。Matrix4::invert()将会为你决定何时的反转方式,但是如果你明确地调用了一个反转函数:invertEuclidean(),invertAffine(),invertProjective()o或invertGeneral()。请阅读 Matrices.cpp中的详细细节。


[cpp]  view plain  copy
  1. Matrix4 m1;  
  2. m1.invert();    // 反转矩阵  





例子:模型视图矩阵



下载源文件和二进制文件:matrix.zip

这个例子显示了怎么将Matrix4类集成到OpenGL程序中。GL_MODELVIEW联合和视图矩阵和模型矩阵,但是我们将它们分开并传递两个矩阵给OpenGL的模型视图矩阵。

[cpp]  view plain  copy
  1. Matrix4 matModel, matView, matModelView;  
  2. glMatrixMode(GL_MODELVIEW);  
  3. ...  
  4.   
  5. // 视图变换  
  6. matView.identity();                 // 变换次序:  
  7. matView.rotate(-camAngleY, 0,1,0);  // 1: 绕Y轴旋转  
  8. matView.rotate(-camAngleX, 1,0,0);  // 2: 绕X轴旋转  
  9. matView.translate(0, 0, -camDist);  // 3: 沿Z轴平移  
  10.   
  11. //模型变换   
  12. // 沿Y轴旋转45度,然后向上平移两个单位  
  13. matModel.identity();  
  14. matModel.rotate(45, 0,1,0);         // 第一个变换  
  15. matModel.translate(0, 2, 0);        // 第二次变换  
  16.   
  17. //构造模型视图矩阵: Mmv = Mv * Mm  
  18. matModelView = matView * matModel;  
  19.   
  20. // 将模型视图矩阵传递给OpenGL  
  21. // 注意:需要将矩阵转置  
  22. glLoadMatrixf(matModelView.getTranspose());  
  23.   
  24. // 绘制  
  25. ...  

等价的OpenGL实现如下:


[cpp]  view plain  copy
  1. //注意:变换的次序是相反的  
  2.  //因为OpenGL使用的是后乘  
  3. glMatrixMode(GL_MODELVIEW);  
  4. glLoadIdentity();  
  5.   
  6. // 视图变换  
  7. glTranslatef(0, 0, -camDist);       // 3: 沿Z轴平移  
  8. glRotatef(-camAngleX, 1,0,0);       // 2: 绕X轴旋转  
  9. glRotatef(-camAngleY, 0,1,0);       // 1: 绕Y轴旋转  
  10.   
  11. // 模型变换  
  12. // 先绕Y轴旋转45度再向上平移2个单位  
  13. glTranslatef(0, 2, 0);              // 2:平移  
  14. glRotatef(45, 0,1,0);               // 1: 旋转  
  15.   
  16. // 绘制  
  17. ...  

模型视图矩阵的反转用来将法向量从物体坐标系变换到人眼坐标系中。在可编程的渲染管线中,你需要将它传递给GLSL着色器。


[cpp]  view plain  copy
  1. //为法向量构造矩阵: (M^-1)^T  
  2. Matrix4 matNormal = matModelView;   // 得到模型视图矩阵  
  3. matNormal.invert();                 // 得到反转矩阵  
  4. matNormal.transpose();              // 将矩阵转置  





例子:投影矩阵


这个例子显示了如何创建投影矩阵,等价于glFrustum()和glOrtho()。更多细节查看source codes

[cpp]  view plain  copy
  1. // 设置投影矩阵并将其传递给OpenGL  
  2. Matrix4 matProject = setFrustum(-1, 1, -1, 1, 1, 100);  
  3.   
  4. glMatrixMode(GL_PROJECTION);  
  5. glLoadMatrixf(matProject.getTranspose());  
  6. ...  
  7.   
  8. ///  
  9. // glFrustum()  
  10. ///  
  11. Matrix4 setFrustum(float l, float r, float b, float t, float n, float f)  
  12. {  
  13.     Matrix4 mat;  
  14.     mat[0]  = 2 * n / (r - l);  
  15.     mat[2]  = (r + l) / (r - l);  
  16.     mat[5]  = 2 * n / (t - b);  
  17.     mat[6]  = (t + b) / (t - b);  
  18.     mat[10] = -(f + n) / (f - n);  
  19.     mat[11] = -(2 * f * n) / (f - n);  
  20.     mat[14] = -1;  
  21.     mat[15] = 0;  
  22.     return mat;  
  23. }  
  24.   
  25. ///  
  26. // gluPerspective()  
  27. ///  
  28. Matrix4 setFrustum(float fovY, float aspect, float front, float back)  
  29. {  
  30.     float tangent = tanf(fovY/2 * DEG2RAD); // 视角一半的切  
  31.     float height = front * tangent;         // 近平面高度的一半  
  32.     float width = height * aspect;          // 近平面宽度的一半  
  33.   
  34.     // 参数: left, right, bottom, top, near, far  
  35.     return setFrustum(-width, width, -height, height, front, back);  
  36. }  
  37.   
  38. ///  
  39. // glOrtho()  
  40. ///  
  41. Matrix4 setOrthoFrustum(float l, float r, float b, float t, float n, float f)  
  42. {  
  43.     Matrix4 mat;  
  44.     mat[0]  = 2 / (r - l);  
  45.     mat[3]  = -(r + l) / (r - l);  
  46.     mat[5]  = 2 / (t - b);  
  47.     mat[7]  = -(t + b) / (t - b);  
  48.     mat[10] = -2 / (f - n);  
  49.     mat[11] = -(f + n) / (f - n);  
  50.     return mat;  
  51. }  
  52. ...  

0
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
NEHE的OPENGL教程 第42课 多视窗口… NEHE的OPENGL教程 第42课 多视窗口… NeHe的OPENGL教程:第41课 体… NeHe的OPENGL教程:第40课 绳… NeHe的OPENGL教程:第39课 物… NeHe的OPENGL教程:第39课 物… NeHe的OPENGL教程:第38课 从… NeHe的OPENGL教程:第37课 卡… 愚人节十大IT假新闻:Opera浏览器… NeHe的OPENGL教程:第36课 放… NeHe的OPENGL教程:第35课 AVI… NeHe的OPENGL教程:第35课 AVI… NeHe的OPENGL教程:第34课 从… NeHe的OPENGL教程:第33课 加… NeHe的OPENGL教程:第32课 Alp… NeHe的OPENGL教程:第32课 Alp… NeHe的OPENGL教程:第32课 Alp… NeHe的OPENGL教程:第31课 模… NEHE的OPENGL教程:第30课 碰… NEHE的OPENGL教程:第30课 碰… NeHe的OPENGL教程:第29课 Bli… NeHe的OPENGL教程:第28课 贝… NeHe的OPENGL教程:第27课 影… NeHe的OPENGL教程:第26课剪裁… NeHe的OPENGL教程:第25课 变… NeHe的OPENGL教程:第24课 TAG… NeHe的OPENGL教程:第23课 球… NeHe的OPENGL教程:第22课 凸… NeHe的OPENGL教程:第22课 凸… NeHe的OPENGL教程:第21课 反… NeHe的OPENGL教程:第21课 反… NeHe的OPENGL教程:第20课 蒙… NeHe的OPENGL教程:第19课 粒… NeHe的OPENGL教程:第18课 二… NeHe的OPENGL教程:第17课 2D… NeHe的OPENGL教程:第16课 雾 NeHe的OPENGL教程:第15课 图… NeHe的OPENGL教程:第14课 图… NeHe的OPENGL教程:第13课 位… NeHe的OPENGL教程:第12课 显… NeHe的OPENGL教程:第11课 飘… NeHe的OPENGL教程:第十课 漫… NeHe的OPENGL教程:第九课 漂… NeHe的OPENGL教程:第八课 Alp… NeHe的OPENGL教程:第七课 纹… NeHe的OPENGL教程:第七课 纹… NeHe的OPENGL教程:第六课 纹… NeHe的OPENGL教程:第五课 向3… NeHe的OPENGL教程:第四课 旋… NeHe的OPENGL教程:第三课 着… NeHe的OPENGL教程:第二课 多… NeHe的OPENGL教程:第一课 新… NeHe的OPENGL教程:第一课 新… DirectX与OpenGL方面的经典电子书… VC++ 6.0下OpengGL配置以及glut配… 怎样开始学习OpenGL
EGL、GLX、Xegl、XGL和XGLX都与OpenGL和X Window System(X11)之间的图形渲染和窗口管理有关。这些是不同的API和扩展,用于在图形应用程序和硬件之间进行通信和协调。 1. EGL(Embedded-System Graphics Library)是一个用于嵌入式系统的图形库,它提供了一个标准的接口,使应用程序能够与底层图形驱动程序进行交互。EGL可以用于管理窗口系统和设备上下文,以及在OpenGL ES等图形API之间进行切换。 2. GLX(OpenGL Extension to the X Window System)是一个在X11窗口系统上使用OpenGL的扩展。它允许应用程序使用OpenGL渲染图形,并将结果显示在X窗口。GLX提供了与X Server的交互,以及创建和管理OpenGL上下文的功能。 3. Xegl是一种将EGL与X Window System集成的方法。它允许应用程序使用EGL进行图形渲染,并在X窗口显示结果。这种集成可以提供更好的性能和更高的灵活性。 4. XGL是一个用于在X Window System上使用OpenGL的实现。它是一种通过将OpenGL命令转换为X协议来实现的技术,在服务器端执行OpenGL渲染。 5. XGLX(X11 Graphics Library Extension)是用于在X Window System上使用OpenGL的另一种扩展。它提供了X Server和OpenGL之间传递图形的功能,用于加速OpenGL渲染。 这些API和扩展提供了在X Window System上使用OpenGL进行图形渲染不同方法。开发人员可以根据特定的需求选择合适的API或扩展来实现他们的图形应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值