一、实验目的:
1) 三维物体的构建;
2) 三视图的生成
二、实验内容
共有三道题目。请根据给定的实验结果样例,结合参考程序设计程序,实现样例的显示效果,把程序代码和实验截图拷贝到实验报告中。
注意:每张图的名字要设置为“图例名+姓名”。
题目 1:
设计程序在三维空间绘制立方体。
1) 生成一个正方体,每个面的颜色不同;
2) 可以通过键盘操作,实现三维观察;
效果:
代码:
#include <GL/glut.h>
#include <math.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#define PI 3.1416
GLfloat xRot = 0;
GLfloat yRot = 0;
GLfloat zRot = 0;
void Init(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 0.0f);
// 把着色模式设置为单调着色
glShadeModel(GL_FLAT); //glShadeModel(GL_SMOOTH);
// 把顺时针环绕的多边形设为正面,这与默认是相反的
glFrontFace(GL_CW);
glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP)
xRot -= 5.0f;
if (key == GLUT_KEY_DOWN)
xRot += 5.0f;
if (key == GLUT_KEY_LEFT)
yRot -= 5.0f;
if (key == GLUT_KEY_RIGHT)
yRot += 5.0f;
if (key > 356.0f)
xRot = 0.0f;
if (key < -1.0f)
xRot = 355.0f;
if (key > 356.0f)
yRot = 0.0f;
if (key < -1.0f)
yRot = 355.0f;
if (key == GLUT_KEY_F1) //绕着 z 轴旋转
zRot += 5.0f;
// 使用新的坐标重新绘制场景
glutPostRedisplay();
}
void RenderScene()
{
// 存储坐标和角度
GLfloat x, y, z, angle, x1, y1;
// 用于三角形颜色的交替设置
int iPivot = 1;
// 用默认颜色设置背景色,并清除深度缓冲区(必须的,因为 3D 空间有视景深度)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//打开剔除功能(背面剔除,它用于消除一个表面的背面)
//glEnable(GL_CULL_FACE);
// 打开深度测试,如果不打开深度测试,3D 锥体的显示就会与现实情况不符合
glEnable(GL_DEPTH_TEST);
// 保存矩阵状态并旋转
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
//立方体正面
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0f, 1.0f, 1.0f);
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();
//立方体后面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.5f, 1.0f, 0.5f);
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();
//立方体左面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.3f, 0.3f, 0.8f);
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();
//立方体右面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.8f, 0.3f, 0.3f);
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();
//立方体上面
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0f, 1.0f, 0.0f);
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();
//立方体下面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0f, 1.0f, 1.0f);
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();
glPopMatrix();
glutSwapBuffers();
}
int main(int argv, char* argc[]) {
glutInit(&argv, argc);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(400, 400);
glutInitWindowPosition(400, 300);
glutCreateWindow("三维空间绘制立方体 陈彬彬 ");
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
Init();
glutMainLoop();
}
题目 2:
设计程序在三维空间绘制三棱柱。
1) 生成一个三棱柱;
2) 可以通过键盘操作,实现三维观察;
效果:
代码:
#include <GL/glut.h>
#include <math.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#define PI 3.1416
GLfloat xRot = 0;
GLfloat yRot = 0;
GLfloat zRot = 0;
void Init(void)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glColor3f(1.0f, 1.0f, 0.0f);
// 把着色模式设置为单调着色
glShadeModel(GL_FLAT); //glShadeModel(GL_SMOOTH);
// 把顺时针环绕的多边形设为正面,这与默认是相反的
glFrontFace(GL_CW);
glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
}
void SpecialKeys(int key, int x, int y)
{
if (key == GLUT_KEY_UP)
xRot -= 5.0f;
if (key == GLUT_KEY_DOWN)
xRot += 5.0f;
if (key == GLUT_KEY_LEFT)
yRot -= 5.0f;
if (key == GLUT_KEY_RIGHT)
yRot += 5.0f;
if (key > 356.0f)
xRot = 0.0f;
if (key < -1.0f)
xRot = 355.0f;
if (key > 356.0f)
yRot = 0.0f;
if (key < -1.0f)
yRot = 355.0f;
if (key == GLUT_KEY_F1) //绕着 z 轴旋转
zRot += 5.0f;
// 使用新的坐标重新绘制场景
glutPostRedisplay();
}
void RenderScene()
{
// 存储坐标和角度
GLfloat x, y, z, angle, x1, y1;
// 用于三角形颜色的交替设置
int iPivot = 1;
// 用默认颜色设置背景色,并清除深度缓冲区(必须的,因为 3D 空间有视景深度)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//打开剔除功能(背面剔除,它用于消除一个表面的背面)
//glEnable(GL_CULL_FACE);
// 打开深度测试,如果不打开深度测试,3D 锥体的显示就会与现实情况不符合
glEnable(GL_DEPTH_TEST);
// 保存矩阵状态并旋转
glPushMatrix();
glRotatef(xRot, 1.0f, 0.0f, 0.0f);
glRotatef(yRot, 0.0f, 1.0f, 0.0f);
glRotatef(zRot, 0.0f, 0.0f, 1.0f);
//三棱柱正面
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0, 1.0, 1.0);
glVertex3f(0.0, 0.0, 0.5); //左上角
glVertex3f(-0.5, -0.5, 0.5); //左下角
glVertex3f(-0.5, -0.5, 0.5); //右上角
glVertex3f(0.5, -0.5, 0.5); //右下角
glEnd();
//三棱柱后面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.5, 1.0, 0.5);
glVertex3f(-0.5, -0.5, -0.5); //后面的右下角
glVertex3f(0.5, -0.5, -0.5); //后面的左下角
glVertex3f(0.0, 0.0, -0.5); //后面的左上角
glEnd();
//三棱柱左面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.3, 0.3, 0.8);
glVertex3f(-0.5, -0.5, 0.5); //正面的左下角
glVertex3f(0.0, 0.0, 0.5); //顶点
glVertex3f(0.0, 0.0, -0.5); //右面的顶点
glVertex3f(-0.5,-0.5, -0.5); //后面的右下角
glEnd();
//三棱柱右面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.8, 0.3, 0.3);
glVertex3f(0.5, -0.5, -0.5); //后面的左下角
glVertex3f(0.5, -0.5, 0.5); //正面的右下角
glVertex3f(0.0, 0.0, 0.5); //左面的顶点
glVertex3f(0.0, 0.0, -0.5); //顶点
glEnd();
//三棱柱下面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0, 1.0, 1.0);
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();
glPopMatrix();
glutSwapBuffers();
}
int main(int argv, char* argc[]) {
glutInit(&argv, argc);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInitWindowSize(400, 400);
glutInitWindowPosition(400, 300);
glutCreateWindow("三棱柱 陈彬彬 ");
glutDisplayFunc(RenderScene);
glutSpecialFunc(SpecialKeys);
Init();
glutMainLoop();
}
点的顺序错误造成的绘制错误:
题目 3:
设计程序在实现上题中三棱柱的三视图。
本题中显示的三视图:
效果:
代码:
#include <GL/glut.h>
void axis(double length)
{
glColor3f(1.0f, 1.0f, 1.0f);
glPushMatrix();
glBegin(GL_LINES);
glVertex3d(0.0, 0.0, 0.0);
glVertex3d(0.0, 0.0, length);
glEnd();
//将当前操作点移到指定位置
glTranslated(0.0, 0.0, length - 0.2);
glColor3f(1.0, 0.0, 0.0);
glutWireCone(0.04, 0.3, 8, 8);
glPopMatrix();
}
void RenderScene()
{
glEnable(GL_DEPTH_TEST);
//三棱柱正面
glBegin(GL_TRIANGLE_FAN);
glColor3f(1.0, 1.0, 1.0);
glVertex3f(0.0, 0.0, 0.5); //左上角
glVertex3f(-0.5, -0.5, 0.5); //左下角
glVertex3f(-0.5, -0.5, 0.5); //右上角
glVertex3f(0.5, -0.5, 0.5); //右下角
glEnd();
//三棱柱后面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.5, 1.0, 0.5);
glVertex3f(-0.5, -0.5, -0.5); //后面的右下角
glVertex3f(0.5, -0.5, -0.5); //后面的左下角
glVertex3f(0.0, 0.0, -0.5); //后面的左上角
glEnd();
//三棱柱左面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.3, 0.3, 0.8);
glVertex3f(-0.5, -0.5, 0.5); //正面的左下角
glVertex3f(0.0, 0.0, 0.5); //顶点
glVertex3f(0.0, 0.0, -0.5); //右面的顶点
glVertex3f(-0.5,-0.5, -0.5); //后面的右下角
glEnd();
//三棱柱右面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.8, 0.3, 0.3);
glVertex3f(0.5, -0.5, -0.5); //后面的左下角
glVertex3f(0.5, -0.5, 0.5); //正面的右下角
glVertex3f(0.0, 0.0, 0.5); //左面的顶点
glVertex3f(0.0, 0.0, -0.5); //顶点
glEnd();
//三棱柱下面
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0, 1.0, 1.0);
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();
glPopMatrix();
glutSwapBuffers();
}
void paint(void) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPointSize(1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-3.0, 3.0, -3.0, 3.0, -3, 3);
//gluLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);//正视图
//gluLookAt(2, 0, 0, 0, 0, 0, 0, 1, 0);//侧视图
gluLookAt(0, 2, 0, 0, 0, 0, 1, 0, 0);//俯视图
//画坐标系
axis(2.0);
glPushMatrix();
glRotated(90.0, 0, 1.0, 0);//绕 y 轴正方向旋转 90 度
axis(2.0);
glPopMatrix();
glPushMatrix();
glRotated(-90, 1, 0, 0);//绕 x 轴负方向旋转
axis(2.0);
glPopMatrix();
glRotated(90, 0, 1, 0);
RenderScene();//三棱柱立体图形
glFlush();
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(400, 400);
glutInitWindowPosition(200, 200);
glutCreateWindow("三棱柱俯视图 陈彬彬");
glutDisplayFunc(paint);
glutMainLoop();
}
四、主要函数说明:
glShadeModel(GLenum mode)
函数功能:上色
(1)mode 指明使用哪种着色技术,可以取值
GL_FLAT
和GL_SMOOTH
。默认取值是 GL_SMOOTH。
(2)采用恒定着色时(即 GL_FLAT),使用图元中某个顶点的颜色来渲染整个图元。
(3)在使用光滑着色时(即GL_SMOOTH),独立的处理图元中各个顶点的颜色。
(4)对于线段图元,线段上各点 的颜色将根据两个顶点的颜色通过差值得到,结果就是渐变色。
(5)若使用 GL_FLAT,假设几何图形由 n 个三角形构成,则只会使用顶点颜色数组中最后 n 个颜色进行着色。
gluLookAt()
void gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,
GLdouble centerx,GLdouble centery,GLdouble centerz,
GLdouble upx,GLdouble upy,GLdouble upz);
- 第一组 eyex,eyey,eyez 相机在世界坐标的位置
- 第二组 centerx,centery,centerz 相机镜头对准的物体在世界坐标的位置
- 第三组 upx,upy,upz 相机向上的方向在世界坐标中的方向
解释:
- 第一组:相机的位置即是眼睛的位置,就相当于你的头在一个三维坐标中的具体坐标。
- 第二组:你眼睛要看的物体的坐标。
- 第三组:你的头的方向,头朝上还是朝下,朝左还是朝右。
对第三组的示例解释:
(1)如果 upx=0,upz=0,upy=1,那么说明头是在坐标系中就是在 y 轴的正向位置,人是站立的, 头朝上;
(2)如果upy=-1,那么说明头是在坐标系中就是在 y 轴的负向位置,相当于人是倒立的,头朝 下。
(3)如果upx=1,upz=0,upy=0,那么说明头是在坐标系中就是在 x 轴的正向位置,相当于我们看 的是物体的右边;
(4)如果upx=-1,那么说明头是在坐标系中就是在 x 轴的负向位置,就相当于看的是 物体的左边。
(5)如果upx=0,upz=1,upy=0,那么说明头是在坐标系中就是在 z 轴的正向位置,相当于我们看 的是屏幕朝我们的方向(z轴正向朝外);
(6)如果 upz=-1,那么说明头是在坐标系中就是在 z 轴的负 向位置,相当于我们看的是屏幕向里的方向。
glutSwapBuffers()
glutSwapBuffers 函数是 OpenGL 中 GLUT 工具包中用于实现双缓冲技术的一个重要函数。该函数的功能是交换两个缓冲区指针。- 通常, 我们所看到的窗体、文字、图像,从根本上来说都是“画”出来的。比如,制作一个简单的五子棋,我们可能先要绘制棋盘,然后绘制棋子,我们可能还要绘制一些提示信息。
- 虽然这些绘制操作有一定的先后顺序,通常情况下,操作系统的这些绘制速度非常的快,使人眼误认为这些绘制操作是同时完成的。
- 但当我们进行复杂的绘图操作时,画面便可能有明显的闪烁。解决这个问题的关键在于使绘制的东西同时 出现在屏幕上。
所谓双缓冲技术, 是指使用两个缓冲区: 前台缓冲和后台缓冲
。
- 前台缓冲即我们看到的屏幕,
- 后台缓冲则在内存当中,对我们来说是不可见的。
- 每次的所有绘图操作都在后台缓冲中进行,当绘制完成时,把 绘制的最终结果复制到屏幕上, 这样, 我们看到所有 GDI元素同时出现在屏幕上,从而解决了频繁刷新导致的画面闪烁问题。
注意:
- 使用 glutSwapBuffers()函数的时候,主程序中的 glutInitDisplayMode()函数需要设置为
glutInitDisplayMode(GLUT_RGB | GLUT_ DOUBLE );
- 使 用 glFlush() 函 数 的 时 候 主 程 序 中 的 glutInitDisplayMode() 函 数 需 要 设 置 为
glutInitDisplayMode(GLUT_RGB | GLUT_ SINGLE | GLUT_DEPTH);
- List item
glOrtho()
glOrtho 是创建一个正交平行的视景体。 一般用于物体不会因为离屏幕的远近而产生大小的变换的情况。
glOrtho(left, right, bottom, top, near, far)
,
- left 表示视景体左面的坐标,right 表示右面的坐标,bottom 表 示下面的,top 表示上面的。
这个函数简单理解起来,就是一个物体摆在那里,你怎么去截取他。这里,我们先抛开 glViewport 函数不看。先单独理解 glOrtho 的功能。
- 假设有一个球体,半径为 1,圆心在(0, 0, 0),
- 那么,我们设定 glOrtho(-1.5, 1.5, -1.5, 1.5, -10,10); 就表示用一个宽高都是 3 的框框把这个球体整个都装了进来。
- 如果设定 glOrtho(0.0, 1.5, -1.5, 1.5, -10, 10);就表示用一个宽是 1.5, 高是 3的框框把整个球体的右面装进来;
- 如果设定 glOrtho(0.0, 1.5, 0.0, 1.5, -10, 10);就表示用一个宽和高都是 1.5的框框把球体的右上角装了进来。
“老年人常思既往,少年人常思将来。惟思既往也,故生留恋心;惟思将来也,故生希望心。惟留恋也,故保守;惟希望也,故进取。惟保守也,故永旧;惟进取也,故日新。”