OpenGL Рука, которая вращает плечо и локоть - PullRequest
0 голосов
/ 04 октября 2018

Я сделал следующий код:

#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

По сути, у меня есть рука, состоящая из плеча, руки, локтяпредплечья и кисти.Когда плечо вращается, все эти компоненты также должны вращаться.Однако, когда локоть вращается, вращаются только локоть, предплечье и рука.

Из-за моего невежества, чтобы достичь этого, я в основном поставил «поворот плеча» для каждого компонентамоей руки, и «поворот локтя» для моих последних 3 компонентов, как вы можете видеть в моей функции отображения и моих функциях «draw_component».

Мне сказали, что вы можете достичь той же функциональности, простодобавив 2 «вращающихся» предложения (одно для плеча и одно для локтя), а не так, как я делал для каждого компонента.

Есть идеи, как это можно сделать?

1 Ответ

0 голосов
/ 04 октября 2018

Обратите внимание, что рисование последовательностями glBegin / glEnd считается устаревшим в течение нескольких лет.Прочтите о конвейере с фиксированными функциями и посмотрите Спецификация вершин и Шейдер для современного способа рендеринга.


Но еслиесли вы хотите сделать это следующим образом, то вы можете вставить и вставить матрицы в стек матриц с помощью glPushMatrix/glPupMatrix.
Если вы хотите представить, как операции с матрицами изменяют модель, вам необходимо«читать» операции в обратном порядке.Это связано с тем, что текущая матрица стека матриц умножается на матрицу, заданную новой операцией, и матрицы хранятся в главном порядке столбцов (конвейер фиксированных функций).
См. Также Перевод OpenGL переди после поворота

Если вы добавите следующий код в функцию 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();                   
}

Предварительный просмотр:


В этом случае glPushMatrix/glPupMatrix необходим для glScalef (enlarge) только операция.
Вместо нажатия и выталкивания матрицы вы также можете выполнить обратную операцию.Это означает, что 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 
...