计算机图形学基础实验报告
专业:
班级:
姓名:
学号:
日期:
OpenGL简介
(1)OpenGL作为一个性能优越的图形应用程序设计界面(API),它独立于硬件和窗口系统,在运行各种操作系统的各种计算机上都可用,并能在网络环境下以客户/服务器模式工作,是专业图形处理、科学计算等高端应用领域的
标准
excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载
图形库。
它具有以下功能。
1. 模型绘制
2. 模型观察
在建立了三维景物模型后,就需要用OpenGL描述如何观察所建立的三维模型。
3. 颜色模式的指定
OpenGL应用了一些专门的
函数
excel方差函数excelsd函数已知函数 2 f x m x mx m 2 1 4 2拉格朗日函数pdf函数公式下载
来指定三维模型的颜色。
4. 光照应用
用OpenGL绘制的三维模型必须加上光照才能更加与客观物体相似。
5. 图象效果增强
OpenGL提供了一系列的增强三维景观的图象效果的函数,这些函数通过反走样、混合和雾化来增强图象的效果。
6. 位图和图象处理
OpenGL还提供了专门对位图和图象进行操作的函数。
7. 纹理映射
8. 实时动画
9. 交互技术
图1.1 OpenGL图形处理系统的层次结构
(2)OpenGL的操作步骤
在OpenGL中进行的图形操作直至在计算机屏幕上渲染绘制出三维图形景观的基本步骤如下:
1. 根据基本图形单元建立景物模型,得到景物模型的数学描述(OpenGL中把点、线、多边形、图像和位图都作为基本图形单元);
2. 把景物模型放在三维空间中的合适的位置,并且设置视点(Viewpoint)以观察所感兴趣的景观;
3. 计算模型中所有物体的色彩,同时确定光照条件、纹理粘贴方式等;
4. 把景物模型的数学描述及其色彩信息转换至计算机屏幕上的像素,这个过程也就是光栅化(rasterization)。
在这些步骤的执行过程中,OpenGL可能执行其他的一些操作,例如自动消隐处理等。另外,景物光栅化之后被送入帧缓冲器之前还可以根据需要对象素数据进行操作。
(3)OpenGL的组成
OpenGL不是一种编程语言,而是一种API(应用程序编程接口),它实际上是一种图形与硬件的接口,包括了多个图形函数。OpenGL主要由以下函数库组成。
1. OpenGL核心库
OpenGL核心库中包含了115个最基本的命令函数,它们都是以“gl”为前缀,可以在任何OpenGL的工作平台上应用。这部分函数用于常规的、核心的图形处理,如建立各种各样的几何模型,产生光照效果,进行反走样以及进行纹理映射,以及进行投影变换等等。由于许多函数可以接收不同数据类型的参数,因此派生出来的函数原形有300多个。
2. OpenGL实用程序库
OpenGL的实用程序库包含有43个函数,以“glu”为前缀,在任何OpenGL平台都可以应用。这部分函数通过调用核心库的函数,来实现一些较为复杂的操作,如纹理映射、坐标变换、网格化、曲线曲面以及二次物体(圆柱、球体等)绘制等。
3. OpenGL编程辅助库
OpenGL的辅助库包含31个函数,以“aux”为前缀,但它们不能在所有的OpenGL平台上使用。OpenGL的辅助库的函数主要用于窗口管理、输入输出处理以及绘制一些简单的三维形体。
4. OpenGL实用程序工具包
OpenGL实用程序工具包(OpenGL utility toolkit,GLUT)包含30多个函数,函数名前缀是“glut”。其中的函数主要提供基于窗口的工具,如窗口系统的初始化,多窗口管理,菜单管理,字体以及一些较复杂物体的绘制等。由于glut库中的窗口管理函数是不依赖于运行环境的,因此OpenGL中的工具库可以在所有的OpenGL平台上运行,在后面的示例中,我们均使用glut库建立OpenGL程序运行框架。
5. Windows专用库
Windows专用库函数包含有6个,每个函数以wgl开头,用于连接OpenGL和Windows NT,这些函数用于在Windows NT环境下的OpenGL窗口能够进行渲染着色,在窗口内绘制位图字体以及把文本放在窗口的某一位置等这些函数把Windows和OpenGL揉合在一起。
6. Win32 API函数库
这部分函数没有专用的前缀,主要用于处理像素存储格式和双帧缓存。
实验一
一、实验目的
理解glut程序框架;理解窗口到视区的变换;理解OpenGL实现动画的原理理解所学的画直线以及圆的各种算法,利用所学的算法,绘制基本的直线以及圆。
二、实验内容
1.添加代码实现中点Bresenham算法画直线
2.添加代码实现改进Bresenham算法画直线
3.添加代码实现圆的绘制(可以适当对框架坐标系进行修改)
三、实验算法分析
1. 中点Bresenham算法:根据直线的斜率确定或选择变量在x或y方向上每次递增一个单位,而另一方向的增量为1或0,它取决于实际直线与相邻象素点的距离,这一距离称为误差项。
判别式:
则有:
误差项的递推:d<0:
d>=0:
初始值d的计算:
则有:0≤k≤1时Bresenham算法的算法步骤为:
(1)输入直线的两端点P0(x0,y0)和P1(x1,y1)。
(2)计算初始值△x、△y、d=0.5-k、x=x0、y=y0;
(3)绘制点(x,y)。判断d的符号;若d<0,则(x,y)更新为(x+1,y+1),d更新为d+1-k;否则(x,y)更新为(x+1,y),d更新为d-k。
(4)当直线没有画完时,重复步骤3。否则结束。
2. 改进Bresenham算法:原理如下;
误差项的计算
d初=0,
每走一步:d=d+k
一旦y方向上走了一步,d=d-1
改进1:令e=d-0.5
误差项的计算
d初=0, e初=-0.5,
每走一步:d=d+k 每走一步有e=e+k。
if (e>0) then d=d-1 if (e>0) then e=e-1
改进2:用E=2e△x来替换e;
e初=-0.5 E初=-0.5*2△x=-△x
每走一步有e=e+k 每走一步有E=(e+k)*2△x=E+2△y if (e>0) then e=e-1 if (e>0) then E=(e-1)*2△x=E-2△x
算法步骤:
(1)输入直线的两端点P0(x0,y0)和P1(x1,y1)。
(2)计算初始值△x、△y、e=-△x、x=x0、y=y0。
(3)绘制点(x,y)。
(4)e更新为e+2△y,判断e的符号。若e>0,则(x,y)更新为(x+1,y+1),同时将e更新为e-2△x;否则(x,y)更新为(x+1,y)。
(5)当直线没有画完时,重复步骤3和4。否则结束。
3.画圆算法:
八分画圆法
中点Bresenham画圆:
构造判别式:
当d≤0时,下一点取Pu(xi +1,yi);
当d>0时,下一点取Pd(xi +1,yi-1)。
d>0:
d≤0:
初始值:
用d-0.25代替d则:
算法步骤:
(1)输入圆的半径R。
(2)计算初始值d=1-R、x=0、y=R。
(3)绘制点(x,y)及其在八分圆中的另外七个对称点。
(4)判断d的符号。若d<0,则先将d更新为d+2x+3,再将(x,y)更新为(x+1,y);否则先将d更新为d+2(x-y)+5,再将(x,y)更新为(x+1,y-1)。
(5)当x
#include
#include "stdio.h"
int m_PointNumber = 0; //动画时绘制点的数目
int m_DrawMode = 4; //绘制模式 1 DDA算法画直线
// 2 中点Bresenham算法画直线
// 3 改进Bresenham算法画直线
// 4 八分法绘制圆
// 5 四分法绘制椭圆
//绘制坐标线
void DrawCordinateLine(void)
{
int i = 0 ;
//坐标线为黑色
glColor3f(0.0f, 0.0f ,0.0f);
glBegin(GL_LINES);
for (i=10;i<=250;i=i+10)
{
glVertex2f((float)(i), 0.0f);
glVertex2f((float)(i), 250.0f);
glVertex2f(0.0f, (float)(i));
glVertex2f(250.0f, (float)(i));
}
glEnd();
}
//绘制一个点,这里用一个正方形表示一个点。
void putpixel(GLsizei x, GLsizei y)
{
glRectf(10*x,10*y,10*x+10,10*y+10);
}
/////////////////////////////////////////////////////////////////////////
//DDA画线算法 //
//参数说明:x0,y0 起点坐标 //
// x1,y1 终点坐标 //
// num 扫描转换时从起点开始输出的点的数目,用于动画 //
////////////////////////////////////////////////////////////////////////
void DDACreateLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei num)
{
//设置颜色
glColor3f(1.0f,0.0f,0.0f);
//对画线动画进行控制
if(num == 1)
printf("DDA画线算法:各点坐标\n");
else if(num==0)
return;
//画线算法的实现
GLsizei dx,dy,epsl,k;
GLfloat x,y,xIncre,yIncre;
dx = x1-x0;
dy = y1-y0;
x = x0;
y = y0;
if(abs(dx) > abs(dy)) epsl = abs(dx);
else epsl = abs(dy);
xIncre = (float)dx / epsl ;
yIncre = (float)dy / epsl ;
for(k = 0; k<=epsl; k++){
putpixel((int)(x+0.5), (int)(y+0.5));
if (k>=num-1) {
printf("x=%f,y=%f,取整后 x=%d,y=%d\n", x, y, (int)(x+0.5),(int)(y+0.5));
break;
}
x += xIncre;
y += yIncre;
if(x >= 25 || y >= 25) break;
}
}
///////////////////////////////////////////////////////////////////////
//中点Bresenham算法画直线(0<=k<=1) //
//参数说明:x0,y0 起点坐标 //
//x1,y1 终点坐标 //
//num 扫描转换时从起点开始输出的点的数目,用于动画 //
///////////////////////////////////////////////////////////////////////
void BresenhamLine(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei num)
{
glColor3f(1.0f,0.0f,0.0f);
GLsizei dx,dy,d,UpIncre,DownIncre,x,y;
if(num == 1)
printf("中点Bresenham算法画直线:各点坐标及判别式的值\n");
else if(num==0)
return;
if(x0>x1){
x=x1;x1=x0;x0=x;
y=y1;y1=y0;y0=y;
}
x=x0;y=y0;
dx=x1-x0;
dy=y1-y0;
d=dx-2*dy;
UpIncre=2*dx-2*dy; DownIncre=-2*dy;
while(x<=x1)
{
putpixel(x,y);
x++;
if(d<0){
y++;
d+=UpIncre;
}
else d+=DownIncre;
}
}
/////////////////////////////////////////////////////////////////////////
//改进的Bresenham算法画直线(0<=k<=1) //
//参数说明:x0,y0 起点坐标 //
//x1,y1 终点坐标 //
// num 扫描转换时从起点开始输出的点的数目,用于动画 //
/////////////////////////////////////////////////////////////////////////
void Bresenham2Line(GLsizei x0, GLsizei y0, GLsizei x1, GLsizei y1, GLsizei num)
{
glColor3f(1.0f,0.0f,0.0f);
GLsizei x,y,dx,dy,e;
if(num == 1)
printf("改进的Bresenham算法画直线:各点坐标及判别式的值\n");
else if(num==0)
return;
dx=x1-x0;
dy=y1-y0;
e=-dx;
x=x0;
y=y0;
while(x<=x1){
putpixel(x,y);
if (x>=num-1) {
printf("x=%d,y=%d\n", x, y);
break;
}
x++;
e=e+2*dy;
if(e>0){
y++;
e=e-2*dx;
}
}
}
/////////////////////////////////////////////////////////////////// // //
//Bresenham算法画圆 //
//参数说明:x,y 圆心坐标 //
// R 圆半径 //
// num 扫描转换时从起点开始输出的点的数目,用于动画 //
/////////////////////////////////////////////////////////////////// // //
void CirclePoint(GLsizei x,GLsizei y)
{ putpixel(x+10,y+10);
putpixel(x+10,-y+10);
putpixel(y+10,-x+10);
putpixel(-y+10,-x+10);
putpixel(-x+10,-y+10);
putpixel(-x+10,y+10);
putpixel(-y+10,x+10);
putpixel(y+10,x+10);
}
void BresenhamCircle(GLsizei x, GLsizei y, GLsizei R, GLsizei num)
{
glColor3f(1.0f,0.0f,0.0f);
GLsizei d;
x=0;y=R;d=1-R;
if(num == 1)
printf("Bresenham算法画圆:各点坐标及判别式的值\n");
else if(num==0)
return;
while(x<=y){
CirclePoint(x,y);
if (x>=num-1) {
printf("x=%d,y=%d\n", x, y);
break;
}
if(d<0)d+=2*x+3;
else{
d+=2*(x-y)+5;
y--;
}
x++;
}
}
//初始化窗口
void Initial(void)
{
// 设置窗口颜色为蓝色
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
}
// 窗口大小改变时调用的登记函数
void ChangeSize(GLsizei w, GLsizei h)
{
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.0, -1.0);
else
glOrtho (0.0f, 250.0f*w/h, 0.0f, 250.0f, 1.0, -1.0);
}
// 在窗口中绘制图形
void ReDraw(void)
{
//用当前背景色填充窗口
glClear(GL_COLOR_BUFFER_BIT);
//画出坐标线
DrawCordinateLine();
switch(m_DrawMode)
{
case 1:
DDACreateLine(0,0,20,15,m_PointNumber);
break;
case 2:
BresenhamLine(0,0,20,15,m_PointNumber);
break;
case 3:
Bresenham2Line(1,1,8,6,m_PointNumber);
break;
case 4:
BresenhamCircle(10,10,10,m_PointNumber);
break;
default:
break;
}
glFlush();
}
//设置时间回调函数
void TimerFunc(int value)
{
if(m_PointNumber == 0)
value = 1;
m_PointNumber = value;
glutPostRedisplay();
glutTimerFunc(500, TimerFunc, value+1);
}
//设置键盘回调函数
void Keyboard(unsigned char key, int x, int y)
{
if (key == '1') m_DrawMode = 1;
if (key == '2') m_DrawMode = 2;
if (key == '3') m_DrawMode = 3;
if (key == '4') m_DrawMode = 4;
m_PointNumber = 0;
glutPostRedisplay();
}
//void main(void)
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
//初始化GLUT库OpenGL窗口的显示模式
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(600,600);
glutInitWindowPosition(100,100);
glutCreateWindow("基本图元绘制程序");
glutDisplayFunc(ReDraw);
glutReshapeFunc(ChangeSize);
glutKeyboardFunc(Keyboard);//键盘响应回调函数
glutTimerFunc(500, TimerFunc, 1);
// 窗口初始化
Initial();
glutMainLoop(); //启动主GLUT事件处理循环
return 0;
}
实验二
一、实验目的
理解OpenGL中的变换过程,理解透视投影与平行投影的不同 ,了解深度测试,通过变换调整观察的位置与方向完成相应的内容。 二、实验内容
1、添加代码实现太阳、地球和月亮的运动模型
2、加入光照模型
三、实验分析
根据所给的代码,我们可以得到类似于题目要求的模型,只不过是在旋转的角度以及球体的大小上有所差别,并且比要求的多了一个球,那么找到生成这个图像的相应的函数,修改参数的数值,即可得到正确的结果,再加上一个光照的模型即达到到实验的要求。
四、运行结果
五、心得体会:
本次试验还是第一次试验要求相似,给出一部分代码,在另外添加代码实现功能。我觉得这种模式非常好,既学到了知识,有免得花费太多时间在一些不是很重要只需要了解的东西上。
但是这次实验遇到了一些困难,感觉比上次稍难一点,可能是课本上的只是没学透彻。开始的时候对光照模型的处理一直不会,之后找同学教了以后才做对了。
感谢帮助我的同学和助教,另外还要感谢老师对我的教诲。
六、源程序:
////////////////////////////////////////////////////////////////////////////
//实验要求:(1)理解OpenGL中的变换过程 //
// (2)理解透视投影与平行投影的不同 //
// (3)添加代码实现太阳、地球和月亮的运动模型 //
// (4)了解深度测试 //
// (5)通过变换调整观察的位置与方向 //
// (6)加入光照模型 //
////////////////////////////////////////////////////////////////////////////
#include
#include
#include
#include
void Initial()
{
//add new
GLfloat light_diffuse[]={1.0f,1.0f,1.0f,1.0f};
GLfloat light_ambient[]={0.0f,0.5f,0.5f,1.0f};
glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
//使光源有效
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST); // 启用深度测试
glFrontFace(GL_CCW); // 指定逆时针绕法表示多边形正面
glClearColor(1.0f, 1.0f, 1.0f, 1.0f ); //背景为白色
}
void ChangeSize(int w, int h)
{
if(h == 0) h = 1;
// 设置视区尺寸
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// 设置修剪空间
GLfloat fAspect;
fAspect = (float)w/(float)h;
gluPerspective(45.0, fAspect, 1.0, 500.0);
/*
if (w = h)
glOrtho (-nRange, nRange, nRange*h/w, -nRange*h/w, -nRange*2.0f, nRange*2.0f);
else
glOrtho (-nRange*w/h, nRange*w/h, nRange, -nRange, -nRange*2.0f, nRange*2.0f);
*/
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void RenderScene(void)
{
// 绕原子核旋转的角度
static float fElect1 = 0.0f;
static float fElect2 = 0.0f;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//add new
GLfloat position[] = { 0.0f, 0.0f, 1.5f, 1.0f };
// 重置模型视图矩阵
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
//将图形沿z轴负向移动
glTranslatef(0.0f, 0.0f, -250.0f);
// 绘制红色的原子核
//glColor3f(1.0f, 0.0f, 0.0f);
//glutSolidSphere(10.0f, 15, 15);
// 当前绘制颜色变为黄色
//glColor3f(0.0f, 0.0f, 0.0f);
//设置光源的位置
glLightfv (GL_LIGHT0, GL_POSITION, position);
//绘制太阳 add new
glTranslated (0.0f, 0.0f, 1.5f);
glDisable (GL_LIGHTING);
glColor3f (1.0f, 0.0f, 0.0f);
glutSolidSphere (30.0f, 50.0f, 50.0f);
glEnable (GL_LIGHTING);
//绘制地球 add new
glColor3f(1.0f, 1.0f, 0.0f);
//绘制第一个电子
//保存当前的模型视图矩阵
glPushMatrix();
glRotatef(15.0f,0.0f,0.0f,0.0f);//add by hyf
glRotatef(fElect1, 0.0f, 1.0f, 0.0f);//绕y轴旋转一定的角度
glTranslatef(90.0f, 0.0f, 0.0f);//平移一段距离
glutSolidSphere(10.0f, 25, 25);//画出电子
// 恢复矩阵
//glPopMatrix();
//绘制月亮
glColor3f(0.f, 0.0f, 0.0f);
glRotatef(60.0f, 0.0f, 1.0f, 0.0f);
glRotatef(fElect2, 0.0f, 1.0f, 0.0f);
glTranslatef(-15.0f, 0.0f, 0.0f);
glutSolidSphere(3.0f, 15, 15);
fElect2 += 10.0f;
if(fElect2 > 360.0f) fElect2 = 10.0f;
glPopMatrix();
// 第二个电子
/* glPushMatrix();
glRotatef(45.0f, 0.0f, 0.0f, 1.0f);
glRotatef(fElect1, 0.0f, 1.0f, 0.0f);
glTranslatef(-70.0f, 0.0f, 0.0f);
glutSolidSphere(6.0f, 15, 15);
glPopMatrix();
// 第三个电子
glPushMatrix();
glRotatef(-45.0f,0.0f, 0.0f, 1.0f);
glRotatef(fElect1, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0f, 0.0f, 60.0f);
glutSolidSphere(6.0f, 15, 15);
glPopMatrix();
*/
// 增加旋转步长
fElect1 += 5.0f;
if(fElect1 > 360.0f) fElect1 = 10.0f;
glutSwapBuffers();
}
void TimerFunc(int value)
{
glutPostRedisplay();
glutTimerFunc(100, TimerFunc, 1);
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutCreateWindow("地球、月亮、太阳");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
glutTimerFunc(500, TimerFunc, 1);
Initial();
glutMainLoop();
return 0;
}
�
应用软件
OpenGL
窗口系统
操作系统
图形硬件