DLGOPENGL-06矩阵

GL_MODELVIEW, GL_TEXTURE oder GL_PROJECTION

模型矩阵,纹理矩阵,透视矩阵

毫无疑问,这些矩阵中最重要的是模型矩阵,因为它描述了“笔”的位置,从而定位对象。纹理矩阵的工作方式与模型矩阵几乎相同,只是它定义了纹理的方向。透视矩阵定义了观众视野的基本特征。glMatrixMode命令允许您更改当前矩阵。可以使用常数GL_MODELVIEW、GL_TEXTURE或GL_PROJECTION确定矩阵。到目前为止,这些常数的名称有望不言自明。从现在起,所有矩阵操作(如glLoadIdentity或glTranslate*)都会导致当前设置的矩阵发生变化。

如前所述,透视矩阵描述了当前的视野。要设置透视矩阵,通常使用glFrustum、gluPerspective、glOrtho或gluOrtho2D等命令。
例如,gluPerspective通过减小对象的大小并增加与观看者的距离,使空间看起来是三维的。这种减小取决于第一个参数中传递的角度。
另一方面,glOrtho对于2D视野来说非常棒,因为这种类型的投影不再包含深度。
有关各个函数的更多详细信息,可以在OpenGLwiki中找到。
然而,我想再谈一件事:其中一些函数需要参数“znear”和“zfar”。这些参数描述了两个相交的曲面,这两个曲面限制了观察者前方的视野。“znear”定义*剪裁*面与查看器的距离。此层前面的所有对象都不可见。“zfar”描述了闹剧飞机与观众之间的距离。它后面的所有对象都被切掉。因此,如果屏幕上只有一半的场景可见,请尝试相应地调整编辑区域!

 

通过调节Near 和Far的值,可以对视场空间进行切割裁剪。

相机的每一个定位都是通过旋转和移动场景来完成的。这需要一点时间来适应,尤其是在开始的时候(“世界在旋转!不是你!”)。
相反,每个操作都直接传递给世界矩阵(更好的模型矩阵)。这意味着当您调用glTranslate*时,该操作已经输入到模型矩阵中,所有其他对象都使用该矩阵绘制。如果您两次调用glTranslate*(2,0,0),您会注意到glTranslate*不会返回两个矩阵,而是只返回一个,然后指向(4,0,1)。所以在开始的时候,你应该非常小心,这需要一段时间,直到你把这个牢牢地记在心里。不要立即放弃:)!

 

glRotatef(90,0,1,0);
朝着Y方向旋转90°。

 

 旋转轴是Y轴,逆时针。


应用此矩阵的对象将绕其Y轴旋转90°(逆时针)。由此,我们得出结论,第一个参数定义了我们要围绕其旋转的度数度量中的角度,以下三个参数描述了要围绕其执行旋转的向量分量X、Y、Z。

旋转实际上很困难,因为对于3D编程初学者来说,想象物体如何围绕其自身的轴旋转并不总是容易的。
但老实说,解决方案很简单。我们简单地称为glTranslate*,然后称为glRotate*,因此对象实际上围绕其自身的轴旋转,在新的、移动的点上。
但是!如果首先旋转对象,然后开始*移,则获得的结果与前一个不同!现在,对象不会围绕自己的轴旋转,而是在以位移为半径的路径上旋转(简单地说:“停止在圆中”)。

 左右2图遵循的区别为,旋转轴一直为模型的左下角,对称轴仍然是模型本身!

 

可以使用glScale*命令调整大小。

glScalef(1,1,1);

在这种情况下,我们将按照指定的方式绘制对象。也就是说,它的原始大小。当然,你已经知道这些参数是什么意思了……它们代表了根据X、Y和Z模式的各个边的比例。如果我们使用2而不是1作为第一个参数,那么我们的对象相对于X轴的空间范围将是它的两倍。如果我们改为指定0.5,那么它只会是大小的一半。
然而,在现实中,glScale*并不会导致尺寸的改变,而是导致坐标系的变形。因此,每次调用glScale*都会影响glTranslate*等命令。从矩阵的角度来看,这种现象也很容易解释。实际上,每次调用glRotate*、glTranslate*或glScale*都会创建自己的矩阵,然后乘以当前矩阵(例如模型视图矩阵)。如果glScale*已经在模型视图矩阵中永久化,则这会影响矩阵相乘时的变换矩阵。

我不认为我需要更详细地说明这样一个事实:调用glScalef(0,0,0)来破坏坐标系不是一个好主意。把坐标系放在一个点上有什么意义?
注意:仅将一个轴缩放为0已经很危险,因为这会损坏当前矩阵(单数),并且gluProject和gluUnProject等命令不再有效。
我希望我没有剥夺你理解OpenGL的最后一丝希望。我可以向你保证,这种理解将随着时间的推移而成熟。

