3.8 一些组合变换的例子

来源:互联网 发布:ubuntu 16.04 unity 编辑:程序博客网 时间:2024/04/29 15:22

这一小节主要是两个例子:创建太阳系模型,创建机器人手臂。
这两个例子,主要用来讲解如何对视图模型进行变换。

3.8.1 创建太阳系模型

/**  planet.c*  This program shows how to composite modeling transformations*  to draw translated and rotated models.*  Interaction:  pressing the d and y keys (day and year)*  alters the rotation of the planet around the sun.*/#include <GL/glut.h>#include <stdlib.h>static int year = 0, day = 0;void init(void){    glClearColor(0.0, 0.0, 0.0, 0.0);    glShadeModel(GL_FLAT);}void display(void){    glClear(GL_COLOR_BUFFER_BIT);    glColor3f(1.0, 1.0, 1.0);    glPushMatrix();    glutWireSphere(1.0, 20, 16);   /* draw sun */    glRotatef((GLfloat)year, 0.0, 1.0, 0.0);    glTranslatef(2.0, 0.0, 0.0);    glRotatef((GLfloat)day, 0.0, 1.0, 0.0);    glutWireSphere(0.2, 10, 8);    /* draw smaller planet */    glPopMatrix();    glutSwapBuffers();}void reshape(int w, int h){    glViewport(0, 0, (GLsizei)w, (GLsizei)h);    glMatrixMode(GL_PROJECTION);    glLoadIdentity();    gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);    glMatrixMode(GL_MODELVIEW);    glLoadIdentity();    gluLookAt(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);}/* ARGSUSED1 */void keyboard(unsigned char key, int x, int y){    switch (key) {    case 'd':        day = (day + 10) % 360;        glutPostRedisplay();        break;    case 'D':        day = (day - 10) % 360;        glutPostRedisplay();        break;    case 'y':        year = (year + 5) % 360;        glutPostRedisplay();        break;    case 'Y':        year = (year - 5) % 360;        glutPostRedisplay();        break;    case 27:        exit(0);        break;    default:        break;    }}int main(int argc, char** argv){    glutInit(&argc, argv);    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);    glutInitWindowSize(500, 500);    glutInitWindowPosition(100, 100);    glutCreateWindow(argv[0]);    init();    glutDisplayFunc(display);    glutReshapeFunc(reshape);    glutKeyboardFunc(keyboard);    glutMainLoop();    return 0;}

上述程序,按住字母d键,小球就会自己旋转,按住字母y键,小球就会绕太阳旋转。
这里写图片描述

主要代码如下:

    glutWireSphere(1.0, 20, 16);   /* draw sun */    glRotatef((GLfloat)year, 0.0, 1.0, 0.0);    glTranslatef(2.0, 0.0, 0.0);    glRotatef((GLfloat)day, 0.0, 1.0, 0.0);    glutWireSphere(0.2, 10, 8);    /* draw smaller planet */

先绘制一个太阳。接下来,有3个操作,旋转,平移,旋转。根据之前的学习,最先作用于物体的是 最后一个旋转,即day对应的旋转,绕着y轴(0.0, 1.0, 0.0),这相当于一个物体本身旋转day度, 接着平移,这个物体沿x方向平移2个单位,最后又旋转,这个物体绕原点(即太阳所在的点)旋转,旋转角度为year,旋转轴为y轴。这样就有了我们看到的效果了。

3.8.2 创建机器人手臂

/* * robot.c * This program shows how to composite modeling transformations * to draw translated and rotated hierarchical models. * Interaction:  pressing the s and e keys (shoulder and elbow) * alters the rotation of the robot arm. */#include <GL/glut.h>#include <stdlib.h>static int shoulder = 0, elbow = 0;void init(void) {  glClearColor (0.0, 0.0, 0.0, 0.0);  glShadeModel (GL_FLAT);}void display(void){   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);}/* ARGSUSED1 */void keyboard (unsigned char key, int x, int y){   switch (key) {      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;      case 27:         exit(0);         break;      default:         break;   }}int main(int argc, char** argv){   glutInit(&argc, argv);   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);   glutInitWindowSize (500, 500);    glutInitWindowPosition (100, 100);   glutCreateWindow (argv[0]);   init ();   glutDisplayFunc(display);    glutReshapeFunc(reshape);   glutKeyboardFunc(keyboard);   glutMainLoop();   return 0;}

这段代码的运行效果如下:
这里写图片描述
按下S旋转整个手臂,按下E键旋转前半段手臂。

主要代码是绘制第一段手臂和第二段手臂。

第一段手臂

    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();

同样的道理,最后出现的操作,最先作用于物体。最先是对物体进行缩放,glScalef(2.0, 0.4, 1.0), x,y,z方向,分别缩放2.0, 0.4, 1.0这样,glutWireCube就不再是一个立方体了,而变成了长方体。然后这个缩放,由于是放在glPushMatrix和glPopMatrix中,所以,缩放不对原来的坐标系产生影响。

然后,glTranslatef(1.0, 0.0, 0.0);这个长方体,进行平移,向x轴方向平移一个单位,这样的话,坐标原点就位于长方体的左端了。如下图所示。刚开始,坐标原点位于长方体中心,现在,由于物体向右平移了一个单位,所以原点位于长方体左端。
这里写图片描述

接着,glRotatef((GLfloat)shoulder, 0.0, 0.0, 1.0); 物体绕经过原点的z轴旋转shoulder度,由于z轴指向屏幕外,所以旋转之后的结果就是这样的。
这里写图片描述

最后,glTranslatef(-1.0, 0.0, 0.0); 又对物体进行移动,沿x轴移动-1.0个单位,所以其实就是将坐标系原点,又移回物体中心。

第二段手臂

    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();

同样的,先对物体进行缩放,得到一个长方体。

然后将物体沿x轴平移一个单位,相对于这个物体的坐标原点移动到了物体的左端。

然后在旋转elbow角度,绕z轴,这个原理和第一个一样的。

最后再平移一个单位,这个其实就是将第二个物体的坐标原点,移动到和第一个物体坐标原点重合的位置。

好了,其他就没啥了。

0 0
原创粉丝点击