一、简介
此OpenGL 程序使用 GLUT 库创建了一个可交互的三维机器人模型,支持关节角度调整和视角控制。
-
层次化建模:通过圆柱体和球体组合构建机器人,包括躯干、头部、四肢等 11 个可独立控制的关节。
-
材质与光照:为不同部件设置了差异化的材质属性,并启用了光源以增强场景真实感。
-
交互控制:
- 鼠标:左键 / 右键旋转选中的关节
- 键盘:WASDQE 控制相机视角和距离
- 菜单:中键点击可选择要控制的关节
-
坐标系统:使用极坐标实现相机环绕观察,支持多角度查看机器人姿态。
二、环境
- 开发语言:C++
- 图形库:OpenGL(通过 GLUT 工具包实现窗口管理)
- 编译环境:VC++6.0
三、原理
1. 三维建模基础
- 几何图元 :使用
gluCylinder
(圆柱体)和gluSphere
(球体)构建机器人各部位(躯干、四肢、头部)。 - 坐标变换 :通过
glTranslatef
(平移)、glRotatef
(旋转)和glScalef
(缩放)实现部件的位置与姿态调整,构建层次化模型结构。
2. 交互式控制
-
鼠标交互 :左键 / 右键点击调整指定关节角度(通过
theta
数组控制各关节旋转量)。 -
键盘交互:
W/S
:调整相机距离(camera_distance
);A/D
:调整相机水平角度(camera_angle
);Q/E
:调整相机高度(camera_height
)。
-
菜单系统:通过中键菜单选择可操作关节(0-10 对应不同部位,11 为退出)。
3. 光照与材质
- 光照设置 :启用 GL_LIGHT0 光源,通过
glLightfv
设置位置和颜色(环境光、漫反射光、镜面光)。 - 材质属性 :为各部件设置不同的
ambient
(环境色)、diffuse
(漫反射色)、specular
(镜面反射色)和shininess
(光泽度),增强视觉区分度(如躯干为银色金属,头部为白色,四肢为灰 / 深灰色)。
代码
一、整体架构
本代码基于 OpenGL 和 GLUT 库实现了一个可交互的三维机器人模型,采用模块化设计,主要分为以下功能模块:
-
常量定义与全局变量:设置机器人各部位尺寸和初始状态
-
材质与场景设置:配置光照、地面和默认材质
-
部件绘制函数:定义机器人各部位的几何形状和材质
-
机器人组装:通过坐标变换组合各部件,构建层次化模型
-
交互控制:实现鼠标、键盘和菜单的输入响应
-
主程序:初始化 GLUT 环境并启动渲染循环
下面对各模块进行详细分析:
二、常量定义与全局变量
arduino
// --------------------- 尺寸宏定义调整 ---------------------
#define TORSO_HEIGHT 4.0 // 躯干高度
#define UPPER_ARM_HEIGHT 1.5 // 上臂高度
#define LOWER_ARM_HEIGHT 1.0 // 下臂高度
#define UPPER_LEG_RADIUS 0.3 // 大腿半径
#define LOWER_LEG_RADIUS 0.3 // 小腿半径
#define LOWER_LEG_HEIGHT 1.5 // 小腿高度
#define UPPER_LEG_HEIGHT 2.0 // 大腿高度
#define TORSO_RADIUS 2.0 // 躯干半径
#define UPPER_ARM_RADIUS 0.3 // 上臂半径
#define LOWER_ARM_RADIUS 0.3 // 下臂半径
#define HEAD_HEIGHT 1.5 // 头部高度
#define HEAD_RADIUS 1.0 // 头部半径
typedef float point[3];
static GLfloat theta[11] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,
180.0,0.0,180.0,0.0}; /* 关节角度数组 */
static GLint angle = 2; /* 当前控制的关节索引 */
static GLfloat camera_angle = 0.0; /* 相机水平角度 */
static GLfloat camera_distance = 20.0; /* 相机距离 */
static GLfloat camera_height = 5.0; /* 相机高度 */
分析:
- 使用宏定义统一管理机器人各部位尺寸,便于后续调整比例
theta
数组存储 11 个关节的旋转角度,索引对应不同身体部位- 相机参数采用极坐标表示,便于实现环绕观察效果
- 二次曲面对象指针用于创建平滑的圆柱体和球体
三、材质与场景设置
scss
// 设置材质辅助函数
void set_material(GLfloat ambient[], GLfloat diffuse[],
GLfloat specular[], GLfloat shininess)
{
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialf(GL_FRONT, GL_SHININESS, shininess);
}
// 绘制地面
void draw_ground()
{
// 设置地面材质
GLfloat ground_ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat ground_diffuse[] = {0.95, 0.95, 0.95, 1.0};
GLfloat ground_specular[] = {0.2, 0.2, 0.2, 1.0};
GLfloat ground_shininess = 20.0;
set_material(ground_ambient, ground_diffuse, ground_specular, ground_shininess);
glPushMatrix();
glBegin(GL_QUADS);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(-20.0, -8, -20.0);
glVertex3f(20.0, -8, -20.0);
glVertex3f(20.0, -8, 20.0);
glVertex3f(-20.0, -8, 20.0);
glEnd();
// 绘制网格线
glLineWidth(1.0);
glColor3f(0.4, 0.4, 0.4);
glBegin(GL_LINES);
// 横向线
for (int i = -20; i <= 20; i += 2) {
glVertex3f(-20.0, -8 + 0.01, i);
glVertex3f(20.0, -8 + 0.01, i);
}
// 纵向线
for (int j = -20; j <= 20; j += 2) {
glVertex3f(j, -8 + 0.01, -20.0);
glVertex3f(j, -8 + 0.01, 20.0);
}
glEnd();
glPopMatrix();
}
分析:
set_material
函数封装了材质设置流程,提高代码复用性- 地面采用大尺寸四边形配合网格线增强空间感
- 材质参数通过 RGB 值和光泽度控制,不同部件使用差异化设置(如躯干为银色金属质感,头部为橙色)
四、部件绘制函数
scss
// 绘制机器人躯干
void torso()
{
// 设置躯干材质
GLfloat torso_ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat torso_diffuse[] = {0.65, 0.33, 0.16, 1.0};
GLfloat torso_specular[] = {0.9, 0.9, 0.9, 1.0};
GLfloat torso_shininess = 100.0;
set_material(torso_ambient, torso_diffuse, torso_specular, torso_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(t, TORSO_RADIUS, TORSO_RADIUS, TORSO_HEIGHT, 30, 30);
glPopMatrix();
}
// 绘制机器人头部
void head()
{
// 设置头部材质
GLfloat head_ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat head_diffuse[] = {1.0, 0.5, 0.0, 1.0};
GLfloat head_specular[] = {0.9, 0.9, 0.9, 1.0};
GLfloat head_shininess = 80.0;
set_material(head_ambient, head_diffuse, head_specular, head_shininess);
glPushMatrix();
glTranslatef(0.0, 0.5*HEAD_HEIGHT, 0.0);
glScalef(HEAD_RADIUS, HEAD_HEIGHT, HEAD_RADIUS);
gluSphere(h, 1.0, 30, 30);
glPopMatrix();
// 绘制眼睛
GLfloat eye_ambient[] = {0.0, 0.0, 0.0, 1.0};
GLfloat eye_diffuse[] = {0.0, 0.0, 0.0, 1.0};
GLfloat eye_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat eye_shininess = 100.0;
set_material(eye_ambient, eye_diffuse, eye_specular, eye_shininess);
glPushMatrix();
glTranslatef(0.0, HEAD_HEIGHT * 0.8, 0.0);
// 左眼
glPushMatrix();
glTranslatef(-0.6, 0.0, 0.8);
gluSphere(h, 0.15, 20, 20);
glPopMatrix();
// 右眼
glPushMatrix();
glTranslatef(0.6, 0.0, 0.8);
gluSphere(h, 0.15, 20, 20);
glPopMatrix();
glPopMatrix();
}
// 绘制机器人左上臂
void left_upper_arm()
{
// 设置左上臂材质
GLfloat arm_ambient[] = {0.1, 0.1, 0.1, 1.0};
GLfloat arm_diffuse[] = {1.0, 0.75, 0.4, 1.0};
GLfloat arm_specular[] = {0.8, 0.8, 0.8, 1.0};
GLfloat arm_shininess = 90.0;
set_material(arm_ambient, arm_diffuse, arm_specular, arm_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lua, UPPER_ARM_RADIUS, UPPER_ARM_RADIUS, UPPER_ARM_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人左下臂
void left_lower_arm()
{
// 设置左下臂材质
GLfloat arm_ambient[] = {0.1, 0.1, 0.1, 1.0};
GLfloat arm_diffuse[] = {1.0, 1.0, 0.0, 1.0};
GLfloat arm_specular[] = {0.8, 0.8, 0.8, 1.0};
GLfloat arm_shininess = 90.0;
set_material(arm_ambient, arm_diffuse, arm_specular, arm_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lla, LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人右上臂
void right_upper_arm()
{
// 设置右上臂材质
GLfloat arm_ambient[] = {0.1, 0.1, 0.1, 1.0};
GLfloat arm_diffuse[] = {1.0, 0.75, 0.4, 1.0};
GLfloat arm_specular[] = {0.8, 0.8, 0.8, 1.0};
GLfloat arm_shininess = 90.0;
set_material(arm_ambient, arm_diffuse, arm_specular, arm_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rua, UPPER_ARM_RADIUS, UPPER_ARM_RADIUS, UPPER_ARM_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人右下臂
void right_lower_arm()
{
// 设置右下臂材质 - 灰色
GLfloat arm_ambient[] = {0.1, 0.1, 0.1, 1.0};
GLfloat arm_diffuse[] = {1.0, 1.0, 0.0, 1.0};
GLfloat arm_specular[] = {0.8, 0.8, 0.8, 1.0};
GLfloat arm_shininess = 90.0;
set_material(arm_ambient, arm_diffuse, arm_specular, arm_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rla, LOWER_ARM_RADIUS, LOWER_ARM_RADIUS, LOWER_ARM_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人左大腿
void left_upper_leg()
{
// 设置左大腿材质
GLfloat leg_ambient[] = {0.05, 0.05, 0.05, 1.0};
GLfloat leg_diffuse[] = {1.0, 0.75, 0.4, 1.0};
GLfloat leg_specular[] = {0.7, 0.7, 0.7, 1.0};
GLfloat leg_shininess = 90.0;
set_material(leg_ambient, leg_diffuse, leg_specular, leg_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lul, UPPER_LEG_RADIUS, UPPER_LEG_RADIUS, UPPER_LEG_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人左小腿
void left_lower_leg()
{
// 设置左小腿材质
GLfloat leg_ambient[] = {0.05, 0.05, 0.05, 1.0};
GLfloat leg_diffuse[] = {1.0, 1.0, 0.0, 1.0};
GLfloat leg_specular[] = {0.7, 0.7, 0.7, 1.0};
GLfloat leg_shininess = 90.0;
set_material(leg_ambient, leg_diffuse, leg_specular, leg_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(lll, LOWER_LEG_RADIUS, LOWER_LEG_RADIUS, LOWER_LEG_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人右大腿
void right_upper_leg()
{
// 设置右大腿材质
GLfloat leg_ambient[] = {0.05, 0.05, 0.05, 1.0};
GLfloat leg_diffuse[] = {1.0, 0.75, 0.4, 1.0};
GLfloat leg_specular[] = {0.7, 0.7, 0.7, 1.0};
GLfloat leg_shininess = 90.0;
set_material(leg_ambient, leg_diffuse, leg_specular, leg_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rul, UPPER_LEG_RADIUS, UPPER_LEG_RADIUS, UPPER_LEG_HEIGHT, 20, 20);
glPopMatrix();
}
// 绘制机器人右小腿
void right_lower_leg()
{
// 设置右小腿材质
GLfloat leg_ambient[] = {0.05, 0.05, 0.05, 1.0};
GLfloat leg_diffuse[] = {1.0, 1.0, 0.0, 1.0};
GLfloat leg_specular[] = {0.7, 0.7, 0.7, 1.0};
GLfloat leg_shininess = 90.0;
set_material(leg_ambient, leg_diffuse, leg_specular, leg_shininess);
glPushMatrix();
glRotatef(-90.0, 1.0, 0.0, 0.0);
gluCylinder(rll, LOWER_LEG_RADIUS, LOWER_LEG_RADIUS, LOWER_LEG_HEIGHT, 20, 20);
glPopMatrix();
}
分析:
- 每个部件函数遵循 "材质设置→坐标变换→几何绘制" 的流程
- 使用
glPushMatrix()
和glPopMatrix()
保护当前变换状态,确保各部件变换独立 - 圆柱体默认沿 Y 轴方向,通过旋转使其沿 Z 轴(竖直方向)
- 头部函数包含了子部件(眼睛)的绘制,展示了层次化建模思想
五、机器人组装
scss
// 绘制机器人
void draw_robot()
{
glPushMatrix();
// 躯干变换与绘制
glRotatef(theta[0], 0.0, 1.0, 0.0);
torso();
// 头部变换与绘制
glPushMatrix();
glTranslatef(0.0, TORSO_HEIGHT + 0.5*HEAD_HEIGHT, 0.0);
glRotatef(theta[1], 1.0, 0.0, 0.0);
glRotatef(theta[2], 0.0, 1.0, 0.0);
glTranslatef(0.0, -0.5*HEAD_HEIGHT, 0.0);
head();
glPopMatrix();
// 左臂变换与绘制
glPushMatrix();
glTranslatef(-(TORSO_RADIUS + UPPER_ARM_RADIUS), 0.9*TORSO_HEIGHT, 0.0);
glRotatef(theta[3], 1.0, 0.0, 0.0);
left_upper_arm();
glTranslatef(0.0, UPPER_ARM_HEIGHT, 0.0);
glRotatef(theta[4], 1.0, 0.0, 0.0);
left_lower_arm();
glPopMatrix();
// 右臂变换与绘制
glPushMatrix();
glTranslatef(TORSO_RADIUS + UPPER_ARM_RADIUS, 0.9*TORSO_HEIGHT, 0.0);
glRotatef(theta[5], 1.0, 0.0, 0.0);
right_upper_arm();
glTranslatef(0.0, UPPER_ARM_HEIGHT, 0.0);
glRotatef(theta[6], 1.0, 0.0, 0.0);
right_lower_arm();
glPopMatrix();
// 左腿变换与绘制
glPushMatrix();
glTranslatef(-(TORSO_RADIUS + UPPER_LEG_RADIUS), 0.1*UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[7], 1.0, 0.0, 0.0);
left_upper_leg();
glTranslatef(0.0, UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[8], 1.0, 0.0, 0.0);
left_lower_leg();
glPopMatrix();
// 右腿变换与绘制
glPushMatrix();
glTranslatef(TORSO_RADIUS + UPPER_LEG_RADIUS, 0.1*UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[9], 1.0, 0.0, 0.0);
right_upper_leg();
glTranslatef(0.0, UPPER_LEG_HEIGHT, 0.0);
glRotatef(theta[10], 1.0, 0.0, 0.0);
right_lower_leg();
glPopMatrix();
glPopMatrix();
}
分析:
- 采用层次化坐标变换:先整体变换(如躯干旋转),再局部变换(如四肢位置)
- 关节角度通过
theta
数组动态控制,实现各部位独立运动 - 子部件的位置基于父部件的坐标系,形成树形结构(如手臂相对于躯干的位置)
- 变换顺序严格遵循 "平移→旋转" 原则,确保旋转中心正确
六、交互控制
scss
// 显示函数
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
// 设置相机位置
GLfloat eye_x = camera_distance * sin(camera_angle);
GLfloat eye_z = camera_distance * cos(camera_angle);
gluLookAt(eye_x, camera_height, eye_z, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
// 设置光照位置
GLfloat light_position[] = {10.0, 8.0, 10.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
// 绘制地面
draw_ground();
// 绘制机器人
draw_robot();
glutSwapBuffers();
}
// 鼠标控制函数
void mouse(int btn, int state, int x, int y)
{
if(btn == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
theta[angle] += 5.0; // 左键增加角度
if(theta[angle] > 360.0) theta[angle] -= 360.0;
}
if(btn == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
theta[angle] -= 5.0; // 右键减少角度
if(theta[angle] < 0.0) theta[angle] += 360.0;
}
display(); // 触发重绘
}
// 键盘控制函数
void keyboard(unsigned char key, int x, int y)
{
switch (key) {
case 'a':
camera_angle -= 0.1;
break;
case 'd':
camera_angle += 0.1;
break;
case 'w':
camera_distance -= 0.5;
if (camera_distance < 5.0) camera_distance = 5.0;
break;
case 's':
camera_distance += 0.5;
if (camera_distance > 30.0) camera_distance = 30.0;
break;
case 'q':
camera_height += 0.2;
break;
case 'e':
camera_height -= 0.2;
if (camera_height < 1.0) camera_height = 1.0;
break;
case 27: // ESC键退出
exit(0);
break;
}
display(); // 触发重绘
}
// 菜单函数
void menu(int id)
{
if(id < 11) angle = id; // 选择关节
if(id == 11) exit(0); // 退出程序
}
// 窗口大小改变回调函数
void myReshape(int w, int h)
{
if (h == 0) h = 1;
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
分析:
- 鼠标控制:通过左右键调整当前选中关节的角度
- 键盘控制:实现相机的六自由度移动(前后、左右、上下)
- 菜单系统:通过中键菜单切换当前控制的关节
- 所有交互操作最终调用
display()
函数触发场景重绘
七、主程序与初始化
运行
scss
// 初始化函数
void myinit()
{
// 设置光源属性
GLfloat light_ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat light_position[] = {10.0, 10.0, 10.0, 0.0};
glLightfv(GL_LIGHT0, GL_POSITION, light_position);
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
// 启用光照和深度测试
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
// 设置默认材质属性
GLfloat default_ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat default_diffuse[] = {0.8, 0.8, 0.8, 1.0};
GLfloat default_specular[] = {0.9, 0.9, 0.9, 1.0};
GLfloat default_shininess = 100.0;
glMaterialfv(GL_FRONT, GL_AMBIENT, default_ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, default_diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, default_specular);
glMaterialf(GL_FRONT, GL_SHININESS, default_shininess);
// 清除颜色和深度缓冲区
glClearColor(1.0, 1.0, 0.9, 1.0);
// 创建二次曲面对象
h = gluNewQuadric();
gluQuadricDrawStyle(h, GLU_FILL);
gluQuadricNormals(h, GLU_SMOOTH);
t = gluNewQuadric();
gluQuadricDrawStyle(t, GLU_FILL);
gluQuadricNormals(t, GLU_SMOOTH);
lua = gluNewQuadric();
gluQuadricDrawStyle(lua, GLU_FILL);
gluQuadricNormals(lua, GLU_SMOOTH);
lla = gluNewQuadric();
gluQuadricDrawStyle(lla, GLU_FILL);
gluQuadricNormals(lla, GLU_SMOOTH);
rua = gluNewQuadric();
gluQuadricDrawStyle(rua, GLU_FILL);
gluQuadricNormals(rua, GLU_SMOOTH);
rla = gluNewQuadric();
gluQuadricDrawStyle(rla, GLU_FILL);
gluQuadricNormals(rla, GLU_SMOOTH);
lul = gluNewQuadric();
gluQuadricDrawStyle(lul, GLU_FILL);
gluQuadricNormals(lul, GLU_SMOOTH);
lll = gluNewQuadric();
gluQuadricDrawStyle(lll, GLU_FILL);
gluQuadricNormals(lll, GLU_SMOOTH);
rul = gluNewQuadric();
gluQuadricDrawStyle(rul, GLU_FILL);
gluQuadricNormals(rul, GLU_SMOOTH);
rll = gluNewQuadric();
gluQuadricDrawStyle(rll, GLU_FILL);
gluQuadricNormals(rll, GLU_SMOOTH);
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(800, 600);
glutCreateWindow("简化版机器人三维场景");
myinit();
// 设置回调函数
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
// 创建菜单
glutCreateMenu(menu);
glutAddMenuEntry("躯干", 0);
glutAddMenuEntry("头部1", 1);
glutAddMenuEntry("头部2", 2);
glutAddMenuEntry("左上臂", 3);
glutAddMenuEntry("左前臂", 4);
glutAddMenuEntry("右上臂", 5);
glutAddMenuEntry("右前臂", 6);
glutAddMenuEntry("左大腿", 7);
glutAddMenuEntry("左小腿", 8);
glutAddMenuEntry("右大腿", 9);
glutAddMenuEntry("右小腿", 10);
glutAddMenuEntry("退出", 11);
glutAttachMenu(GLUT_MIDDLE_BUTTON);
glutMainLoop();
return 0;
}
分析:
- 初始化流程:GLUT 环境设置→自定义初始化→回调函数注册→进入主循环
- 双缓冲模式(
GLUT_DOUBLE
)避免画面闪烁 - 深度测试(
GL_DEPTH_TEST
)确保正确的遮挡关系 - 回调函数机制实现事件驱动的渲染流程
效果展示
点击鼠标中键出现菜单,鼠标左键和右键控制旋转,awds键控制视角。
调整角度及各个关节后的效果:
