我编写了以下代码:
#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;
}
基本上,我的手臂由肩膀,手臂,肘部,前臂和手组成。当肩部旋转时,所有这些组件也必须旋转。但是,当肘部旋转时,只有肘部,前臂和手才旋转。
出于无知,要实现这一目标,我基本上为手臂的每个组件都设置了“肩旋转”,为最后三个组件设置了“肘部旋转”,如您在显示功能和我的“ draw_component”函数。
有人告诉我您可以通过添加2个“旋转”语句(一个用于肩膀,一个用于肘部)来实现相同的功能,而不是像我对每个组件所做的那样。
有什么想法可以做到吗?
答案 0 :(得分:2)
请注意,自glBegin
/ glEnd
序列开始绘制以来,已经过了几年。
阅读有关Fixed Function Pipeline的信息,并参阅Vertex Specification和Shader了解最新的渲染方式。
但是,如果要这样做,则可以通过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();
}
预览:
在这种情况下,glScalef
(enlarge
)操作仅需要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