OpenGL中的glLoadIdentity、glTranslatef、glRotatef原理【转帖】

OpenGL中的glLoadIdentity、glTranslatef、glRotatef原理

 
单位矩阵  对角线上都是1,其余元素皆为0的矩阵。
在矩阵的乘法中,有一种矩阵起着特殊的作用,如同数的乘法中的1,我们称这种矩阵为单位矩阵.
它是个方阵,除左上角到右下角的对角线(称为主对角线)上的元素均为1以外全都为0.

OpenGL中的坐标用齐次坐标表示,即(x,y,z)表示成(x',y',z',h),其中x=x'/h; y=y'/h; z=z'/h. 通常h取1. 比如空间中的点(2,3,4),在OpenGL中将表示成(2,3,4,1). 齐次坐标表示方式适合于矩阵运算,也很方便地表示了无穷远的点,比如(1,0,0,0)就表示x轴上无穷远的点,因为1/0是无穷大,这里约定0/0=0.

接着要说点矩阵(线性代数)的知识。OpenGL里面的平移、旋转、缩放等变换均是线性变换,用矩阵相乘来表示。以平移变换为例,请见官方对glTranslatef函数的说明。假设有点(3,3,3),如果把该点沿x轴移动2单位,沿y轴移动3单位,沿z轴移动4单位,那么该点会是(3+2, 3+3, 4+4) = (5,6,7). 用矩阵表示是:

2009-11-29 18-42-47.png

左边的矩阵称为平移变换矩阵,若把2、3、4换成x、y、z,则用它乘以一个齐次坐标表示的向量,就可以将该向量平移(x,y,z). 旋转变换和缩放变换都像平移变换一样可用一个矩阵来表示。这里可以不用理会这些矩阵长什么样,只需清楚它们乘以一个齐次坐标表示的向量,就可以使该向量发生需要的变换。

把平移变换矩阵记为T(x,y,z),旋转变换矩阵记为R(x,y,z,s),表示绕向量(x,y,z)旋转s角度;把向量记为X。这里只需要知道它们是矩阵就行了,现在要把一个点X,如(3,3,3,1),移动(2,2,2)单位,再绕y轴旋转30度角,用矩阵表示即R(0,1,0,30)*T(2,2,2)*X,可以理解为离X最近的矩阵最先作用。理解这个顺序很重要,这样,所有变换都可以用一串矩阵的相乘来表示,计算机里面也确实是这么做的。

介绍完基本的数学知识,下面说OpenGL的作用机制。OpenGL有个变换矩阵堆栈,堆栈就像子弹夹一样,先进的后出。OpenGL中的每个向量,在被定义之后进入到OpenGL世界中,都必须先乘以这个变换矩阵堆栈的栈顶变换矩阵。如下图所示:

2009-11-29 19-12-50.png

理解完上面的知识,再来理解glLoadIdentity、glTranslatef、glRotatef这些函数干了什么就容易多了。这些函数就是对这个堆栈的操作:

  • glTranslatef:将T(x,y,z)右乘与堆栈的栈顶变换矩阵。右乘的解释,假设目前栈顶变换矩阵为M,那么就相当于把M修改为M*T.
  • glRotatef :将R(x,y,z,s)右乘与堆栈的栈顶变换矩阵。
  • glLoadIdentity:将堆栈的栈顶变换矩阵设置成单位矩阵。
  • glPushMatrix:将堆栈的栈顶变换矩阵复制一份,然后Push到堆栈中。所谓Push,就像塞子弹一样把一个矩阵压入到堆栈中,此时,栈顶就是这个新的矩阵了,注意定义的向量都是和栈顶变换矩阵作用的。
  • glPopMatrix:将堆栈的栈顶变换矩阵Pop出来。

该讲的讲完了,下面出几道题目练习下吧。

1、OpenGL代码是:glLoadIdentity(); glTranslate3f(4,5,1); glRotate3f(0,1,0,90); glVertex3f(1,1,1); 请问此时栈顶变换矩阵是什么?(1,1,1)这个点到了OpenGL世界中的点是什么?

答:栈顶变换矩阵是T(4,5,1)*R(0,1,0,90),(1,1,1)到OpenGL世界中的坐标是T(4,5,1)*R(0,1,0,90)*(1,1,1).

2、解释为什么使用glPushMatrix和glPopMatrix的组合可以隔离这两个函数中的变换,使之不影响后面的点?

答:glPushMatrix新压入的变换矩阵是复制了原来的栈顶变换矩阵,所以它继承了之前的变换,此后执行glTranslatef、glRotatef这些函数时,修改的是栈顶变换矩阵,在glPopMatrix之前的点都将受到栈顶变换矩阵的作用,之后用glPopMatrix,把栈顶变换矩阵Pop掉,此时的栈顶变换矩阵又还原成原来的那个栈顶变换矩阵。

3、为什么有时候glTranslate3f和glRotate3f能颠倒有时候又不能?

答:矩阵A乘以矩阵B未必等于矩阵B乘以矩阵A,当它们相等时,很多只是巧合。

发布了7 篇原创文章 · 获赞 7 · 访问量 7万+
展开阅读全文

关于Opengl建立的立体图形来利用鼠标来进行控制其旋转的问题

07-03

在vs2010里面我建立了open gl 后,添加了一个其自动旋转的三维立体图形,其代码如下 #include <GL/glut.h> GLfloat xRotated, yRotated, zRotated; void Display(void) { glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); glTranslatef(0.0,0.0,-4.0); glRotatef(xRotated,1.0,0.0,0.0); glRotatef(yRotated,0.0,1.0,0.0); glRotatef(zRotated,0.0,0.0,1.0); //glScalef(2.0,1.0,1.0); glutWireCube(1.5); glFlush(); //Finish rendering glutSwapBuffers(); } void Reshape(int x, int y) { if (y == 0 || x == 0) return; //Nothing is visible then, so return //Set a new projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); //Angle of view:40 degrees //Near clipping plane distance: 0.5 //Far clipping plane distance: 20.0 gluPerspective(40.0,(GLdouble)x/(GLdouble)y,0.5,20.0); glMatrixMode(GL_MODELVIEW); glViewport(0,0,x,y); //Use the whole window for rendering } static int times = 0; void Idle(void) { times++; if(times >30000) times = 0; if(times %30000 == 0) { xRotated += 0.3; yRotated += 0.1; zRotated += -0.4; Display(); } } int main (int argc, char **argv) { //Initialize GLUT glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); //For animations you should use double buffering glutInitWindowSize(300,300); //Create a window with rendering context and everything else we need glutCreateWindow("Cube example"); glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); xRotated = yRotated = zRotated = 0.0; glClearColor(0.5,0.5,0.0,0.0); //Assign the two used Msg-routines glutDisplayFunc(Display); glutReshapeFunc(Reshape); glutIdleFunc(Idle); //Let GLUT get the msgs glutMainLoop(); return 0; } 现如今想在这个代码的基础上可以用鼠标控制他的旋转。求源代码,望各位帮帮忙。最好附有效果图。谢谢各位。 问答

OpenGL 默认的Z轴方向问题

12-28

OpenGL默认的Z坐标轴的方向是垂直窗口向外的,以前用C语言开发OpenGL程序时一直没有出现问题。现在我用C#开发OpenGL程序,却发现默认的Z轴方向是垂直窗口向内,真的搞不懂怎么回事。我没有使用模型变换和投影变换,仅仅是是在窗口绘制两个简单的图形,发现Z坐标为负的图形可以看得见,而Z坐标为正的图形却被覆盖。已经开启了深度测试。代码如下: ``` void Draw() { GL.glEnable(GLCONST.GL_DEPTH_TEST); GL.glClear(GLCONST.GL_COLOR_BUFFER_BIT); GL.glClear(GLCONST.GL_DEPTH_BUFFER_BIT); //红色的三角形,Z=0; GL.glBegin(GLCONST.GL_TRIANGLES); GL.glColor3(1f, 0f, 0f); GL.glVertex3(-0.5f, -0.5f,0f); GL.glVertex3(0.5f, -0.5f,0f); GL.glVertex3(0f, 0.5f,0f); GL.glEnd(); //绿色的直线,Z=-0.5 GL.glColor3(0f, 1f, 0f); GL.glBegin(GLCONST.GL_LINES); GL.glVertex3(-0.8f, 0f, -0.5f); GL.glVertex3(0.8f, 0f, -0.5f); GL.glEnd(); //蓝色的直线,Z=0.5 GL.glColor3(0f, 0f, 1f); GL.glBegin(GLCONST.GL_LINES); GL.glVertex3(0f, 0.8f, 0.5f); GL.glVertex3(0f, -0.8f, 0.5f); GL.glEnd(); GL.glFlush(); } ``` 绘制时,发现红色的三角形(Z=0)会把蓝色的直线(Z=0.5)掩盖,而绿色的直线(Z=-0.5)浮在三角形之上。效果如下图: ![图片说明](https://img-ask.csdn.net/upload/201712/28/1514439525_203737.jpg) 这种问题,似乎有不少人遇到,但都没有的到很好的解决。特此悬赏160金币,希望有人能解决。只要提供解决的方法,或者给予启示,或者提供线索都可以获得悬赏。 问答

一个雪人程序,但是雪人无法显示出来,只弹出一个黑框,咋改呢?

09-21

#include<GL/glut.h> //旋转参数 static GLfloat xRot = 180; static GLfloat yRot = 180; void doMyInit() { glClearColor(0.0, 0.0, 0.0, 0.0); // Set the clear color to black // Specify the boundaries of the viewing window glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-1.0, 1.0, -1.0, 1.0); // The para are: (left, right, bottom, top) glMatrixMode(GL_MODELVIEW); } void snowman() { GLUquadricObj *pObj; // declare Quadric Object glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear the frame buffer // Save the matrix state and put the snowman in place glPushMatrix(); // Move snowman back and do in place rotation glTranslatef(0.0f, -1.0f, -5.0f); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); // create Quadric object pObj = gluNewQuadric(); gluQuadricNormals(pObj, GLU_SMOOTH); // Main Body glPushMatrix(); glColor3f(1.0f, 1.0f, 1.0f); gluSphere(pObj, .40f, 26, 13); // Bottom glTranslatef(0.0f, .550f, 0.0f); gluSphere(pObj, .3f, 26, 13); // Mid section glTranslatef(0.0f, 0.45f, 0.0f); gluSphere(pObj, 0.24f, 26, 13); // Head // Eyes glColor3f(0.0f, 0.0f, 0.0f); glTranslatef(0.1f, 0.1f, 0.21f); gluSphere(pObj, 0.02f, 26, 13); glTranslatef(-0.2f, 0.0f, 0.0f); gluSphere(pObj, 0.02f, 26, 13); // Nose glColor3f(1.0f, 0.3f, 0.3f); glTranslatef(0.1f, -0.12f, 0.0f); gluCylinder(pObj, 0.04f, 0.0f, 0.3f, 26, 13); glPopMatrix(); // Hat glPushMatrix(); glColor3f(0.0f, 0.0f, 0.0f); glTranslatef(0.0f, 1.17f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); gluCylinder(pObj, 0.17f, 0.17f, 0.4f, 26, 13); // Hat brim glDisable(GL_CULL_FACE); gluDisk(pObj, 0.17f, 0.28f, 26, 13); glEnable(GL_CULL_FACE); glTranslatef(0.0f, 0.0f, 0.40f); gluDisk(pObj, 0.0f, 0.17f, 26, 13); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); glFlush(); // Force to display the new drawings immediately } void reshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h);//设置视口 glMatrixMode(GL_PROJECTION);//指明当前矩阵为GL_PROJECTION glLoadIdentity();//将当前矩阵置换为单位阵 if (w <= h) gluOrtho2D(-1.0, 1.5, -1.5, 1.5*(GLfloat)h / (GLfloat)w);//定义二维正视投影矩阵 else gluOrtho2D(-1.0, 1.5*(GLfloat)w / (GLfloat)h, -1.5, 1.5); glMatrixMode(GL_MODELVIEW);//指明当前矩阵为GL_MODELVIEW } int main(int argc, char ** argv) { //初始化 glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500, 500); glutInitWindowPosition(0, 0); //创建窗口 glutCreateWindow("SnowMan"); /*绘制与显示*/ doMyInit(); glutReshapeFunc(reshape); glutDisplayFunc(snowman); //main event loop glutMainLoop(); return(0); } 问答

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览