在视图模型变换中,顶点v的变换是按照相反的顺序发生的,而不是按照它的代码中先后顺序出现的。下面举例说明。
考虑下面的代码:
glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMultMatrixf(N); glMultMatrixf(M); glMultMatrixf(L); glBegin(GL_POINTS); glVertex3dv(v); glEnd();
在这段代码中,模型视图矩阵按顺序分别包含I、N、NM,最后是NML,其中I表示单位矩阵。经过变化的顶点是NMLv。因此顶点变换就是N(M(Lv))。
下面看绘制机器人手臂的display()函数的代码:
void display() { glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glTranslatef(-1.0,0.0,0.0); glRotatef((GLfloat)shoulder,0.0,0.0,1.0); glTranslatef(1.0,0.0,0.0); //绘制第一段手臂 glPushMatrix(); glScalef(2.0,0.4,1.0); glutWireCube(1.0); glPopMatrix(); glTranslatef(1.0,0.0,0.0); glRotatef((GLfloat)elbow,0.0,0.0,1.0); glTranslatef(1.0,0.0,0.0); //绘制第二段手臂 glPushMatrix(); glScalef(2.0,0.4,1.0); glutWireCube(1.0); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); }
我们通过逐步调试运行来查看效果。
现在注释掉代码:
glTranslatef(-1.0,0.0,0.0); glRotatef((GLfloat)shoulder,0.0,0.0,1.0); glTranslatef(1.0,0.0,0.0);
以及绘制第二段手臂的代码:
//绘制第二段手臂 glPushMatrix(); glScalef(2.0,0.4,1.0); glutWireCube(1.0); glPopMatrix();
只保留绘制第一段的代码,便于查看效果。
运行结果:
显示的是经过缩放了的立方体。
然后解除下面这行代码的注释:glTranslatef(1.0,0.0,0.0);(位于旋转之下的代码)
运行结果:
显示的是经过缩放、平移的结果。
在解除这行代码的注释:glRotatef((GLfloat)shoulder,0.0,0.0,1.0);
运行结果:
显示的是经过缩放、平移、再旋转地结果。
再解除这行代码的注释:glTranslatef(-1.0,0.0,0.0);(位于旋转之上的代码)
运行结果:
可以看出是上一步的结果又平移之后的效果。
从上面的单步效果可以看出,乘法的出现顺序和他们的代码中得出现顺序相反。
最后给出绘制两端机器人手臂整个代码:
//绘制机器人手臂 #include
static int shoulder = 0,elbow = 0;//两段手臂旋转的角度 void init () { glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_FLAT); } void display() { glClear(GL_COLOR_BUFFER_BIT); glPushMatrix(); glTranslatef(-1.0,0.0,0.0); glRotatef((GLfloat)shoulder,0.0,0.0,1.0); glTranslatef(1.0,0.0,0.0); //绘制第一段手臂 glPushMatrix(); glScalef(2.0,0.4,1.0); glutWireCube(1.0); glPopMatrix(); glTranslatef(1.0,0.0,0.0); glRotatef((GLfloat)elbow,0.0,0.0,1.0); glTranslatef(1.0,0.0,0.0); //绘制第二段手臂 glPushMatrix(); glScalef(2.0,0.4,1.0); glutWireCube(1.0); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); } void reshape(int w,int h) { glViewport(0,0,(GLsizei)w,(GLsizei)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); } void keyboard(unsigned char key,int x,int y) { switch(key)//s和e键控制两端手臂的旋转角度 { case 's': shoulder = (shoulder + 5)% 360; glutPostRedisplay(); break; case 'S': shoulder = (shoulder - 5)% 360; glutPostRedisplay(); break; case 'e': elbow = (elbow + 5) % 360; glutPostRedisplay(); break; case 'E': elbow = (elbow - 5) % 360; glutPostRedisplay(); break; default: break; } } int main(int argc,char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(400,400); glutInitWindowPosition(100,100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }运行效果(通过s和e键可以控制两端手臂的旋转角度):