计算机图形学课程设计三维真实感图形设计与绘制Word格式文档下载.docx
《计算机图形学课程设计三维真实感图形设计与绘制Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《计算机图形学课程设计三维真实感图形设计与绘制Word格式文档下载.docx(49页珍藏版)》请在冰豆网上搜索。
三、设计简介及设计方案论述
3.1设计简介
为了实现本程序的两大功能,计划采用OPENGL图形库并调用一系列WINDOWSAPI采用C/C++语言编写。
首先,应熟悉OPENGL在WIN32平台下的相关API,以及其余WINDOWS窗口交互的相关接口方法,来构建窗口的内容。
其次,熟悉了解OPENGL库函数在窗体中实现绘图,实现图形的旋转、光照、纹理等功能的相关函数。
最后,实现OPENGL与WINDOWS的交互的过程,完成程序及注释。
3.2OPENGL图形库简介
3.2.1OPENGL特点
从程序开发人员的角度来看,OpenGL是一组绘图命令的API集合。
利用这些API能够方便地描述二维和三维几何物体,并控制这些物体按某种方式绘制到显示缓冲区中。
OpenGL的API集合提供了物体描述、平移、旋转、缩放、光照、纹理、材质、象素、位图、文字、交互以及提高显示性能等方面的功能,基本涵盖了开发二、三维图形程序所需的各个方面。
与一般的图形开发工具相比,OpenGL具有以下几个突出特点:
(1)应用广泛
(2)跨平台性
(3)高质量和高性能
(4)出色的编程特性
(5)网络透明性
3.2.2OPENGL工作顺序
OpenGL的工作顺序就是一个从定义几何要素到把象素段写入帧缓冲区的过程。
在屏幕上显示图象的主要步骤是以下3步:
1)构造几何要素(点、线、多边形、图像、位图),创建对象的数学描述。
在三维空间放置对象,选择有利的观察点。
2)计算对象的颜色,这些颜色可能直接定义,或由光照条件及纹理间接给出。
3)光栅化,把对象的数学描述和颜色信息转换到屏幕的象素。
3.3OPENGL简单编程方法
3.3.1OPENGL基本语法
OpenGL基本函数均使用gl作为函数名的前缀,如glClearColor();
实用函数则使用glu作为函数名的前缀,如gluSphere()。
OpenGL基本常量的名字以GL_开头,如GL_LINE_LOOP;
实用常量的名字以GLU_开头,如GLU_FILL。
一些函数如glColor*()(定义颜色值),函数名后可以接不同的后缀以支持不同的数据类型和格式。
如glColor3b(…)、glColor3d(…)、
glColor3f(…)和glColor3bv(…)等,这几个函数在功能上是相似的,只是适用于不同的数据类型和格式,其中3表示该函数带有三个参数,b、d、f分别表示参数的类型是字节型、双精度浮点型和单精度浮点型,v则表示这些参数是以向量(数组)形式出现的。
OpenGL还定义了一些特殊的类型名,如GLfloat,GLvoid。
它们其实就是C中的float和void。
在gl.h文件中可以看到以下定义:
typedeffloatGLfloat;
typedefvoidGLvoid;
……
一些基本的数据类型都有类似的定义。
3.3.2OPENGL状态机制
OpenGL的工作方式是一种状态机制,它可以进行各种状态或模式设置,这些状态或模式在重新改变它们之前一直有效。
例如,当前颜色就是一个状态变量,在这个状态改变之前,绘制的每个象素都将使用该颜色,直到当前颜色被设置为其它颜色为止。
OpenGL中大量地使用了这种状态机制,如颜色模式、投影模式、单双显示缓存区的设置、背景色的设置、光源的位置和特性等等。
3.3.3OPENGL基本结构
OpenGL程序的基本结构可分为三个部分:
第一部分是初始化部分,主要是设置一些OpenGL的状态开关,如颜色模式(RGBA或ALPHA等)的选择,是否作光照处理(若有的话,还需设置光源的特性),深度检验,裁剪等等。
这些状态一般都用函数glEnable(),glDisable()来设置,()中为相应的状态。
第二部分设置观察坐标系下的取景模式和取景框位置及大小。
主要利用了三个函数:
1.函数voidglViewport(left,top,right,bottom):
设置在屏幕上的窗口大小,四个参数描述屏幕窗口四个边界坐标(以象素表示);
2.函数voidglOrtho(left,right,bottom,top,near,far):
设置投影方式为正交投影(平行投影),其取景体积(观察体)是一个各面均为矩形的六面体;
3.函数voidgluPerspective(fovy,aspect,zNear,zFar):
设置投影方式为透视投影,其取景体积(观察体)是一个截头锥体(棱台),在这个体积内的物体投影到锥体的顶点。
第三部分是OpenGL的主要部分,使用OpenGL的库函数构造几何物体对象的数学描述,包括点线面的位置和拓扑关系,几何变换,光照处理等。
3.4OPENGL及WINDOWS坐标系
OPENGL的三维坐标系如图3-1所示:
XOY平面为屏幕所在
图3-1OPENGL三维坐标系
WINDOWS的窗体坐标如图3-2所示:
图3-2WINDOWS窗体二维坐标系
3.5、WINDOWS消息机制
消息机制是Windows应用程序的核心,在Windows中发生的一切都可以用消息来表示,消息用于告诉操作系统发生了什么,所有的Windows应用程序都是消息驱动的,除了WM_COMMAND消息,所有以WM_为前缀的消息都是标准的Windows消息,如窗口、鼠标移动、窗口大小改变等,程序启动或退出甚至每一段固定的时间都会产生标准Windows消息。
Windows消息控制中心一般是三层结构,其顶端就是Windows内核。
Windows内核维护着一个消息队列,第二级控制中心从这个消息队列中获取属于自己管辖的消息,后做出处理,有些消息直接处理掉,有些还要发送给下一级窗体(Window)或控件(Control)。
第二级控制中心一般是各Windows应用程序的Application对象。
第三级控制中心就是Windows窗体对象,每一个窗体都有一个默认的窗体过程,这个过程负责处理各种接收到的消息。
1、消息的组成:
一个消息由一个消息名称(UINT),和两个参数(WPARAM,LPARAM)。
当用户进行了输入或是窗口的状态发生改变时系统都会发送消息到某一个窗口。
例如当菜单转中之后会有WM_COMMAND消息发送,WPARAM的高字中(HIWORD(wParam))是命令的ID号,对菜单来讲就是菜单ID。
当然用户也可以定义自己的消息名称,也可以利用自定义消息来发送通知和传送数据。
2、谁将收到消息:
一个消息必须由一个窗口接收。
在窗口的过程(WNDPROC)中可以对消息进行分析,对自己感兴趣的消息进行处理。
例如你希望对菜单选择进行处理那么你可以定义对WM_COMMAND进行处理的代码,如果希望在窗口中进行图形输出就必须对WM_PAINT进行处理。
3、未处理的消息到那里去了:
M$为窗口编写了默认的窗口过程,这个窗口过程将负责处理那些你不处理消息。
正因为有了这个默认窗口过程我们才可以利用Windows的窗口进行开发而不必过多关注窗口各种消息的处理。
例如窗口在被拖动时会有很多消息发送,而我们都可以不予理睬让系统自己去处理。
4、窗口句柄:
说到消息就不能不说窗口句柄,系统通过窗口句柄来在整个系统中唯一标识一个窗口,发送一个消息时必须指定一个窗口句柄表明该消息由那个窗口接收。
而每个窗口都会有自己的窗口过程,所以用户的输入就会被正确的处理。
例如有两个窗口共用一个窗口过程代码,你在窗口一上按下鼠标时消息就会通过窗口一的句柄被发送到窗口一而不是窗口二。
一个消息从产生到被一个窗口响应,其中有5个步骤:
1)系统中发生了某个事件。
2)Windows把这个事件翻译为消息,然后把它放到消息队列中。
3)应用程序从消息队列中接收到这个消息,把它存放在TMsg记录中。
4)应用程序把消息传递给一个适当的窗口的窗口过程。
5)窗口过程响应这个消息并进行处理。
步骤3和4构成了应用程序的消息循环。
消息循环往往是Windows应用程序的核心,因为消息循环 使一个应用程序能够响应外部的事件。
消息循环的任务就是从消息队列中检索消息,然后把消息传递给适当的窗口。
如果消息队列中没有消息,Windows就允许其他应用程序处理它们的消息。
Windows操作系统最大的特点就是其图形化的操作界面,其图形化界面是建立在其消息处理机制这个基础之上的
3.6大体设计方案
综上所述,在本程序中。
首先使用相关的WINDOWSAPI创建窗口,其次实现程序的相应功能:
1.使用OPENGL相应库函数画出三维图形。
2.使之旋转起来。
3.在窗体中响应鼠标事件,控制正方体的旋转。
程序流程图如图3-3所示:
图3-3程序流程图
程序的大体内容以及机构已经构造成型,功能部分还需要进一步的细化。
显然在消息循环中的内容还远不止这些,还需加入响应以下事件:
1.当窗口大小发生变化时,重置窗口。
2.响应鼠标事件,并改变相对应的参数值,来改变旋转速度。
3.响应窗口中断事件,如关闭事件、屏保事件。
4.
四、详细设计
4.1OPENGL的绘制工作
上面提到完成OPENGL的绘制工作主有两个主要方面的工作需要完成:
1.OPENGL的初始化。
2.OPENGL的绘制工作,其中包括了是图形旋转,纹理。
以下我们分别来完成。
4.1.1OPENGL的初始化工作
通过查找资料OPENGL的初始化工作由如下库函数过程来完成
glShadeModel(GL_SMOOTH);
//启用阴影平滑
启用smoothshading(阴影平滑)。
阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑。
glClearColor(1.0f,0.0f,1.0f,0.5f);
//紫色背景
色彩值的范围从0.0f到1.0f。
0.0f代表最黑的情况,1.0f就是最亮的情况。
glClearColor后的第一个参数是RedIntensity(红色分量),第二个是绿色,第三个是蓝色。
最大值也是1.0f,代表特定颜色分量的最亮情况。
接下来的三个函数必须做的是关于depthbuffer(深度缓存)的。
将深度缓存设想为屏幕后面的层。
深度缓存不断的对物体进入屏幕内部有多深进行跟踪。
几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。
它的排序决定那个物体先画。
这样您就不会将一个圆形后面的正方形画到圆形上来。
深度缓存是OpenGL十分重要的部分。
glClearDepth(1.0f);
//设置深度缓存
glEnable(GL_DEPTH_TEST);
//启用深度测试
glDepthFunc(GL_LEQUAL);
//所作深度测试的类型
接下来是透视图修饰使透视图好看些:
glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
//真正精细的透视修正
4.1.2OPENGL的主体绘制工作
首先使用glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
清除屏幕和深度缓存
然后使用glLoadIdentity();
重置当前的模型观察矩阵,确定绘制好图形的位置glTranslatef(0.0f,0.0f,z);
移入屏幕z个单位。
函数glTranslatef(x,y,z)作用为沿着X,Y和Z轴移动。
绘制图形函数:
voidDraw(void)
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//清晰的画面和深度缓冲
glLoadIdentity();
//重置当前点矩阵
glTranslatef(-1.5f,0.0f,-6.0f);
//往左移到屏幕上1.5个单位为6.0
glPushMatrix();
//准备动态改变
glMultMatrixf(Transform.M);
//采用动态变换
glColor3f(0.75f,0.75f,1.0f);
//glBindTexture(GL_TEXTURE_2D,texture[0]);
Torus(0.30f,1.00f);
glPopMatrix();
glTranslatef(1.5f,0.0f,-6.0f);
glColor3f(1.0f,0.75f,0.75f);
glBindTexture(GL_TEXTURE_2D,texture[1]);
gluSphere(quadratic,1.3f,20,20);
glFlush();
//刷新
}
4.2鼠标控制图形的旋转
首先我们把鼠标坐标映射到[-1,1]之间,它很简单:
MousePt.X=((MousePt.X/((Width-1)/2))-1);
MousePt.Y=-((MousePt.Y/((Height-1)/2))-1);
下面我们计算这个长度,如果它大于轨迹球的边界,我们将简单的把z轴设为0,否则我们把z轴设置为这个二维点映射到球面上对应的z值。
一旦我们有了两个点,就可以计算它的法向量了和旋转角了。
下面我们从构造函数开始,完整的讲解这个类:
ArcBall_t:
:
ArcBall_t(GLfloatNewWidth,GLfloatNewHeight)
当点击鼠标时,记录点击的位置
voidArcBall_t:
click(constPoint2fT*NewPt)
当拖动鼠标时,记录当前鼠标的位置,并计算出旋转的量。
drag(constPoint2fT*NewPt,Quat4fT*NewRot)
如果窗口大小改变,设置鼠标移动的范围
setBounds(GLfloatNewWidth,GLfloatNewHeight)
下面是完成计算所要用到的数据结果,都是一些矩阵和向量
Matrix4fTTransform={1.0f,0.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,0.0f,
0.0f,0.0f,1.0f,0.0f,
0.0f,0.0f,0.0f,1.0f};
Matrix3fTLastRot={1.0f,0.0f,0.0f,
0.0f,1.0f,0.0f,
0.0f,0.0f,1.0f};
Matrix3fTThisRot={1.0f,0.0f,0.0f,
ArcBallTArcBall(640.0f,480.0f);
Point2fTMousePt;
boolisClicked=false;
//是否点击鼠标
boolisRClicked=false;
//是否右击鼠标
boolisDragging=false;
//是否拖动
为了更新鼠标的移动范围,我们在函数ReshapeGL中加入下面一行:
voidReshapeGL(intwidth,intheight)
...
ArcBall.setBounds((GLfloat)width,(GLfloat)height);
//更新鼠标的移动范围
//处理鼠标的按键操作
LRESULTCALLBACKWindowProc(HWNDhWnd,UINTuMsg,WPARAMwParam,LPARAMlParam)
...
caseWM_MOUSEMOVE:
MousePt.s.X=(GLfloat)LOWORD(lParam);
MousePt.s.Y=(GLfloat)HIWORD(lParam);
isClicked=(LOWORD(wParam)&
MK_LBUTTON)?
true:
false;
isRClicked=(LOWORD(wParam)&
MK_RBUTTON)?
break;
caseWM_LBUTTONUP:
isClicked=false;
break;
caseWM_RBUTTONUP:
isRClicked=false;
caseWM_LBUTTONDOWN:
isClicked=true;
caseWM_RBUTTONDOWN:
isRClicked=true;
4.3三维模型纹理映射
纹理映射是一个相当复杂的过程,这节只简单地叙述一下最基本的执行纹理映射所需的
步骤。
基本步骤如下:
一、定义纹理;
二、控制滤波;
三、说明映射方式;
四、绘制场景,给出顶点的纹理坐标和几何坐标。
二维纹理定义的函数是:
voidglTexImage2D(GLenumtarget,GLintlevel,GLintcomponents,GLsizeiwidth,
glsizeiheight,GLintborder,GLenumformat,GLenumtype,
constGLvoid*pixels);
4.4重置OPENGL窗口
下面的代码的作用是重新设置OpenGL场景的大小,而不管窗口的大小是否已经改变(假定您没有使用全屏模式)。
甚至您无法改变窗口的大小时(例如您在全屏模式下),它至少仍将运行一次--在程序开始时设置我们的透视图。
OpenGL场景的尺寸将被设置成它显示时所在窗口的大小。
GLvoidReSizeGLScene(GLsizeiwidth,GLsizeiheight)//重置OpenGL窗口大小
if(height==0)//防止被零除
{
height=1;
//将Height设为1
}
glViewport(0,0,width,height);
//重置当前的视口
下面几行为透视图设置屏幕。
意味着越远的东西看起来越小。
这么做创建了一个现实外观的场景。
此处透视按照基于窗口宽度和高度的45度视角来计算。
0.1f,100.0f是我们在场景中所能绘制深度的起点和终点。
glMatrixMode(GL_PROJECTION)指明接下来的两行代码将影响projectionmatrix(投影矩阵)。
投影矩阵负责为我们的场景增加透视。
glLoadIdentity()近似于重置。
它将所选的矩阵状态恢复成其原始状态。
调用glLoadIdentity()之后我们为场景设置透视图。
glMatrixMode(GL_MODELVIEW)指明任何新的变换将会影响modelviewmatrix(模型观察矩阵)。
模型观察矩阵中存放了我们的物体讯息。
最后我们重置模型观察矩阵
glMatrixMode(GL_PROJECTION);
//选择投影矩阵
//重置投影矩阵
//设置视口的大小
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);
glMatrixMode(GL_MODELVIEW);
//选择模型观察矩阵
//重置模型观察矩阵
4.4WINDOWS中OPENGL窗体设置及创建
WINDOWS中OPENGL的窗体的设置及创建主要有以下几个大的方面,其中具体细节不再阐述:
1.相关变量的设置
HGLRChRC=NULL;
//窗口着色描述表句柄
HDChDC=NULL;
//OpenGL渲染描述表句柄
HWNDhWnd=NULL;
//保存我们的窗口句柄
HINSTANCEhInstance;
//保存程序的实例
第一行设置的变量是RenderingContext(着色描述表)。
每一个OpenGL都被连接到一个着色描述表上。
着色描述表将所有的OpenGL调用命令连接到DeviceContext(设备描述表)上。
我将OpenGL的着色描述表定义为hRC。
要让您的程序能够绘制窗口的话,还需要创建一个设备描述表,也就是第二行的内容。
Windows的设备描述表被定义为