OpenGL手臂旋转肩膀和肘部

时间:2018-10-04 17:06:12

标签: c opengl rotation transformation glut

我编写了以下代码:

#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#define WIDTH 400
#define HEIGTH 400
#define ORIGIN_X 50
#define ORIGIN_Y 50

#define move(x,y) glTranslatef(x, y, 0.0f);
#define enlarge(y) glScalef(1, y, 1);

#define rotateX(angle) glRotatef(angle, 1,0,0);
#define rotateY(angle) glRotatef(angle, 0,1,0);
#define rotateZ(angle) glRotatef(angle, 0,0,1);

// Variables que definen la rotación del brazo entero (de hombro a mano)
static GLfloat shoulder_Xangle, shoulder_Yangle, shoulder_Zangle;
// Variables que definen sólo la rotación del antebrazo (de codo a mano)
static GLfloat elbow_Xangle, elbow_Yangle, elbow_Zangle;

void keyboardHandler(unsigned char key, int x, int y ){

    switch(key){
        case 'q': shoulder_Zangle++; break;
        case 'e': shoulder_Zangle--; break;
        case 'a': shoulder_Yangle++; break;
        case 'd': shoulder_Yangle--; break;
        case 'w': shoulder_Xangle++; break;
        case 's': shoulder_Xangle--; break;
        case 'r':    elbow_Zangle++; break;
        case 'y':    elbow_Zangle--; break;
        case 'f':    elbow_Yangle++; break;
        case 'h':    elbow_Yangle--; break;
        case 't':    elbow_Xangle++; break;
        case 'g':    elbow_Xangle--; break;
        default:                     break;
    }

    glutPostRedisplay();                // Avisa que la ventana ha de refrescarse
}

void init() {
    glutKeyboardFunc(keyboardHandler);  // Asociar handler a eventos procedentes del teclado
    glClearColor(0.0,0.0,0.0,0.0);  // Fijar el color por defecto a negro en el formato RGBA
}

void rotate(GLfloat Xangle, GLfloat Yangle, GLfloat Zangle) {
    rotateX(Xangle);        // Rotar Xangle grados sobre el eje X
    rotateY(Yangle);        // Rotar Yangle grados sobre el eje Y
    rotateZ(Zangle);        // Rotar Zangle grados sobre el eje Z
}

void draw_sphere(GLdouble radius) {
    GLint slices = 360;
    GLint stacks = 360;
    glutWireSphere(radius, slices, stacks);
}

void draw_cube() {

    glBegin(GL_QUADS);

      glColor3f ( 0.0,  0.7,  0.1);     // Parte anterior: verde        
      glVertex3f(-0.5,  0.5,  0.5);
      glVertex3f( 0.5,  0.5,  0.5);
      glVertex3f( 0.5, -0.5,  0.5);
      glVertex3f(-0.5, -0.5,  0.5);

      glColor3f ( 1.0,  0.0,  0.0);     // Parte posterior: rojo 
      glVertex3f(-0.5,  0.5, -0.5);     
      glVertex3f( 0.5,  0.5, -0.5);
      glVertex3f( 0.5, -0.5, -0.5);
      glVertex3f(-0.5, -0.5, -0.5);

      glColor3f ( 1.0,  1.0,  1.0);     // Resto: blanco
      glVertex3f(-0.5,  0.5,  0.5);
      glVertex3f( 0.5,  0.5,  0.5);
      glVertex3f( 0.5,  0.5, -0.5);
      glVertex3f(-0.5,  0.5, -0.5);

      glVertex3f(-0.5, -0.5,  0.5);
      glVertex3f( 0.5, -0.5,  0.5);
      glVertex3f( 0.5, -0.5, -0.5);
      glVertex3f(-0.5, -0.5, -0.5);

    glEnd();
}

void draw_shoulder() { draw_sphere(0.5); }

void draw_elbow() {
    move(0, -3.0)                                              // 3) Colocar en su posición final
    rotate(elbow_Xangle, elbow_Yangle, elbow_Zangle);          // 2) Rotamiento del codo
    draw_sphere(0.5);                                          // 1) Dibujar 1 esfera (codo) 
}

void draw_arm() {
    move(0.0, -1.5);                                           // 3) Colocar en su posición final
    enlarge(2.0);                                              // 2) Escalar el brazo
    draw_cube();                                               // 1) Dibujar 1 cubo (brazo)
}

void draw_forearm() {
    move(0.0, -3.0);                                           // 5) Colocar en su posición final
    rotate(elbow_Xangle, elbow_Yangle, elbow_Zangle);          // 4) Rotamiento del codo
    move(0.0, -1.5);                                           // 3) Mover hacia abajo para que el radio de rotación = tamaño codo
    enlarge(2.0);                                              // 2) Escalar el antebrazo
    draw_cube();                                               // 1) Dibujar 1 cubo (antebrazo)
}

void draw_hand() {
    move(0, -3.0);                                             // 4) Colocar en su posición final
    rotate(elbow_Xangle, elbow_Yangle, elbow_Zangle);          // 3) Rotamiento del codo
    move(0.0, -2.5)                                            // 2) Mover hacia abajo el tamaño del codo+antebrazo = (1.0+2.0)-0.5
    rotateX(90);                                               // 1) Poner la mano en su sitio
    glutSolidCone(0.5, 1.5, 360, 360);
}

