c - 旋转肩膀和肘部的 OpenGL Arm

标签 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

基本上,我的 ARM 由肩膀、 ARM 、肘部、前臂和手组成。当肩膀旋转时,所有这些组件也必须旋转。然而,当肘部旋转时,只有肘部、前臂和手在旋转。

由于我的无知,为了实现这一点,我基本上为 ARM 的每个组件设置了“肩部旋转”,为我的最后 3 个组件设置了“肘部旋转”,正如您在我的显示功能和我的“draw_component”函数。

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

有什么想法可以做到这一点吗?

最佳答案

请注意,由 glBegin/glEnd 序列绘制已被弃用多年。 了解 Fixed Function Pipeline并查看 Vertex SpecificationShader最先进的渲染方式。


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

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

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 

关于c - 旋转肩膀和肘部的 OpenGL Arm,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52652098/

相关文章:

c - 动态分配内存中指针的访问值

c++ - 什么 OpenGL 函数在顶点着色器之前修改顶点位置?

performance - 如何优化基于 QGraphicsView 的应用程序的性能?

c++ - 语法错误 : unexpected $end at token "<EOF>" GLSL with any shader

c++ - 一种在SDL2、C++中旋转纹理的方法

html - 旋转div时如何显示不同的内容

javascript - 从左侧查找旋转的 div 顶部位置

c - 段错误 :11 in my code for creating a linked list in C

c - 无法发现C代码中的错误

c - 没有 free() 调用 malloc() 的真正后果是什么?它会使程序变得疯狂,例如永远循环吗?