由于其出色的特性,glScale*不仅能够调整对象的大小,而且还可以通过将负值传递给glScale*来镜像对象。因此,例如,D3D转换器可以通过调用glScalef(1,1,-1)来简化生活,以确保Z轴正向进入屏幕。
任何想了解模型视图矩阵功能的人,我都想推荐Lithander的Matrixcontrol程序(见附录)。它允许您直接看到矩阵的某些更改,如果您稍微摆弄一下程序,即使最后一个也会很快出现。如果没有,那么只有勤奋的编程和应用程序才有帮助,在某些时候,当你的手掌停在额头上时,它会发出响亮的声音;)。

 

无论是谁读了这个标题,现在不可避免地记得他在生活中已经吃了什么,或者第二天早上醒来的人,都不知道!我们谈论的是完全不同的事情。。。
正如我们已经了解到的,每次调用glTranslate*、glRotate*或glScale*都会改变世界矩阵并直接影响其他对象。这可能是非常可取的。然而,如果我们在一个大世界中放置不同的物体,这很快就会成为一个诅咒。当然,我们可以抵消这种情况,并每次调用glLoadIdentity。然而,这有一个缺点,即世界矩阵再次为空,我们必须首先设置相机,以便在正确的位置变换对象。

一个更优雅的解决方案是使用“矩阵堆栈”!对glPushMatrix的每次调用都会导致将当前矩阵写入堆栈。我们随后进行的所有操作都照常进行。绘制完所有内容后,我们使用glPopMatrix从堆栈中检索最后一个矩阵,并基本上重建了更改之前的最后一个状态,然后可以再次开始构建此矩阵。当然,也可以将几个矩阵推到堆栈上!这可以节省大量时间,因为否则您必须不断重置场景的矩阵。
为了让整个事情更清楚一点,让我们举一个简单的例子。我们将在原点的右侧和左侧分别绘制两个三角形。绘制左侧对象后,我们将不使用glLoadIdentity或相应地向右转换第二个对象,而是使用矩阵堆栈。

glLoadIdentity();
glTranslatef(0,0,-10);
glPushMatrix();-----存入堆栈,设置第一个场景
  glTranslatef(-2,0,0);
  glBegin(GL_TRIANGLES);
    glColor3f(1,0,0); glVertex3f(-1,-1, 0);
    glColor3f(0,0,1); glVertex3f( 1,-1, 0);
    glColor3f(0,1,0); glVertex3f( 0, 1, 0);
  glEnd();
glPopMatrix();----取出堆栈,设置第二个场景

glTranslatef(2,0,0);
glBegin(GL_TRIANGLES);
  glColor3f(1,0,0); glVertex3f(-1,-1, 0);
  glColor3f(0,0,1); glVertex3f( 1,-1, 0);
  glColor3f(0,1,0); glVertex3f( 0, 1, 0);
glEnd();

 

 如上图,二次设置分别让模型向X正反方向进行了移动。

任何认为这已经是事实的人都是错的。还有其他方法可以影响矩阵。命令glLoadMatrix*允许您加载任何4x4矩阵,并用加载的矩阵完全替换当前矩阵。
glMultMatrix*命令将传递的4x4矩阵乘以当前矩阵。例如,您可以使用此命令编写自己的glScale*和glRotate*命令,尽管您也可以在这里讨论其含义。更有用的应用程序将在后面的教程中介绍。
带有标记GL_MODELVIEW_MATRIX、GL_TEXTURE_MATRIX和GL_PROJECTION_MATRIX的glGet*命令允许您请求各个矩阵。



任何一个已经尝试过自豪地向他的朋友展示第一个自己编写的OpenGL程序的人都会注意到,另一台计算机上的动作比自己的计算机上的快或慢。
这种现象很容易解释。假设我们在屏幕上围绕值1从左向右移动一个三角形。像我的电脑这样的老拐杖可能会达到50 FPS。这意味着该对象在一秒钟内向右移动50毫米。这意味着一秒钟总共50个单位。但如果该程序在高端系统上运行,我们将能够更新场景…例如…500次。因此,在这个计算器上,三角形在一秒钟内移动500个单位。
我们唯一能从三角形中捕捉到的是屏幕上闪电般的抽搐,我们很快就会将其视为视觉错觉。但我们如何应对这个问题呢?
假设我们知道绘制一个框架所需的时间,并使用该值来确定我们纳入运动的时间因素。

NewPosition := OldPosition + Movement * TimeFactor;
新位置=老位置+运动向量*时间因子,旧电脑的FPS不如新电脑的FPS。

 

 




posted @ 2022-11-21 10:10  下雨天不爱打伞  阅读(33)  评论(0编辑  收藏  举报