void display() {


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);         // Borrado del FrameBuffer
    glEnable(GL_DEPTH_TEST);

    glLoadIdentity();                                           // Cargar la matriz identidad en la matriz de proyección            

    rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);  // Movimiento del hombro          
    draw_shoulder();                                            // Dibujar el hombro                          

    glLoadIdentity();

    rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);  // Movimiento del hombro
    draw_arm();                                                 // Dibujar el brazo

    glLoadIdentity();

    rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);  // Movimiento del hombro
    draw_elbow();                                               // Dibujar el codo

    glLoadIdentity();

    rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);  // Movimiento del hombro
    draw_forearm();                                             // Dibujar el antebrazo

    glLoadIdentity();

    rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);  // Movimiento del hombro
    draw_hand();                                                // Dibujar la mano


    // Forzar renderizado
    glutSwapBuffers();                   
}

void reshape(int w, int h) {

    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);                              // Activar las modificaciones en la cámara
    glLoadIdentity();                            
    glOrtho(-8, 8, -12, 4, -8, 8);
    glMatrixMode(GL_MODELVIEW);                               // Activar las modificaciones en el modelo
}

int main(int argc, char** argv) {

    glutInit(&argc, argv);                                    // Cargar el teclado y el ráton

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); // Búffer doble, con color RGB y profundidad

    glutInitWindowSize(WIDTH, HEIGTH);                        // Tamaño de la ventana
    glutInitWindowPosition(ORIGIN_X, ORIGIN_Y);               // Posición del extremo superior-izquierdo de la ventana

    glutCreateWindow("Brazo Articulado");                     // Crear la ventana
    init();
    glutDisplayFunc(display);                                 // Activar la función de pintado
    glutReshapeFunc(reshape);                                 // Activar la función de escalado
    glutMainLoop();                                           // Arrancar el bucle de OpenGL

    return 0;
}

enter image description here

基本上,我的手臂由肩膀,手臂,肘部,前臂和手组成。当肩部旋转时,所有这些组件也必须旋转。但是,当肘部旋转时,只有肘部,前臂和手才旋转。

出于无知,要实现这一目标,我基本上为手臂的每个组件都设置了“肩旋转”,为最后三个组件设置了“肘部旋转”,如您在显示功能和我的“ draw_component”函数。

有人告诉我您可以通过添加2个“旋转”语句(一个用于肩膀,一个用于肘部)来实现相同的功能,而不是像我对每个组件所做的那样。

有什么想法可以做到吗?

1 个答案:

答案 0 :(得分:2)

请注意,自glBegin / glEnd序列开始绘制以来,已经过了几年。 阅读有关Fixed Function Pipeline的信息,并参阅Vertex SpecificationShader了解最新的渲染方式。


但是,如果要这样做,则可以通过glPushMatrix/glPupMatrix将矩阵推入并弹出到矩阵堆栈中。
如果您想想象矩阵运算如何改变模型,则需要以相反的顺序“读取”运算。这是因为,矩阵堆栈的当前矩阵乘以新操作指定的矩阵,并且矩阵以列优先顺序存储(固定函数管道)。
另请参见OpenGL translation before and after a rotation

如果将以下代码添加到display函数中,则会得到第二条手臂,其行为与第一条手臂相同:

void display() {

    // your original code
    ....  

    glLoadIdentity();

    move( 3.0, 0.0 )

    // rotate sholder
    rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);

    draw_sphere(0.5); // shoulder
    move(0.0, -1.5); 
    glPushMatrix();
    enlarge(2.0);                                     
    draw_cube(); //arm
    glPopMatrix();

    move(0.0, -1.5)

    // rotate elbow
    rotate(elbow_Xangle, elbow_Yangle, elbow_Zangle);

    draw_sphere(0.5); // elbow
    move(0.0, -1.5)  
    glPushMatrix();
    enlarge(2.0);  
    draw_cube();  // forearm
    glPopMatrix();
    move(0.0, -1.0)   
    rotateX(90);                  
    glutSolidCone(0.5, 1.5, 360, 360); // hand

    // Forzar renderizado
    glutSwapBuffers();                   
}

预览:


在这种情况下,glScalefenlarge)操作仅需要glPushMatrix/glPupMatrix
除了推动和弹出矩阵,您还可以执行逆运算。这意味着enlarge(2.0)可以被enlarge(0.5)反转:

// rotate sholder
rotate(shoulder_Xangle, shoulder_Yangle, shoulder_Zangle);

draw_sphere(0.5); // shoulder

move(0.0, -1.5); 
enlarge(2.0);                                     
draw_cube(); //arm
enlarge(0.5);

move(0.0, -1.5)

// rotate elbow
rotate(elbow_Xangle, elbow_Yangle, elbow_Zangle);

draw_sphere(0.5); // elbow

move(0.0, -1.5)  
enlarge(2.0);  
draw_cube();  // forearm
enlarge(0.5);

move(0.0, -1.0)   
rotateX(90);                  
glutSolidCone(0.5, 1.5, 360, 360); // hand