计算机图形学实验指导书.docx
《计算机图形学实验指导书.docx》由会员分享,可在线阅读,更多相关《计算机图形学实验指导书.docx(48页珍藏版)》请在冰豆网上搜索。
计算机图形学实验指导书
巢湖学院
计算机与信息工程学院
《计算机图形学基础》
实验指导书
主编教师:
卜华龙
【上机学时】:
18学时
【上机学分】:
0.5学分
【上机项目数】:
6
【教学对象】:
计算机科学与技术、计算机科学与技术(专升本)
【教学目标】:
通过系列实验,让学生熟练掌握常见图形生成操作如点、直线、多边形等以及图形变换的相关知识。
【教学内容】:
依据计算机图形学教学内容的基本要求,结合我院学分制各专业方向特点和大纲要求,制定本上机实验项目。
项目数为8,前6个项目都为必做项目。
序号
内容
学时
1
学会c++环境下的opengl编程环境
3
2
空间点的绘制
3
3
空间直线的绘制
3
4
多边形的绘制
3
5
平面多面体的绘制
3
6
图形变换
3
7
颜色绘制(选做)
0
8
光照效果(选做)
0
合计
16
一、学会C/C++环境下的opengl编程环境
1.C++配置
1.开发环境的配置
1)将“glut32.dll”等dll文件文件拷贝到操作系统对应的目录system32中。
2)将“glut32.h”等.h文件拷贝到VC++6.0的Include文件夹中。
3)将“glut32.lib”等.lib文件拷贝到VC++6.0的lib文件夹中。
2.用glut编C++程程序的方法
新建一个win32consoleproject,然后新建下面的tut1.cpp:
#include
voiddisplay()
{
}
intmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA);
//设置显示模式:
单缓冲区,RGBA颜色模式
glutInitWindowSize(200,200);
//设置窗口宽度、高度
glutCreateWindow(argv[0]);
//弹出窗口
glutDisplayFunc(display);
//设置窗口刷新的回调函数
glutMainLoop();
//开始主循环
return0;
}
display()是窗口刷新的回调函数。
每当被遮住的窗口再次暴露出来时,系统就调用此函数刷新窗口(即在窗口里作图)。
因为我们的display()什么也不干,因此你看到窗口里是它后面的背景。
我们先画个正方形。
别的不变,只需要改display()
voiddisplay()
{
glClearColor(1,1,1,1);
//设置刷新背景色
glClear(GL_COLOR_BUFFER_BIT);
//刷新背景
glBegin(GL_LINE_LOOP);
glColor3f(1,0,0);
//设置当前颜色
glVertex3f(-0.9,-0.9,0);
glVertex3f(0.9,-0.9,0);
glVertex3f(0.9,0.9,0);
glVertex3f(-0.9,0.9,0);
glEnd();
glFlush();
//更新窗口
}
2.C语言配置
程序GLRect中包含了4个头文件,其中定义了程序所用的函数原形。
此外,OpenGL需要下列*.lib包含在你的工程中:
opengl.lib,glu.lib,glut32.lib;另外在运行程序路径下或\win98\system\(\winNT\system32)下需要一些动态连接库:
opengl32.dll,glu32.dll,glut32.dll。
实验上述内容,写出实验报告。
二、空间点的绘制
最简单的计算机图形就是在屏幕上某个位置绘制一个点,并用特定的颜色绘制出来。
请看下面的代码:
glBegin(GL_POINTS);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(10.0f,10.0f,10.0f);
glEnd();
计算机中的图元只是把一组顶点或顶点列表解释为屏幕上绘制的某些形状,而顶点是用函数glVertex3f来定义,该函数中的参数指明定义点的x、y和z坐标。
OpenGL中定义的定点到放在函数glBegin和glEnd之间,由函数glBegin的参数指定绘制图元的类型。
GL_POINTS表示这个序列中绘制的是单个的点。
注意一个glBegin/glEnd序列中可以包括任意多个相同类型的图元。
表2-1列出了glBegin可支持的OpenGL图元。
glVertex函数用于指定顶点,它可以有2,3,4个参数。
带2个参数时指定的是空间点的x,y坐标,其z坐标为默认值0,在绘制平面图形时常常使用这类函数;带3个参数时14指定的是空间点的x,y和z坐标;带4个参数时,除了定义空间点的x,y,z坐标,还有一个不为0的w坐标,这样,点的坐标(x,y,z,w)实际上构成了一个齐次坐标。
在OpenGL中,我们仍然使用规范化齐次坐标以保证点的齐次坐标与三维坐标的一一对应关系,最后指定的空间点的坐标为(x/w,y/w,z/w,1),w成了坐标值的一个缩放因子。
在OpenGL中绘制一个点时,点大小的默认值是一个象素。
可以用函数glPointSize修改这个值:
voidglPointSize(GLfloatsize);
这个函数采用一个参数来指定画点时以象素为单位的近似直径。
但是不是任意大小点都支持,通常使用下面的代码来获取点大小的范围和它们之间最小的中间值:
GLfloatsizes[2];//保存绘制点的尺寸范围
GLfloatstep;//保存绘制点尺寸的步长
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);
在数组seize中包含两个元素,分别保存了glPointSize的最小有效值和最大有效值,而变量step将保存点大小之间允许的最小增量。
指定范围之外的大小不会被解释为错误,而是使用最接近指定值的可支持的最大或最小尺寸。
在OpenGL程序中,我们常可以利用离散的点来拟合一些常见的曲线,如圆,螺旋线等等。
新建一个win32consoleproject,然后加入下面的tut2.cpp:
#include
voiddisplay()
{
}
intmain(intargc,char**argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGBA);
//设置显示模式:
单缓冲区,RGBA颜色模式
glutInitWindowSize(200,200);
//设置窗口宽度、高度
glutCreateWindow(argv[0]);
//弹出窗口
glutDisplayFunc(display);
//设置窗口刷新的回调函数
glutMainLoop();
//开始主循环
return0;
}
display()是窗口刷新的回调函数。
每当被遮住的窗口再次暴露出来时,系统就调用此函数刷新窗口(即在窗口里作图)。
因为我们的display()什么也不干,因此你看到窗口里是它后面的背景。
我们先画单个点。
别的不变,只需要改display()。
//PointAndLine.c
#include
#include
#include
voidRenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);//用当前背景色填充窗口
glColor3f(0.0f,0.0f,0.0f);//设置当前的绘图绘图RGB颜色
GLfloatsizes[2];//保存绘制点的尺寸范围
GLfloatstep;//保存绘制点尺寸的步长
GLfloatcurSize;//当前绘制的点的大小
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);//获得点的尺寸范围
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);//获得点尺寸的步长
//绘制不同大小的点
curSize=sizes[0];
for(inti=0;i<25;i++)
{
glPointSize(curSize);//设置点的大小
glBegin(GL_POINTS);
glVertex3f(25.0+i*8,200.0f,0.0f);
glEnd();
curSize+=step*2;
}
glDisable(GL_LINE_STIPPLE);
glFlush();//刷新OpenGL命令队列
}
voidChangeSize(GLsizeiw,GLsizeih)
{
if(h==0)h=1;
glViewport(0,0,w,h);//设置视区尺寸
//重置坐标系统
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//建立修剪空间的范围
if(w<=h)
glOrtho(0.0f,250.0f,0.0f,250.0f*h/w,1.0f,-1.0f);
else
glOrtho(0.0f,250.0f*w/h,0.0f,250.0f,1.0f,-1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
voidSetupRC(void)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);//设置窗口的背景色
}
voidmain(void)
{
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutCreateWindow("点与线");
glutDisplayFunc(RenderScene);//设置当前窗口的显示回调函数
glutReshapeFunc(ChangeSize);//为当前窗口设置窗口再整形回调函数
SetupRC();
glutMainLoop();//启动主GLUT事件处理循环
}
如果要修改点的大小,颜色等,只要在display()里做相应修改就可以了。
实验上述内容,要求写出实验报告。
三、空间直线的绘制
使用模式GL_LINES可以在两点之间画线,如下面的代码在两点(0,0,0)和(10,10,10)之间画一条直线:
glBegin(GL_LINES);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(10.0f,10.0f,10.0f);
glEnd();
注意,在glBegin/glEnd序列中两个顶点指定了一个图元(直线),如果序列中指定的点为奇数个,那么最后一个顶点将被忽略。
有时我们需要在一系列的顶点之间绘制连续直线,此时需要用到GL_LINE_STRIP或GL_LINE_LOOP模式。
GL_LINE_STRIP模式可以根据指定的一系列顶点,从一个顶点到另一个顶点用连续的线段画线。
glBegin(GL_LINE_STRIP);
glVertex3f(0.0f,0.0f,0.0f);
glVertex3f(10.0f,10.0f,0.0f);
glVertex3f(20.0f,5.0f,0.0f);
glEnd();
上面这段代码实际上在xy平面内绘制了两条直线(0,0,0)到(10,0,0)和(0,10,0)到(20,5,0)。
特别的,当沿着某条曲线指定一系列靠的很近的点,使用GL_LINE_STRIP模式可以绘制一条曲线。
GL_LINE_LOOP模式与GL_LINE_STRIP模式类似,只是会在指定的最后一个顶点与第一个顶点之间画最后一条线。
直线的属性包括线宽和线型。
在OpenGL中可用glLineWidth指定线宽:
voidglLineWidth(GLfloatwidth)
与点的大小类似,glLineWidth函数采用一个参数来指定要画的线以象素计的近似宽度,可以用下面的代码来获取线宽范围和它们之间的最小间隔:
GLfloatsizes[2];//保存线宽的尺寸范围
GLfloatstep;//保存线宽尺寸的最小间隔
glGetFloarv(GL_LINE_WIDTH_RANGE,sizes);
glGetFloatv(GL_LINE_WIDTH_GRANULARITY,&step);
数组seize中保存了glLineWidth的最小有效值和最大有效值,而变量step将保存线宽之间允许的最小增量。
OpenGL规范只要求支持一种线宽:
1.0。
Microsoft的OpenGL实现允许线宽从0.5到10.0,最小增量为0.125。
除了修改线宽,可以用虚线或短划线模式创建直线,为此需要先调用:
glEnable(GL_LINE_STIPPLE);
然后,函数glLineStipple将建立用于画线的模式:
glLineStipple(GLintfactor,GLushortpattern);
其中,pattern是一个16位值,他指定了画线时所用的模式。
每一位代表线段的一部分是开还是关。
默认情况下,每一位对应一个象素,但factor参数充当倍数可以增加模式的宽度。
例如,将factor设为2会使模式中的每一位代表一行中2个象素的开或关。
另外,在应用模式时,pattern是逆向使用的,即模式的最低有效位最先作用于指定线段。
图2.1说明了模式0X00FF是如何应用到线段上的。
在下面的程序演示了点的大小,线型以及线宽等等,输出图形如图2.2所示。
程序清单3:
点的大小,直线线型和线宽的示例
//PointAndLine.c
#include
#include
#include
voidRenderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT);//用当前背景色填充窗口
glColor3f(0.0f,0.0f,0.0f);//设置当前的绘图绘图RGB颜色
GLfloatsizes[2];//保存绘制点的尺寸范围
GLfloatstep;//保存绘制点尺寸的步长
GLfloatcurSize;//当前绘制的点的大小
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);//获得点的尺寸范围
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);//获得点尺寸的步长
//绘制不同大小的点
curSize=sizes[0];
for(inti=0;i<25;i++)
{
glPointSize(curSize);//设置点的大小
glBegin(GL_POINTS);
glVertex3f(25.0+i*8,200.0f,0.0f);
glEnd();
curSize+=step*2;
}
//绘制一条宽度为5的直线
glLineWidth(5);//设置线宽
glBegin(GL_LINES);
glVertex3f(25.0f,160.0f,0.0f);
glVertex3f(225.0f,160.0f,0.0f);
glEnd();
//绘制一条虚线
glEnable(GL_LINE_STIPPLE);
glLineStipple(1,0x00FF);//设置点划线模式
glBegin(GL_LINES);
glVertex3f(25.0f,120.0f,0.0f);
glVertex3f(225.0f,120.0f,0.0f);
glEnd();
//绘制一条宽度为3的点划线
glLineWidth(3);
glLineStipple(1,0xFF0C);
glBegin(GL_LINES);
glVertex3f(25.0f,80.0f,0.0f);
glVertex3f(225.0f,80.0f,0.0f);
glEnd();
//增加重复因子绘制的点划线
glLineStipple(4,0xFF0C);
glBegin(GL_LINES);
glVertex3f(25.0f,40.0f,0.0f);
glVertex3f(225.0f,40.0f,0.0f);
glEnd();
glDisable(GL_LINE_STIPPLE);
glFlush();//刷新OpenGL命令队列
}
voidChangeSize(GLsizeiw,GLsizeih)
{
if(h==0)h=1;
glViewport(0,0,w,h);//设置视区尺寸
//重置坐标系统
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//建立修剪空间的范围
if(w<=h)
glOrtho(0.0f,250.0f,0.0f,250.0f*h/w,1.0f,-1.0f);
else
glOrtho(0.0f,250.0f*w/h,0.0f,250.0f,1.0f,-1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
voidSetupRC(void)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);//设置窗口的背景色
}
voidmain(void)
{
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutCreateWindow("点与线");
glutDisplayFunc(RenderScene);//设置当前窗口的显示回调函数
glutReshapeFunc(ChangeSize);//为当前窗口设置窗口再整形回调函数
SetupRC();
glutMainLoop();//启动主GLUT事件处理循环
}
四、多边形的绘制
1.三角形的绘制
在OpenGL中,面是由多边形构成的。
三角形可能是最简单的多边形,它有三条边。
可以使用GL_TRIANGLES模式通过把三个顶点连接到一起而绘出三角形。
下面的代码绘制了一个三角形:
glBegin(GL_TRIANGLES);
glVertex2f(0.0,0.0);
glVertex2f(15.0,15.0);
glVertex2f(30.0,0.0);
glEnd();
注意,这里三角形将被用当前选定的颜色填充,如果尚未指定绘图的颜色,结果将是不确定的。
使用GL_TRIANGLE_STRIP模式可以绘制几个相连的三角形,系统根据前三个顶点绘制第一个多边形,以后每指定一个顶点,就与构成上一个三角形的后两个顶点绘制新的一个三角形。
使用GL_TRIANGLE_FAN模式可以绘制一组相连的三角形,这些三角形绕着一个中心点成扇形排列。
第一个顶点构成扇形的中心,用前三个顶点绘制出最初的三角形之后,随后的所有顶点都和扇形中心以及紧跟在它前面的顶点构成下一个三角形,此时是以顺时针方向穿过顶点。
这两种模式的推进如图2.3和图2.4所示。
2.绕法
在绘制三角形的过程中,三个顶点将三角形封闭的过程是有序的,即三角形的构成路径具有方向性,我们把指定顶点时顺序和方向的组合称为“绕法”。
比如上面的例子中画出的三角形的绕法就是顺时针的,若把后两个顶点的位置互换,就得到了逆时针绕法。
绕法是任何多边形图元的一个重要特性。
一般默认情况下,OpenGL认为逆时针绕法的多边形是正对着的,这一特性对于希望给多边形的正面和背面赋予不同的物理特性十分有用。
如果要反转OpenGL的默认行为,可以调用函数:
glFrontFace(GL_CW);
CL_CW告诉OpenGL应该把顺时针缠绕的多边形为正对着的。
为了改回把逆时针绕法视为正面,可以使用CL_CCW。
3.明暗处理
在绘制多边形时,我们常常要指定绘制的颜色,而在OpenGL中,颜色实际上是对各个顶点而不是对各个多边形指定的。
多边形的轮廓或者内部用单一的颜色或许多不同的颜色来填充的处理方式称为明暗处理。
在OpenGL中,用单一颜色处理的称为平面明暗处理(FlatShading),用许多不同颜色处理的称为光滑明暗处理(SmoothShading),也称为Gourand暗处理(GourandShading)。
设置明暗处理模式的函数为:
voidglShadeModel(GLenummode);
其中参数mode的取值为GL_FLAT或GL_SMOOTH,分别表示平面明暗处理和光滑明暗处理。
应用平面明暗处理模式时,多边形内每个点的法向一致,且颜色也一致,OpenGL用指定多边形最后一个顶点时的当前颜色作为填充多边形的纯色;应用光滑明暗处理模式时,多边形所有点的法向是由内插生成的,具有一定的连续性,因此每个点的颜色也相应内插,故呈现不同色。
这种模式下,插值方法采用的是双线性插值法Gouraud明暗处理通常算法为:
先用多边形顶点的光强线性插值出当前扫描线与多边形边交点处的光强,然后再用交点的光强线插值处扫描线位于多边形内区段上每一象素处的光强值。
图2.5中显示出一条扫描线与多边形相交,交线的端点是A点和B点,P点是扫描线上位于多边形内的任一点,多边形三个顶点的光强分别为I1、I2和I3。
取A点的光强Ia为I1和I2的线性插值,B点的光强Ib为I1和I3