`
chriszeng87
  • 浏览: 713844 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

OpenGL使用矩阵堆栈glpushMatrix的原因

阅读更多

1.原理讲解

 终于明白为什么使用glPushMatrix()和glPopMatrix()的原因了。将本次需要执行的缩放、平移等操作放在glPushMatrix和glPopMatrix之间。glPushMatrix()和glPopMatrix()的配对使用可以消除上一次的变换对本次变换的影响。使本次变换是以世界坐标系的原点为参考点进行。下面对上述结论做进一步的解释:

1)OpenGL中的modelview矩阵变换是一个马尔科夫过程:上一次的变换结果对本次变换有影响,上次modelview变换后物体在世界坐标系下的位置是本次modelview变换的起点。默认时本次变换和上次变换不独立。

2)OpenGL物体建模实际上是分两步走的。第一步,在世界坐标系的原点位置绘制出该物体;第二步,通过modelview变换矩阵对世界坐标系原点处的物体进行仿射变换,将该物体移动到世界坐标系的目标位置处。

3)将modelview变换放在glPushMatrix和glPopMatrix之间可以使本次变换和上次变换独立。

4)凡是使用glPushMatrix()和glPopMatrix()的程序一般可以判定是采用世界坐标系建模。既世界坐标系固定,modelview矩阵移动物体。

一般说来,矩阵堆栈常用于构造具有继承性的模型,即由一些简单目标构成的复杂模型。例如,一辆自行车就是由两个轮子、一个三角架及其它一些零部件构成的。它的继承性表现在当自行车往前走时,首先是前轮旋转,然后整个车身向前平移,接着是后轮旋转,然后整个车身向前平移,如此进行下去,这样自行车就往前走了。将上述模型的构造过程放在glPushMatrix和glPopMatrix之间,则本次汽车在世界坐标系中的位置不是基于上一次汽车的位置而给出的(以前一次的位置为参考),而是直接给出的以世界下的坐标(以世界坐标系的原点为参考)。整个过程是符合人的思维过程的,由于每次建模都是以单位阵为变换起点,故便于采用统一的实现方式进行处理。

矩阵堆栈对复杂模型运动过程中的多个变换操作之间的联系与独立十分有利。因为所有矩阵操作函数如glLoadMatrix()、glMultMatrix()、glLoadIdentity()等只处理当前矩阵或堆栈顶部矩阵,这样堆栈中下面的其它矩阵就不受影响。堆栈操作函数有以下两个:
          void glPushMatrix(void);

          void glPopMatrix(void);

第一个函数表示将所有矩阵依次压入堆栈中,顶部矩阵是第二个矩阵的备份;压入的矩阵数不能太多,否则出错。第二个函数表示弹出堆栈顶部的矩阵,令原第二个矩阵成为顶部矩阵,接受当前操作,故原顶部矩阵被破坏;当堆栈中仅存一个矩阵时,不能进行弹出操作,否则出错。由此看出,矩阵堆栈操作与压入矩阵的顺序刚好相反,编程时要特别注意矩阵操作的顺序。为了更好地理解这两个函数,我们可以形象地认为glPushMatrix()就是“记住自己在哪”,glPopMatrix()就是“返回自己原来所在地”。

2. 举例

例1. OpenGL光源位置的移动

移动方式: 先pushMatrix()一下,然后在进行移动操作,然后旋转操作,然后指定光源的位置,然后PopMatrix()一下,就完成了。

#include "windows.h"
#include <gl/glut.h>

static int spin = 0;

void init()
{
glShadeModel( GL_SMOOTH );
glEnable( GL_LIGHTING );
glEnable( GL_LIGHT0 );
glEnable( GL_DEPTH_TEST );

}

void display()
{
 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
 
 GLfloat position[] = { 0.0, 0.0, 1.5, 1.0 }; 
 //第一点也是最重要的一点:OpenGL中的模型视图变换矩阵全是右乘当前变换矩阵
 glPushMatrix();  //将当前变换矩阵(单位阵)压入堆栈
 glTranslatef( 0.0, 0.0, -5.0 );     // transformation 1
 glPushMatrix();  //将平移变换后的的矩阵作为当前变换矩阵压入堆栈,
 glRotated( (GLdouble)spin, 1.0, 0.0, 0.0 );
 glLightfv( GL_LIGHT0, GL_POSITION, position );
 glTranslated( 0.0, 0.0, 1.5 );
 glDisable( GL_LIGHTING );
 glColor3f( 0.0, 1.0, 0.0 );
 glutWireCube( 0.1 );//绿色的下框,代表光源位置
 glEnable( GL_LIGHTING );
 glPopMatrix();  //消除绘制绿色WireCube时对当前变换矩阵的影响

 glutSolidSphere( 0.5, 40, 40 );//以被光照的物体
 glPopMatrix(); // Pop the old matrix without the transformations.   //返回到单位矩阵
 glFlush();
}

void reshape( int w, int h )
{
 glViewport( 0, 0, (GLsizei)w, (GLsizei)h );
 glMatrixMode( GL_PROJECTION );
 glLoadIdentity();
 gluPerspective( 40.0, (GLfloat)w/(GLfloat)h, 1.0, 20.0 );
 glMatrixMode( GL_MODELVIEW );
 glLoadIdentity();
}

void mouse( int button, int state, int x, int y )
{
 switch ( button )
 {
 case GLUT_LEFT_BUTTON:
  if ( state == GLUT_DOWN )
  {
   spin = ( spin + 30 ) % 360;
   glutPostRedisplay();
  }
  break;
 default:
  break;
 }
}

int main( int argc, char ** argv )
{
 glutInit( &argc, argv );
 glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH );
 glutInitWindowPosition( 100, 100 );
 glutInitWindowSize( 500, 500 );
 glutCreateWindow( argv[0] );
 init();
 glutDisplayFunc( display );
 glutReshapeFunc( reshape );
 glutMouseFunc( mouse );
 glutMainLoop();
 return 0;
}

例2  机械手臂的旋转

下面例子中的机械手臂是由两个简单的长方体依据一定的继承关系构成的。glPushMatrix和glPopMatrix之间的变换相对前一次是独立的

#include "windows.h"
#include <GL/gl.h>

#include <GL/glu.h>

#include <GL/glaux.h>

void myinit(void);

void drawPlane(void);

void CALLBACK elbowAdd (void);

void CALLBACK elbowSubtract (void);

void CALLBACK shoulderAdd (void);

void CALLBACK shoulderSubtract (void);

void CALLBACK display(void);

void CALLBACK myReshape(GLsizei w, GLsizei h);


static int shoulder = 0, elbow = 0;

void CALLBACK elbowAdd (void)

{
   elbow = (elbow + 5) % 360;

}

void CALLBACK elbowSubtract (void)

{
   elbow = (elbow - 5) % 360;

}

void CALLBACK shoulderAdd (void)

{
   shoulder = (shoulder + 5) % 360;

}

void CALLBACK shoulderSubtract (void)

{
   shoulder = (shoulder - 5) % 360;

}

void CALLBACK display(void)

{
   glClear(GL_COLOR_BUFFER_BIT);
   glColor3f(0.0, 1.0, 1.0);

   glPushMatrix(); // 将此句注释掉后可以发现上一次的变换结果对当前变换有影响,加上了glPushMatrix的目的是让各次变换相互独立。

   glTranslatef (-0.5, 0.0, 0.0); // 将旋转后的Wirebox向左移动0.5个单位
   glRotatef ((GLfloat) shoulder, 0.0, 0.0, 1.0);   //看到shoulder是相对于0的绝对角度,不是基于上一次位置的相对角度。
   glTranslatef (1.0, 0.0, 0.0); //Step 1将WireBox向右移动一个单位
   // void auxWireBox(GLdouble width,GLdouble height,GLdouble depth)

   auxWireBox(2.0, 0.2, 0.5);  //这个WireBox以x=1为中心,width=2从该中心开始向两边各延伸1个单位。

   glTranslatef (1.0, 0.0, 0.0);
   glRotatef ((GLfloat) elbow, 0.0, 0.0, 1.0);
   glTranslatef (0.8, 0.0, 0.0);
   auxWireBox(1.6, 0.2, 0.5);

   glPopMatrix(); // 可以看出glPushMatrix和glPopMatrix之间的变换效果被消除。清除上一次对modelview矩阵的修改。
   glFlush();

}

void myinit (void)

{
   glShadeModel (GL_FLAT);

}

void CALLBACK myReshape(GLsizei w, GLsizei h)

{
   glViewport(0, 0, w, h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   gluPerspective(65.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   glTranslatef (0.0, 0.0, -5.0);  /* 认为是viewing transform 不好理解,因此时是物体不动,世界坐标系向z轴正方向移动5个单位,眼睛位于世界坐标系的原点; 此处理解为对模型的变换更加直观既将物体向负z轴移动5个单位。*/
 }

void main(void)

{
   auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
   auxInitPosition (0, 0, 400, 400);
   auxInitWindow ("Composite Modeling Transformations");
   myinit ();
   auxKeyFunc (AUX_LEFT, shoulderSubtract);
   auxKeyFunc (AUX_RIGHT, shoulderAdd);
   auxKeyFunc (AUX_UP, elbowAdd);
   auxKeyFunc (AUX_DOWN, elbowSubtract);
   auxReshapeFunc (myReshape);
   auxMainLoop(display);
 
}

 

转自:http://anony3721.blog.163.com/blog/static/511974201133095555708/

分享到:
评论

相关推荐

    opengl中的堆栈操作

    本算法可以学习函数 glPushMatrix(void)和 glPopMatrix(void)的使用方法

    OpenGl实验报告.doc

    实验目的与要求 1、学习和掌握OpenGL的使用 2、掌握矩阵堆栈的实现方法 3、根据自己的创意实现实验内容,进一步掌握和理解OpenGL的使用 2. 实验内容 1、请编写地球围绕太阳自动旋转的方式 2、请再加上一个月亮, 并...

    用opengl做的太阳系

    VC+Opengl做的一个关于太阳系的一个例子。实现的功能比较简单,能够选择、放大缩小、全屏等功能。希望对下载的各位能有所帮助。

    基于 C++ OpenGL框架实现小桌模型绘制【100010594】

    首先考虑到后续要组合多个图形并且要做矩阵变换,用glPushMatrix和glPopMatrix函数,对栈顶矩阵进行处理。对于矩阵的操作都是对于矩阵栈的栈顶来操作的。当前矩阵即为矩阵栈的栈顶元素,而对当前矩阵进行平移、旋转...

    计算机图形学OpenGL画机器人

    计算机图形学OpenGL画机器人,学习glPopMatrix()和glPushMatrix()的作用

    用opengl绘制一个旋转正方体.cpp

    //使用双缓存 使用深度缓存。 glutInitWindowSize(480, 480); glutCreateWindow("OpenGL颜色立方体"); glutReshapeFunc(reshape); //窗口改变的时候调用的函数 glutDisplayFunc(display); glutSpecialFunc...

    opengl的太阳系模型

    // 初始化OpenGL void InitGL(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //设置黑色背景 glClearDepth(2.0f); // 设置深度缓存 glEnable(GL_DEPTH_TEST); //启动深度测试 glDepthFunc(GL_LEQUAL); //深度...

    OpenGL 库函数汇总(中文分类)CHM

    glPushMatrix , glPopMatrix glPushAttrib , glPopAttrib glPushName , glPopName glInitName glLoadName 1.GL 函数库(续) =============================== 显示列表 ----------------------------- ...

    opengl 帮助文档

    Name glScalef , glScalex - multiply the current matrix by a general scaling matrix C Specification void glScalef(GLfloat x, ...glEnable, glMatrixMode, glMultMatrix, glPushMatrix, glRotate, glTranslate

    opengl橡皮筋

    // 使用新的坐标重新绘制场景 glutPostRedisplay(); } void init(void) { glClearColor(1.0, 1.0, 1.0, 0.0); glEnable(GL_DEPTH_TEST); glShadeModel(GL_SMOOTH); makeStripeImage(); glPixelStorei(GL_...

    openGL期末大作业——行走的机器人

    通过glPushMatrix() 和glPopMatrix()绘制出机器人层次结构模型和几何变换,要求实现机器人手、脚、头、肩膀的旋转等几何变换,能够实现机器人走路的效果。同时机器人打上光照。内付完整代码以及实验报告!!

    openGL程序

    glPushMatrix(); glTranslatef(0.0f,-0.3f,-4.0f); if(xRot&gt;360.5f) { xRot=0.0f; } if(yRot&gt;360.5f) { yRot=0.0f; } glBotatef(xROt,1.0f,0.0f,0.0f); glRotatef(yRot,0.0f,1.0f,0.0f); ...

    threejs-coord-frames:使用单独的坐标系为three.js 中的对象层次设置动画

    在 OpenGL 中,我们使用以下代码表示上述依赖项: glPushMatrix(); glMulMatrixf (__support_frame_cf__); support_frame.render(); glPushMatrix(); glMulMatrixf (__arm_cf__); arm.render(); ...

    HKUST_Modeler:在此项目中,您将定义3D模型和用于移动它的控件,然后显示和操作该模型。 在这个项目中,您将使用OpenGL创建和动画自己设计的角色。 您将熟悉3D分层建模和转换

    )您还必须使用glPushMatrix()和glPopMatrix ()来嵌套矩阵转换。 建模器框架提供了用于创建滑块并将其挂接到模型的不同功能的功能。 您必须添加至少其中之一作为模型某些关节/组件的控制旋钮(实际上是滑块)-在...

    使用双缓存行走的机器人

    使用双缓存绘制行走的机器人,使用glPushMatrix()和glPopMatrix()命令保存和恢复个状态变量的值。按下“g”键,机器人向前迈出一步。

    HumanMotionTrack 全

    假定读者已经熟悉OpenGL编程,就算不熟悉,只要了解基本的旋转,平移,堆栈操作就好。 假定读者已经了解基本的c++编程,其中需要了解递归的算法,递归的方法请参考一下数据结构吧。 制作过程: 第一步,3D模型...

    计算机图形学制作时钟源代码

    PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL| PFD_DOUBLEBUFFER|PFD_SUPPORT_GDI, PFD_TYPE_RGBA, 24, 0,0,0,0,0,0, 0, 0, 0, 0,0,0,0, 32, 0, 0, PFD_MAIN_PLANE, 0, 0,0,0 }; this-&gt;m_GLPixelIndex ...

    计算机图形学 交互实体模型

    交互式 实体模型 简单po一段代码 #include #define ball1 5.0 #define jh 2.0 #define sjr 0.5 #pragma comment( linker, "/subsystem:\"windows\" /entry:\... glPushMatrix(); gluSphere(obj[0], ball1, 1

    图形绘制机器人

    图形学中用gult绘制机器人,机器人绘制:通过glPushMatrix() 和glPopMatrix()绘制出机器人层次结构模型

    高级图形学期末大作业.rar_23R_人运动模型_读取obj文件

    实现机器人带光照的绘制和运动变换。通过glPushMatrix() 和glPopMatrix()绘制出机器人层次结构模型和几何变换,要求实现机器人手、脚、头、肩膀的旋转等几何变换,能够实现机器人走路的效果。同时机器人应打上光照。

Global site tag (gtag.js) - Google Analytics