红宝书上根据机器人手臂的例子做了简单的修改. 本来以为这次重新看了矩阵变换,对矩阵变换已经有了比较深刻的认识,直到合上书,在没有参考书上代码的情况下, 尝试自己实现这个简单的机器人手臂的变换,才知道还是有许多不足. 总结几个在理解model矩阵变化时, 需要注意的地方: 1. model矩阵变换的顺序和代码的顺序相反 2. 可以理解为 ,各种model变换,都会影响坐标轴本身.比如 glRotatef(),绕 z 轴旋转 30度后, 相当于整个坐标系(x,y,z 3轴), 都跟着做了一次变换. 再调用 glTranslatef() 沿x轴向左平移时, 就不是沿着原本坐标系的x轴向左平移了, 而是沿着新坐标系的 x轴向左平移, 相当于 向以前坐标轴的左下方平移了. 3. glLoadIdentity() 会将坐标系还原,使得坐标系不再受到以前各种变换的影响,而变成最最开始的 x轴 横平, y轴竖直,z轴向外. #include <GL/glut.h> static float shoulder_angle = 0.0f; static float elbow_angle = 0.0f; static float finger_angle = 0.0f; static float triangle_angle = 0.0f; static float ball_angle = 0.0f; const float BIG_ARM_LENGTH = 2.0f; const float SMALL_ARM_LENGTH = 1.5f; const float FINGER_LENGTH = 1.0f; const float BALL_RADIUS = 0.5f; void init() { glClearColor( 0.0,0.0,0.0,0.0); glShadeModel( /*GL_FLAT*/GL_SMOOTH ); glEnable( GL_CULL_FACE ); glCullFace( GL_BACK); } void display() { glClear( GL_COLOR_BUFFER_BIT ); glMatrixMode( GL_MODELVIEW); glLoadIdentity(); gluLookAt( 0,0,5,0,0,0,0,1,0); glPushMatrix(); { // big arm glColor3f(1.0f,0,0); glTranslatef(-BIG_ARM_LENGTH/2,0,0); glRotatef(shoulder_angle,0,0,1); glTranslatef(BIG_ARM_LENGTH/2,0,0); glPushMatrix(); glScalef(BIG_ARM_LENGTH,0.4,0.1); glutWireCube(1.0f); glPopMatrix(); // small arm glColor3f(1.0f,1.0f,0.0f); glTranslatef(BIG_ARM_LENGTH/2,0.0,0.0); glRotatef(elbow_angle,0,0,1); glTranslatef(SMALL_ARM_LENGTH/2,0.0,0.0); glPushMatrix(); glScalef(SMALL_ARM_LENGTH,0.4,0.1); glutWireCube(1.0f); glPopMatrix(); // finger glColor3f(1.0f,0.0f,1.0f); glTranslatef(SMALL_ARM_LENGTH/2,0.0,0.0); glRotatef( finger_angle,0,0,1); glTranslatef( FINGER_LENGTH/2,0,0); glPushMatrix(); glScalef(FINGER_LENGTH,0.4,0.1); glutWireCube(1.0f); glPopMatrix(); // the ball glColor3f(1.0f,0.0f,0.5f); glTranslatef( BALL_RADIUS * 2,0,0); glRotatef(ball_angle,1,0,0); glPushMatrix(); glScalef(1.0f,1.0f,1.0f); glutWireSphere( BALL_RADIUS,10,10); glPopMatrix(); } glPopMatrix(); // draw a triangle glPushMatrix(); { glRotatef( triangle_angle,1,0,0); glBegin( GL_TRIANGLES ); glColor3f(1,0,0); glVertex3f( 1,0,-1); glColor3f(1,1,0); glVertex3f( 0,1,-1); glColor3f(1,0,1); glVertex3f( -1,0,-1); glEnd(); } glPopMatrix(); glFlush(); } void reshape(int w,int h) { glViewport( 0,0,(GLsizei)w,(GLsizei)h); glMatrixMode( GL_PROJECTION); glLoadIdentity(); gluPerspective( 90,(GLdouble)w/(GLdouble)h,0.1,1000); } void keyboard(unsigned char key,int x,int y) { switch( key ) { // shoulder case 's': shoulder_angle += 5.0f; break; case 'S': shoulder_angle -= 5.0f; break; // elbow case 'e': elbow_angle += 5.0f; break; case 'E': elbow_angle -= 5.0f; break; // finger case 'f': finger_angle += 5.0f; break; case 'F': finger_angle -= 5.0f; break; // ball case 'b': ball_angle += 5.0f; break; case 'B': ball_angle -= 5.0f; break; // triangle case 't': triangle_angle += 5.0f; break; case 'T': triangle_angle -= 5.0f; break; default: break; } glutPostRedisplay(); } int main( int argc,char** argv) { glutInit( &argc,argv); glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB ); glutInitWindowSize( 800,600 ); glutInitWindowPosition( 100,100 ); glutCreateWindow("Clip Plane"); glutReshapeFunc( reshape); glutDisplayFunc( display); //glutMouseFunc( mousePress); //glutMotionFunc( mouseMove); glutKeyboardFunc( keyboard ); glutMainLoop(); return 0; }