【实验目的】
1. 掌握三维物体的显示方法。
2. 掌握投影变换和照相机位置及方向的设置方法。
3. 掌握几何变换的方法。
【实验原理】
【实验内容】
阅读arraycube.c,掌握彩色立方体的建模方法,为程序加注释
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
// 顶点坐标
GLdouble vertices[8][3] =
{ {-1.0, -1.0, 1.0},
{-1.0,1.0,1.0},
{1.0,1.0,1.0},
{1.0,-1.0,1.0},{-1.0,-1.0,-1.0},
{-1.0,1.0,-1.0}, {1.0,1.0,-1.0}, {1.0,-1.0,-1.0} };
// 颜色值
GLdouble colors[8][3] = { {0.0,0.0,0.0}, {1.0,0.0,0.0},
{1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0} };
// 绘制一个四边形,分别设置顶点坐标和颜色
void polygon(int a, int b, int c, int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_QUADS);
glColor3dv(colors[a]);
glVertex3dv(vertices[a]);
glColor3dv(colors[b]);
glVertex3dv(vertices[b]);
glColor3dv(colors[c]);
glVertex3dv(vertices[c]);
glColor3dv(colors[d]);
glVertex3dv(vertices[d]);
glEnd();
}
// 绘制彩色立方体的面
void colorcube()
{
/* map vertices to faces */
polygon(0, 3, 2, 1);
polygon(2, 3, 7, 6);
polygon(0, 4, 7, 3);
polygon(1, 2, 6, 5);
polygon(4, 5, 6, 7);
polygon(0, 1, 5, 4);
}
// 显示回调函数
void display()
{
/* display callback, clear frame buffer and z buffer,/
and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 清除颜色缓冲区和深度缓冲区
glMatrixMode(GL_MODELVIEW); //设置当前矩阵为模型视图矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
gluLookAt(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);// 设置观察矩阵
colorcube();// 绘制彩色立方体
glutSwapBuffers(); // 交换前后缓冲区
}
// 窗口大小改变回调函数
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);// 设置视口大小
glMatrixMode(GL_PROJECTION);// 设置当前矩阵为投影矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat)h / (GLfloat)w,
2.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0);// 设置正交投影矩阵
else
glOrtho(-2.0 * (GLfloat)w / (GLfloat)h,
2.0 * (GLfloat)w / (GLfloat)h, -2.0, 2.0, -10.0, 10.0);// 设置正交投影矩阵
glMatrixMode(GL_MODELVIEW);// 设置当前矩阵为模型视图矩阵
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);// 初始化glut
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);// 设置显示模式
glutInitWindowSize(500, 500);// 设置窗口大小
glutCreateWindow("colorcube");// 创建窗口
glClearColor(0.0, 0.0, 0.0, 0.0);// 设置清除颜色
//glShadeModel(GL_SMOOTH);
glShadeModel(GL_FLAT);// 设置着色模式
glutReshapeFunc(myReshape);// 注册窗口大小改变回调函数
glutDisplayFunc(display);//注册显示回调函数
//glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glutMainLoop();// 进入glut事件处理循环
}
2. 修改arraycube.c,实现交互式地移动照相机来观察已经建模好的彩色立方体。即用鼠标或键盘来改变gluLookAt(eyex, eyey, eyez, atx, aty, atz, upx, upy, upz)函数的9个参数,以此来观察立方体。要求:
(1)交互时采用的鼠标和键盘按键自定。
(2)分别在正投影和透视投影下实现题目中的功能。
正投影
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
GLfloat eyex = 1.0, eyey = 1.0, eyez = 1.0; // 照相机位置
GLfloat atx = 0.0, aty = 0.0, atz = 0.0; // 观察点位置
GLfloat upx = 0.0, upy = 1.0, upz = 0.0; // 上方向
// 顶点坐标
GLdouble vertices[8][3] =
{ {-1.0, -1.0, 1.0},
{-1.0,1.0,1.0},
{1.0,1.0,1.0},
{1.0,-1.0,1.0},{-1.0,-1.0,-1.0},
{-1.0,1.0,-1.0}, {1.0,1.0,-1.0}, {1.0,-1.0,-1.0} };
// 颜色值
GLdouble colors[8][3] = { {0.0,0.0,0.0}, {1.0,0.0,0.0},
{1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0} };
// 绘制一个四边形,分别设置顶点坐标和颜色
void polygon(int a, int b, int c, int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_QUADS);
glColor3dv(colors[a]);
glVertex3dv(vertices[a]);
glColor3dv(colors[b]);
glVertex3dv(vertices[b]);
glColor3dv(colors[c]);
glVertex3dv(vertices[c]);
glColor3dv(colors[d]);
glVertex3dv(vertices[d]);
glEnd();
}
// 绘制彩色立方体的面
void colorcube()
{
/* map vertices to faces */
polygon(0, 3, 2, 1);
polygon(2, 3, 7, 6);
polygon(0, 4, 7, 3);
polygon(1, 2, 6, 5);
polygon(4, 5, 6, 7);
polygon(0, 1, 5, 4);
}
// 显示回调函数
void display()
{
/* display callback, clear frame buffer and z buffer,/
and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 清除颜色缓冲区和深度缓冲区
glMatrixMode(GL_MODELVIEW); //设置当前矩阵为模型视图矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
gluLookAt(eyex, eyey, eyez, atx, aty, atz, upx, upy, upz);// 设置观察矩阵
colorcube();// 绘制彩色立方体
glutSwapBuffers(); // 交换前后缓冲区
}
// 窗口大小改变回调函数
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);// 设置视口大小
glMatrixMode(GL_PROJECTION);// 设置当前矩阵为投影矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat)h / (GLfloat)w,
2.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0);// 设置正交投影矩阵
else
glOrtho(-2.0 * (GLfloat)w / (GLfloat)h,
2.0 * (GLfloat)w / (GLfloat)h, -2.0, 2.0, -10.0, 10.0);// 设置正交投影矩阵
glMatrixMode(GL_MODELVIEW);// 设置当前矩阵为模型视图矩阵
}
// 键盘事件处理函数
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'w':
eyey += 0.1;
break;
case 's':
eyey -= 0.1;
break;
case 'a':
eyex -= 0.1;
break;
case 'd':
eyex += 0.1;
break;
}
glutPostRedisplay(); // 标记当前窗口需要重新绘制
}
// 鼠标事件处理函数
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
atx = (2.0 * x - 500) / 500.0;
aty = (500 - 2.0 * y) / 500.0;
glutPostRedisplay();
}
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);// 初始化glut
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);// 设置显示模式
glutInitWindowSize(500, 500);// 设置窗口大小
glutCreateWindow("colorcube");// 创建窗口
glClearColor(0.0, 0.0, 0.0, 0.0);// 设置清除颜色
//glShadeModel(GL_SMOOTH);
glShadeModel(GL_FLAT);// 设置着色模式
glEnable(GL_DEPTH_TEST); // 启用深度测试
glutReshapeFunc(myReshape);// 注册窗口大小改变回调函数
glutDisplayFunc(display);//注册显示回调函数
//glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glutKeyboardFunc(keyboard); // 注册键盘事件处理函数
glutMouseFunc(mouse); // 注册鼠标事件处理函数
glutMainLoop();// 进入glut事件处理循环
}
透视投影:
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
GLfloat eyex = 0.0, eyey = 0.0, eyez = 5.0; // 照相机位置
GLfloat atx = 0.0, aty = 0.0, atz = 0.0; // 观察点位置
GLfloat upx = 0.0, upy = 1.0, upz = 0.0; // 上方向
// 顶点坐标
GLdouble vertices[8][3] =
{ {-1.0, -1.0, 1.0},
{-1.0,1.0,1.0},
{1.0,1.0,1.0},
{1.0,-1.0,1.0},{-1.0,-1.0,-1.0},
{-1.0,1.0,-1.0}, {1.0,1.0,-1.0}, {1.0,-1.0,-1.0} };
// 颜色值
GLdouble colors[8][3] = { {0.0,0.0,0.0}, {1.0,0.0,0.0},
{1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0} };
// 绘制一个四边形,分别设置顶点坐标和颜色
void polygon(int a, int b, int c, int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_QUADS);
glColor3dv(colors[a]);
glVertex3dv(vertices[a]);
glColor3dv(colors[b]);
glVertex3dv(vertices[b]);
glColor3dv(colors[c]);
glVertex3dv(vertices[c]);
glColor3dv(colors[d]);
glVertex3dv(vertices[d]);
glEnd();
}
// 绘制彩色立方体的面
void colorcube()
{
/* map vertices to faces */
polygon(0, 3, 2, 1);
polygon(2, 3, 7, 6);
polygon(0, 4, 7, 3);
polygon(1, 2, 6, 5);
polygon(4, 5, 6, 7);
polygon(0, 1, 5, 4);
}
// 显示回调函数
void display()
{
/* display callback, clear frame buffer and z buffer,/
and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 清除颜色缓冲区和深度缓冲区
glMatrixMode(GL_MODELVIEW); //设置当前矩阵为模型视图矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
gluLookAt(eyex, eyey, eyez, atx, aty, atz, upx, upy, upz);// 设置观察矩阵
colorcube();// 绘制彩色立方体
glutSwapBuffers(); // 交换前后缓冲区
}
// 窗口大小改变回调函数
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);// 设置视口大小
glMatrixMode(GL_PROJECTION);// 设置当前矩阵为投影矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
glMatrixMode(GL_MODELVIEW);// 设置当前矩阵为模型视图矩阵
}
// 键盘事件处理函数
void keyboard(unsigned char key, int x, int y)
{
switch (key)
{
case 'w':
eyey += 0.1;
break;
case 's':
eyey -= 0.1;
break;
case 'a':
eyex -= 0.1;
break;
case 'd':
eyex += 0.1;
break;
}
glutPostRedisplay(); // 标记当前窗口需要重新绘制
}
// 鼠标事件处理函数
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
atx = (2.0 * x - 500) / 500.0;
aty = (500 - 2.0 * y) / 500.0;
glutPostRedisplay();
}
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);// 初始化glut
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);// 设置显示模式
glutInitWindowSize(500, 500);// 设置窗口大小
glutCreateWindow("colorcube");// 创建窗口
glClearColor(0.0, 0.0, 0.0, 0.0);// 设置清除颜色
//glShadeModel(GL_SMOOTH);
glShadeModel(GL_FLAT);// 设置着色模式
glEnable(GL_DEPTH_TEST); // 启用深度测试
glutReshapeFunc(myReshape);// 注册窗口大小改变回调函数
glutDisplayFunc(display);//注册显示回调函数
//glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */
glutKeyboardFunc(keyboard); // 注册键盘事件处理函数
glutMouseFunc(mouse); // 注册鼠标事件处理函数
glutMainLoop();// 进入glut事件处理循环
}
3. 在arraycube.c的基础上编写一个交互式程序,实现立方体的旋转。具体要求如下:
(1)立方体的旋转方式由鼠标和键盘按键来控制:按下鼠标左键,立方体绕x轴连续旋转;按下鼠标左键+ctrl键,立方体绕y轴连续旋转;按下鼠标右键,立方体绕z轴连续旋转。(注意:旋转的不动点在原点,正好是立方体的中心。)
#include <stdlib.h>
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
GLfloat angleX = 0.0;
GLfloat angleY = 0.0;
GLfloat angleZ = 0.0;
bool leftButtonPressed = false;
bool ctrlPressed = false;
bool rightButtonPressed = false;
// 顶点坐标
GLdouble vertices[8][3] =
{ {-1.0, -1.0, 1.0},
{-1.0,1.0,1.0},
{1.0,1.0,1.0},
{1.0,-1.0,1.0},{-1.0,-1.0,-1.0},
{-1.0,1.0,-1.0}, {1.0,1.0,-1.0}, {1.0,-1.0,-1.0} };
// 颜色值
GLdouble colors[8][3] = { {0.0,0.0,0.0}, {1.0,0.0,0.0},
{1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0} };
// 绘制一个四边形,分别设置顶点坐标和颜色
void polygon(int a, int b, int c, int d)
{
/* draw a polygon via list of vertices */
glBegin(GL_QUADS);
glColor3dv(colors[a]);
glVertex3dv(vertices[a]);
glColor3dv(colors[b]);
glVertex3dv(vertices[b]);
glColor3dv(colors[c]);
glVertex3dv(vertices[c]);
glColor3dv(colors[d]);
glVertex3dv(vertices[d]);
glEnd();
}
// 绘制彩色立方体的面
void colorcube()
{
/* map vertices to faces */
polygon(0, 3, 2, 1);
polygon(2, 3, 7, 6);
polygon(0, 4, 7, 3);
polygon(1, 2, 6, 5);
polygon(4, 5, 6, 7);
polygon(0, 1, 5, 4);
}
// 显示回调函数
void display()
{
/* display callback, clear frame buffer and z buffer,/
and draw, swap buffers */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// 清除颜色缓冲区和深度缓冲区
glMatrixMode(GL_MODELVIEW); //设置当前矩阵为模型视图矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
gluLookAt(1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);// 设置观察矩阵
glRotatef(angleX, 1.0f, 0.0f, 0.0f);
glRotatef(angleY, 0.0f, 1.0f, 0.0f);
glRotatef(angleZ, 0.0f, 0.0f, 1.0f);
colorcube();// 绘制彩色立方体
glutSwapBuffers(); // 交换前后缓冲区
}
// 窗口大小改变回调函数
void myReshape(int w, int h)
{
glViewport(0, 0, w, h);// 设置视口大小
glMatrixMode(GL_PROJECTION);// 设置当前矩阵为投影矩阵
glLoadIdentity();// 重置当前矩阵为单位矩阵
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat)h / (GLfloat)w,
2.0 * (GLfloat)h / (GLfloat)w, -10.0, 10.0);// 设置正交投影矩阵
else
glOrtho(-2.0 * (GLfloat)w / (GLfloat)h,
2.0 * (GLfloat)w / (GLfloat)h, -2.0, 2.0, -10.0, 10.0);// 设置正交投影矩阵
glMatrixMode(GL_MODELVIEW);// 设置当前矩阵为模型视图矩阵
}
void mouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
leftButtonPressed = (state == GLUT_DOWN);
}
else if (button == GLUT_RIGHT_BUTTON)
{
rightButtonPressed = (state == GLUT_DOWN);
}
// Check if Ctrl key is pressed
ctrlPressed = (glutGetModifiers() ==GLUT_ACTIVE_CTRL);
glutPostRedisplay();
}
void updateRotation(int value)
{
const float rotationSpeed = 0.5f;
if (leftButtonPressed)
{
if (ctrlPressed)
{
angleY += rotationSpeed;
}
else
{
angleX += rotationSpeed;
}
}
if (rightButtonPressed)
{
angleZ += rotationSpeed;
}
glutPostRedisplay();
}
void idle()
{
updateRotation(10);
}
void main(int argc, char** argv)
{
glutInit(&argc, argv);// 初始化glut
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);// 设置显示模式
glutInitWindowSize(500, 500);// 设置窗口大小
glutCreateWindow("colorcube");// 创建窗口
glClearColor(0.0, 0.0, 0.0, 0.0);// 设置清除颜色
//glShadeModel(GL_SMOOTH);
glShadeModel(GL_FLAT);// 设置着色模式
glutReshapeFunc(myReshape);// 注册窗口大小改变回调函数
glutDisplayFunc(display);//注册显示回调函数
glutMouseFunc(mouse); // 注册鼠标事件处理函数
glutIdleFunc(idle);
glEnable(GL_DEPTH_TEST);
glutMainLoop();// 进入glut事件处理循环
}
- 如果旋转的不动点不在原点,而改为点P(1,1,1),如何实现立方体绕3个坐标轴的旋转?
要实现立方体围绕点P(1,1,1)绕三个坐标轴的旋转,可以采取以下步骤:
将立方体平移到点P(1,1,1)处。这可以通过将每个顶点的坐标减去(1,1,1)来实现。
执行旋转操作。对于围绕X轴的旋转,使用glRotatef(angleX, 1.0f, 0.0f, 0.0f);对于围绕Y轴的旋转,使用glRotatef(angleY, 0.0f, 1.0f, 0.0f);对于围绕Z轴的旋转,使用glRotatef(angleZ, 0.0f, 0.0f, 1.0f)。
将立方体平移回原来的位置。这可以通过将每个顶点的坐标加上(1,1,1)来实现。
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(5.0, 5.0, 5.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0);
glTranslatef(1.0f, 1.0f, 1.0f); // 平移到点P(1,1,1)
glRotatef(angleX, 1.0f, 0.0f, 0.0f); // 绕X轴旋转
glRotatef(angleY, 0.0f, 1.0f, 0.0f); // 绕Y轴旋转
glRotatef(angleZ, 0.0f, 0.0f, 1.0f); // 绕Z轴旋转
glTranslatef(-1.0f, -1.0f, -1.0f); // 平移回原来的位置
colorcube();
glutSwapBuffers();
}
(3)如果要求每按下一次鼠标按键或键盘按键,立方体旋转的角度增加5度,应如何修改程序?
在全局变量中定义表示角度增量的变量,例如float rotationSpeed= 5.0f;。
在updateRotation函数中,并且将旋转角度的增量改为rotationSpeed。
void updateRotation(int value)
{
if (leftButtonPressed)
{
if (ctrlPressed)
{
angleY += rotationSpeed;
}
else
{
angleX += rotationSpeed;
}
}
if (rightButtonPressed)
{
angleZ += rotationSpeed;
}
glutPostRedisplay();