由于接下来的实验要实现火柴人的动作,所以实验要求要采用分层设计,如下图所示:
这样转动hip(臀部),整个火柴人就整体转动。比如如果要动左腿,那么在相对hip上进行自己的操作,这样设计对火柴人的动作实现很方便。
贴上自己的代码,程序用递归来实现分层设计,此外还增添了火柴人旋转功能:
#define _STDCALL_SUPPORTED
#include <GL/glut.h>
GLUquadricObj *uquadric; //二次曲面声明类型
void drawTorso();
void drawLeftleg1();
void drawRightleg1();
void drawLeftarm1();
void drawLefttarm2();
void drawRightarm1();
void drawRightarm2();
void drawNeck();
void drawHead();
void selfRotateRL1();
//画臀部,根节点
void drawHip(){
glScalef(2.0,0.5,1.0);
glPushMatrix();
glTranslatef(0.0,-1.0,0.0);
glutWireCube(0.3);
drawTorso();
drawLeftleg1();
drawRightleg1();
glPopMatrix();
}
//画肩膀
void drawShoulder(){
glScalef(2.0,0.5,2.0); //先还原成1:1
glScalef(2.0,0.5,1.0);
glPushMatrix();
glTranslatef(0.0,1.45,0.0);
glutWireCube(0.4);
drawRightarm1();
drawLeftarm1();
drawNeck();
drawHead();
glPopMatrix();
}
//画躯干
void drawTorso(){
glScalef(0.5,2.0,1.0); //先还原成1:1
glScalef(0.5,2.0,0.5); //躯干Z轴方向缩短一半,不然躯干太粗
glPushMatrix();
glTranslatef(0.0,0.35,0.0);
glutWireCube(0.6);
drawShoulder();
glPopMatrix();
}
void drawRightarm2(){
glPushMatrix();
//差点忘记了,arm1是绕x轴旋转了90度,所以三维坐标也跟着旋转了90度
//这里第二个是“z轴”,负的往里,正的往外
//第三个是“y轴”,负的网上,正的往下
glTranslatef(0.0,0.0,0.7);
glRotatef(15,0.0,-1.0,0.0);
gluCylinder(uquadric, 0.08, 0.08, 0.6, 20.0, 8.0);
glPopMatrix();
}
void drawRightarm1(){
glScalef(0.5,2.0,1.0); //还原成1:1
glPushMatrix();
//gluQuadricDrawStyle(uquadric, GLU_FILL); //控制绘图风格
glTranslatef(-0.3,-0.05,0.0);
glRotatef(90,1.0,0.0,0.0);
gluCylinder(uquadric, 0.08, 0.08, 0.7, 20.0, 8.0);
drawRightarm2();
glPopMatrix();
}
void drawLeftarm2(){
glPushMatrix();
glTranslatef(0.0,0.0,0.7);
glRotatef(15,0.0,1.0,0.0);
gluCylinder(uquadric, 0.08, 0.08, 0.6, 20.0, 8.0);
glPopMatrix();
}
void drawLeftarm1(){
glPushMatrix();
glTranslatef(0.3,-0.05,0.0);
glRotatef(90,1.0,0.0,0.0);
gluCylinder(uquadric, 0.08, 0.08, 0.7, 20.0, 8.0);
drawLeftarm2();
glPopMatrix();
}
//画头
void drawHead(){
glPushMatrix();
glTranslatef(0.0,0.65,0.0);
glutWireCube(0.40);
glPopMatrix();
}
//画脖子
void drawNeck(){
glPushMatrix();
glTranslatef(0.0,0.40,0.0);
glRotatef(90,1.0,0.0,0.0);
gluCylinder(uquadric, 0.10, 0.10, 0.30, 20.0, 8.0);
glPopMatrix();
}
void drawRightLeg2(){
glPushMatrix();
glTranslatef(0.0,0.0,0.8);
//glRotatef(10,0.0,-1.0,0.0);
gluCylinder(uquadric, 0.1, 0.1, 0.8, 20.0, 8.0);
glPopMatrix();
}
void drawRightleg1(){
//glScalef(2.0,0.5,1.0); //先还原成1:1
glPushMatrix();
glTranslatef(0.20,-0.05,0.0);
//注意这里坐标轴绕x旋转了90度,leg2的坐标会变化
glRotatef(90,1.0,0.0,0.0);
gluCylinder(uquadric, 0.1, 0.1, 0.8, 20.0, 8.0);
drawRightLeg2();
glPopMatrix();
}
void drawLeftLeg2(){
glPushMatrix();
glTranslatef(0.0,0.0,0.8);
//glRotatef(10,0.0,-1.0,0.0);
gluCylinder(uquadric, 0.1, 0.1, 0.8, 20.0, 8.0);
glPopMatrix();
}
void drawLeftleg1(){
glScalef(2.0,0.5,1.0); //先还原成1:1
glPushMatrix();
glTranslatef(-0.20,-0.05,0.0);
//注意这里坐标轴绕x旋转了90度,leg2的坐标会变化
glRotatef(90,1.0,0.0,0.0);
gluCylinder(uquadric, 0.1, 0.1, 0.8, 20.0, 8.0);
drawLeftLeg2();
glPopMatrix();
}
static float rotateAngle = 0;
static int times1 = 0;
void selfRotateWhole(){
times1++;
if(times1 > 50)
{
times1 = 0;
}
if(times1 % 50 == 0)
{
rotateAngle += 0.5;
}
glRotatef(rotateAngle, 0, 1, 0);
glRotatef(rotateAngle, 1, 0, 0);
}
//自由旋转转动
void renderScene()
{
glClear(GL_COLOR_BUFFER_BIT); //清除当前可写的颜色缓冲
glColor3f(1.0,0.0,0.0);
glLoadIdentity();
gluLookAt(0.0,0.0,0.0,0.0,0.0,-1.0,0.0,1.0,0.0);
glLoadIdentity();
/*
glMatrixMode设置当前矩阵模式:
GL_MODELVIEW,对模型视景矩阵堆栈应用随后的矩阵操作.
GL_PROJECTION,对投影矩阵应用随后的矩阵操作.
GL_TEXTURE,对纹理矩阵堆栈应用随后的矩阵操作.
与glLoadIdentity()一同使用
*/
glMatrixMode(GL_MODELVIEW);
glScalef(0.5,0.5,1.0); //先缩放下,不然木头人会很大。。。
glPushMatrix();
selfRotateWhole();
drawHip();
glPopMatrix();
glFlush();
//glutSwapBuffers();
}
void init(){
glClearColor(0.0,0.0,0.0,0.0); //glClearColor(R,G,B,AFA)清空当前颜色,并且设定颜色值
glShadeModel(GL_FLAT); //设置着色模式。
uquadric = gluNewQuadric();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
/*
GLUT_RGB:指定 RGB 颜色模式的窗口
GLUT_SINGLE:指定单缓存窗口
*/
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowPosition(100, 100);
glutInitWindowSize(500, 500);
glutCreateWindow("太空漂浮");
init();
//glutDisplayFunc(display);
glutDisplayFunc(renderScene);
glutIdleFunc(renderScene);
//glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
附上几张运行图片: