OpenGL Arm that rotates shoulder and elbow

无人久伴 提交于 2019-12-24 08:09:27

问题


I've made the following code:

#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;
}

Basically, I have an arm made up of a shoulder, arm, elbow, forearm and hand. When the shoulder rotates, all those components have to rotate aswell. However, when the elbow rotates, only the elbow, the forearm and the hand are the ones that rotate.

From my ignorance, to achieve this, I've basically put a "shoulder rotate" for every single component of my arm, and an "elbow rotate" for my last 3 components, as you can see in my display function and my "draw_component" functions.

I've been told you can achieve the same functionality by just adding 2 "rotate" sentences (one for the shoulder and one for the elbow), and not like I did for every single component.

Any ideas how could this be made?


回答1:


Note, that Drawing by glBegin/glEnd sequences is deprecated since several years. Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.


But if you want to do it like this, then you can push and pop matrices to the matrix stack by glPushMatrix/glPupMatrix.
If you want to imagine how the matrix operations change the model, then you need to "read" the operations in the reverse order. This is, because the current matrix of the matrix stack is multiplied by the matrix which is specified by the new operation and the matrices are stored in column-major order (fixed function pipeline).
See also OpenGL translation before and after a rotation

If you add the following code to the display function, then you get a second arm, which behaves the same as the first:

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

Preview:


In this case the glPushMatrix/glPupMatrix is needed for the glScalef (enlarge) operation only.
Instead of push and pop the matrix you can do the inverse operation too. This means enlarge(2.0) can be reversed by 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 


来源:https://stackoverflow.com/questions/52652098/opengl-arm-that-rotates-shoulder-and-elbow

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!