精品基于Direct3D的投篮游戏.docx
《精品基于Direct3D的投篮游戏.docx》由会员分享,可在线阅读,更多相关《精品基于Direct3D的投篮游戏.docx(23页珍藏版)》请在冰豆网上搜索。
精品基于Direct3D的投篮游戏
【关键字】精品
HUNANUNIVERSITY
毕业设计(论文)
设计论文题目:
基于Direct3D的投篮游戏
学生姓名:
何杰
学生学号:
506
专业班级:
开发2班
学院名称:
软件学院
指导老师:
申煜湘
学院院长:
林亚平
2008年5月25日
基于Direct3D的投篮游戏
摘要
现在游戏已经深入到人们的生活中,几乎每个人都玩过至少一款游戏。
随着越来越多的人关注游戏,当今的游戏产业也成为潜力无穷的产业。
与此同时,游戏设计已经成为当今许多玩家的梦想。
本设计就是基于DirectX技术的投篮游戏设计,采用VisualC++进行编写。
DirectX是Microsoft公司提供的目前比较普遍的Windows游戏设计开发工具(SDK)。
它基本包括了2D、3D、声音、控制、网络等的基本操作函数,使得程序员不必直接与硬件打交道,大大地提高了游戏开发的简易性和效率。
本设计在Direct3D的基础上,设计出了图形渲染模块,用户界面模块,物理模块,摄像机模块等,并加以代码实现,实现了一个简单的3D投篮游戏。
关键字:
游戏设计,DirectX,投篮
BasketballgamebasedonDirect3D
Abstract
Nowgameshasgonedeepintothepeople’slives,almosteveryoneplayedgames.Withmoreandmorepeopleincreasinginterestingames,thegameindustryisbecomingtobeadevelopingindustry.Atthesametime,gamedesignhasbecomethedreamofmanyplayers.
ThisisaspaceshootinggamedesignbasedonDirectXtechnology,usingVisualC++inprogramming.DirectXisawidelyusedgamedesignanddeveloptool(SDK)whichissuppliedbyMicrosoftCorporation.Itbasicallycoversthe2D,3D,sound,control,andnetwork,makesprogrammerwithoutdealingdirectlywiththehardware,greatlyenhancingthesimplicityandefficiencyofthedevelopmentofgame.
ThisdesignisbasedonDirect3D,ithasgraphicrendermodule,userinterfacemodule,physicmodule,cameramodule.Thenimplementthesemodulesbycoding,sowehaveasimplebasketballgame.
Keyword:
GameDesign,DirectX,Basketball
1.绪论
1.1课题背景
我们生活在一个充满三维物体的三维世界中,为了使计算机能精确地再现这些物体,我们必须能在三维空间描绘这些物体。
我们又生活在一个充满信息的世界中,能否尽快地理解并运用这些信息将直接影响事业的成败,所以我们需要用一种最直接的形式来表示这些信息。
最近几年计算机图形学的发展使得三维表现技术得以形成,这些三维表现技术使我们能够再现三维世界中的物体,能够用三维形体来表示复杂的信息,这种技术就是可视化(Visualization)技术。
可视化技术使人能够在三维图形世界中直接对具有形体的信息进行操作,和计算机直接交流。
这种技术已经把人和机器的力量以一种直觉而自然的方式加以统一,这种革命性的变化无疑将极大地提高人们的工作效率。
可视化技术赋予人们一种仿真的、三维的并且具有实时交互的能力,这样人们可以在三维图形世界中用以前不可想象的手段来获取信息或发挥自己创造性的思维。
机械工程师可以从二维平面图中得以解放直接进入三维世界,从而很快得到自己设计的三维机械零件模型。
医生可以从病人的三维扫描图象分析病人的病灶。
军事指挥员可以面对用三维图形技术生成的战场地形,指挥具有真实感的三维飞机、军舰、坦克向目标开进并分析战斗方案的效果。
更令人惊奇的是目前正在发展的虚拟现实技术,它能使人们进入一个三维的、多媒体的虚拟世界,人们可以游历远古时代的城堡,也可以遨游浩翰的太空。
所有这些都依赖于计算机图形学、计算机可视化技术的发展。
随着三维技术的进步,对于普通电脑用户最大的感受就是电脑游戏的发展了,如今游戏的画面基本上全部都是3D化,在游戏市场的巨大利益推动下,游戏开发商和硬件厂商不断推陈出新,技术的发展可以用一日千里来形容。
1.2国内外研究现状和发展趋势
目前游戏开发采用的主要有OpenGL与DirectX两种图形库。
目前的游戏引擎都是基于这两种图形库来实现图形的渲染。
OpenGL是在SGI等多家世界闻名的计算机公司的倡导下,以SGI的GL三维图形库为基础制定的一个通用共享的开放式三维图形标准。
目前,包括Microsoft、SGI、IBM、DEC、SUN、HP等大公司都采用了OpenGL做为三维图形标准,许多软件厂商也纷纷以OpenGL为基础开发出自己的产品。
OpenGL目前版本为2.0,支持可编程渲染管线。
DirectX是伴随着视窗操作系统的推出而出现的,DirectX的原名为DirectXSDK(或GameSDK),英文原意:
DirectXSoftwareDevelopmentKit,是微软所开发出的一套主要用在设计多媒体、2D、3D游戏及程序的API,其中包含了各类与制作多媒体功能相关的组件(Component),各个组件提供了许多处理多媒体的接口与方法。
从这点介绍我们可以领会到DirectX是为游戏而诞生,从DirectX1.0到DirectX3.0,微软让它的DirectX开始在游戏领域树立起3D的标杆,尽管当时的3D很粗糙,但是雏形已初步形成,到DirectX7开始,随着OpenGL和Glide势力日渐衰弱,DirectX的霸气初现,到DirectX8发布后,DirectX已经在3D游戏领域树立起它的的权威地位,引人的Ps和Vs的出现令OpenGL和Glide自叹不如,DirecetX9.0,更是如日中天,权威地位无人能撼动。
目前DirectX在桌面游戏方面更受开发者的欢迎。
目前版本为10.0。
1.3本文结构
本文分为五章,第一章为绪论。
第二章为技术原理,主要简单介绍本设计中用到的一些基本原理。
第三章为系统设计,主要讲解系统的设计方案。
第四章为系统的实现方案,讲解系统的具体实现。
第五章展示系统的运行效果。
2.技术原理
2.1数学基础知识
几何学中,我们用有向线段表示向量,向量的两个属性是它的长度和它的顶点所指的方向,因此,可以用向量来模拟既有大小又有方向的物理模型。
向量为在3维空间中表示方向提供了方便.
2.1.13D坐标系
3D坐标系中使用最广泛的是笛卡尔坐标系,它基于空间中三条相互垂直的坐标轴:
X轴、Y轴和Z轴。
要定义空间中的一个点P,需要三个坐标:
X,Y,Z写成P(X,Y,Z)。
三个坐标轴构成三个平面:
X-Y平面、X-Z平面和Y-Z平面。
这三个平面将整个空间分成8个子空间,在3D笛卡尔坐标系中共有8个卦限。
图2.1.1左手坐标系
3D笛卡尔坐标系包括左手坐标系和右手坐标系两种。
左手坐标系(LHS)假设X-Y为纸张上或屏幕上的水平轴和垂直轴,正Z轴指向纸内或屏幕内。
右手坐标〔RHS)假设X-Y为纸张上或屏幕上的水平轴和垂直轴,正Z轴指向纸外或屏幕外。
1.向量相等
几何学上,有同样方向和长度的两个向量相等。
数学上,我们说有同样维数和分量的向量相等。
例如:
如果ux=vx,uy=vy,且uz=vz.那么(ux,uy,uz)=(vx,vy,vz)。
在代码中我们能够用“==”判断两个向量相等。
同样的,我们也能用“!
=”判断两个向量不相等。
2.向量的模
几何学上,向量的大小是有向线段的长度。
知道向量的分量,利用下面的公式我们就能计算出向量的大小。
图向量的模
‖u‖表示向量u的长度。
3.标准化向量
标准化向量是让向量的大小等于1,即被叫作单位向量。
我们能利用向量大小以及各个分量把一个向量标准化,就象这样:
图标准化向量
我们这样表示单位向量û。
4.向量相加
我们能够通过分别把两个向量的各个分量相加得到向量之和,注意在相加之前必须保证它们有相同的维数。
图向量相加
下图显示的是几何学上的向量相加。
图几何上的向量相加
5.向量相减
和加法类似,通过分别把两个向量的各个分量相减得到向量之差。
再次重声两个向量必须是相同维数。
图向量相减
下图显示的是几何学上的向量相减。
图几何上的向量相减
6.数乘
我们能用一个标量与向量相乘,就象名字暗示的一样,向量按比例变化。
这种运算不会改变向量的方向,除非标量是负数,这种情况向量方向相反。
图向量数乘
7.点乘
数学上定义点积是两个向量的乘积。
按下面等式计算:
图向量点乘
上面的等式不能很明显的体现几何上的意义。
利用余弦定律,我们能够发现它们的关系。
u·v=|u||v|cosθ,表示两个向量的点积是它们的模和夹角的余弦之积。
因此,如果u和v都是单位向量,那么u·v就是它们夹角的余弦。
一些点积中有用的特性:
假如u·v=0,那么u⊥v。
假如u·v>0,那么两个向量的角度θ小于90度。
假如u·v<0,那么两个向量的角度θ大于90度。
8.叉乘
第二种乘法在向量数学中叫叉积。
不象点积,结果值是一个标量,叉积的结果值是另一个向量。
通过把两个向量u和v相乘得到另一的向量p,向量p垂直于u和v。
也就是说向量p垂直于u并且垂直于u。
十字相乘就象这样计算:
图向量叉乘
如果u·v=0,那么u⊥v。
同样的如果j·k=0并且j·i=0那么我们便能知道j既垂直于k又垂直于i的。
当我们在编程时,通常都使用4x4矩阵来进行矩阵变换。
因为下面所讨论的矩阵变换都是基于4x4矩阵的。
1.矩阵相乘
矩阵相乘在3D计算机图形学中是非常重要的运算。
通过矩阵相乘,我们能变换向量并且,将不同向量转换到一起。
为了得到矩阵之积AB,A的列数必须等于B的行数。
假如这个条件不满足,就不能相乘。
考虑两个矩阵,A和B,分别是2×3和3×3,
我们看乘积AB是可以计算的,因为A的列数等于B的行数。
注意乘积BA,它们是不能计算的,因为B的列数不等于A的行数。
由此说明:
一般情况下矩阵乘法不满足乘法交换律(也就是,AB≠BA)。
我们说“一般不可交换”因为有一些矩阵乘法的实例还是可以的。
知道了矩阵乘法的计算方法,现在我们就能给出精确的定义:
假如A是一个m×n的矩阵,B是一个n×p的矩阵,那么它们之积AB可计算并且是一个m×p的矩阵C,C的成员ij等于A的第i个与B的第j个相乘:
图矩阵乘法
2.矩阵平移
通过与一个特定的矩阵相乘来达到矩阵平移的目的。
例如有向量(x,y,z,m),将其沿x轴移动dx个单位,沿y轴移动dy个单位,沿z轴移动dz个单位,只需将其与下面矩阵相乘。
图平移矩阵
3.矩阵旋转
例如向量(x,y,z,m)围绕x轴旋转θ弧度,只需与下面矩阵相乘:
图x轴旋转矩阵
当要围绕y轴旋转θ弧度,只需与下面矩阵相乘
图y轴旋转矩阵
当要围绕z轴旋转B弧度,只需与下面矩阵相乘
图z轴旋转矩阵
4.矩阵缩放
通过矩阵相乘可以实现矩阵缩放
例如向量(x,y,z,m),沿x轴缩放dx个单位,沿y轴缩放dy个单位,沿z
轴缩放dz个单位,只需将其与下面矩阵相乘。
图缩放矩阵
2.2Direct3D基础
2.2.1Direct3D概述
Direct3D是一种低层图形API(ApplicationProgrammingInterface,应用程序接口),它能让我们利用3D硬件加速来渲染3D世界。
我们可以把Direct3D看作是应用程序和图形设备(3D硬件)之间的中介。
通过利用Direct3DAPI编程,能够屏蔽许多底层实现的技术细节,缩短开发周期。
下图显示了Direct3D,HAL(HardwareAbstractionLayer,硬件抽象层)及硬件之间的关系。
其中HAL即硬件抽象层,是一组指示设备执行某种操作的特殊设备代码的集合,由设备制造商实现,Direct3D不能直接作用于图形设备,通过使用HAL与硬件图形设备协同工作。
如下图所示,Direct3D应用程序最终通过图形卡的设备驱动程序访问图形硬件。
由于HAL存在,Direct3D将可以不需要了解某个设备的具体硬件特性,使它能够独立于硬件设备。
Direct3D提供了相应的方法在运行时检查设备是否能执行某项操作。
图2.2Direct3D层次
2.2.2Direct3D重要概念
1.顶点:
一个场景是多个物体或模型的集合。
一个物体可以用三角形网格来近似表示,3D世界中最基本的图元就是三角形,一个多边形的两边相交的点叫做顶点。
为了描述一个三角形,我们通常指定三个点的位置来对应三角形的三个顶点,这样我们就能够很明确的表示出这个三角形。
3D物体中的三角形经常会有许多共用顶点。
为了解决复杂精细场景重复顶点占用更多的渲染带宽,我们在创建一个顶点列表的同时也创建一个索引列表。
顶点列表包含所有不重复的顶点,索引列表中则用顶点列表中定义的值来表示每一个三角形的构造方式。
通常每个顶点都包含如下信息:
x,y,z坐标值、颜色值、用于计算灯光的法线和纹理坐标(u,v)。
2.表面:
是一个像素点阵,主要用来存储2D图形数据。
表面数据就像一个矩阵,像素数据实际上是存储在线性数组里面。
Direct3D里面的IDirect3DSurface9接口用来描述表面,这个接口提供一些方法来直接操作表面数据。
3.多重采样(MultiSampling):
由于使用像素来表示图像,在显示时会出现锯齿状。
MultiSampling就是使图像变得平滑的技术。
它的最普通的用法就是全屏抗锯齿。
D3DMULTISAMPLE_TYPE枚举类型能使我们制定全屏抗锯齿的质量等级。
4.交换链和页面交换:
Direct3D通常建立2--3个页面组成一个集合,即为交换链,通常由IDirect3DSwapChain接口来表示。
交换链和页面交换技巧被用在使两帧动画之间过渡更加平滑。
通常由Direct3D自己去管理。
5.深度缓冲:
深度缓冲是一个表面,但它不是用来存储图像数据而是用来记录像素的深度信息。
深度缓冲为每一个像素计算深度值,并进行深度测试。
通过深度测试我们可以知道哪个像素离摄像机近从而把它画出来。
这样就可以只绘制最靠近摄像机的像素,被遮住的像素就不会被画出来。
6.顶点处理:
顶点是3D图形学的基础,它能够通过两种不同的方法来处理,一种是:
软件顶点处理(SoftwareVertexProcessing),二种是:
硬件顶点处理(HardwareVertexProcessing)。
前者总是被支持而且永久可用,后者要显卡硬件支持顶点处理才可用。
使用硬件顶点处理总是首选,因为它比软件方式更快,而且不占用CPU资源。
如果一块显卡支持硬件顶点处理的话,也就是说它支持硬件几何变换和光照计算。
7.设备能力:
Direct3D支持的每一种特性都对应于D3DCAPS9结构的一个数据成员,初始化一个D3DCAPS9实例应该以你的设备实际支持的特性为基础。
因此,在我们的应用程序里,我们能够通过检测D3DCAPS9结构中相对应的某一成员来检测设备是否支持这一特性。
2.2.3Direct3D初始化
初始化步骤:
1.获得IDirect3D9接口指针。
2.检查设备的技术特性,确定显卡是否支持硬件顶点处理。
3.初始化一个D3DPRESENT_PARAMETER结构实例,这个结构包含了许多数据成员,它允许我们指定将要创建IDirect3DDevice9接口的特性。
4.创建一个基于已经初始化好了的D3DPRESENT_PARAMETER结构的IDirect3DDevice9对象。
2.3基本3D流水线简介
大家都知道,一个3D场景中,我们见到的任何光辉灿烂的物体,都是由一个一个面片组成的。
而装载面片位置信息的就是其各个定点的三维坐标。
这是用来在模型中存储的,而要把物体显示在屏幕上,还需要将它们转换成显示器上的二维坐标。
这就需要对每个点实施一套3to2的转换公式,在Direct3D中叫做“几何流水线”(GeometryPipeline)。
Direct3D中的GeometryPipeline如下图所示:
图2.3.13D流水线
每渲染一帧,我们都要用到这条流水线把所有定点的坐标转化成当前要显示的位置。
不过放心,D3D不会改变你原有的顶点坐标,变换出的顶点数据会存放在新的地方用来渲染。
想一想物体,也就是面片,也就是顶点要显示在屏幕上,其位置取决于什么呢?
首先它一定取决于该点在场景中的位置,然后还在于你从什么角度看,更详细一点就是我的眼睛在哪儿,我注视着哪儿,以及我的视野宽窄等等。
对于每个独立被引入程序的mesh物体,它们的坐标系、坐标原点理论上都应该是不同的,其顶点也都是用局部坐标表示的。
那么要做统一的变换,首先应将它们引入到同一个坐标系下,也就是我们称之为“世界坐标系”的坐标。
这个变换也因此得名世界变换(WorldTransform)。
对物体所需要做的移动、旋转等工作也是要在此时完成的。
经过了以上一些操作后,每个顶点(也就是每个物体)在整个场景中的位置就如你所愿确定下来了。
要把它们映射到屏幕上,还要确定观察者(你可以叫他玩家、摄影机都无所谓)的位置和视角。
我们是要把所有的点变换到新建立的以观察者为基准的坐标系下。
这个步骤就是“视图变换”(ViewTransform)。
实际上和后面要说的射影变换相比,这两种变换并没有什么本质区别。
有时候为了效率,可以把世界变换与视图变换合并为一个世界——视图变换。
这不就是说你一开始就选择观察者的位置为世界坐标系的原点,并按照视角来确定坐标轴么?
后面一步是“射影变换”(ProjectionTransform)。
实际上,我们要做的所有坐标转换归根结蒂是要把三维的点投影到二维的屏幕上,如图所示
图2.3.2射影变换
经过上述两次坐标转换后,我们已经让屏幕平行于坐标轴平面了,也就是说,经过一些比例范围的调整,理论上我们能从点的三维坐标中的某两个直接得到期待已久的屏幕坐标。
但是别急,此时得到的坐标绘出的图就像我们小时候画的那些画一样——没有立体感。
比如上图那个矩形,因为近大远小,在我们的视野中应该看起来像个梯形。
但是如果我们不做任何处理就直接把它的顶点(已经过前两重变换)投影到显示器上(假设平行于图中的XY平面)这样还是一个方方正正的矩形。
想象一下,投影实际上就是把空间中的所有点都压扁,扁到某一个平面上。
这样出来的图形自然不会有透视效果。
(之所以有近大远小是因为人眼的凸透镜成像,其像高是物距的减函数。
这里不多说了)你可能想到让每个点像这样斜着投影,但是仔细想想,如何斜着投影呢?
等你想明白了再回答这样做真的方便么?
于是另一种办法就是把整个空间范围变成一个棱台(里面的点随之进行放缩)。
图2.3.3投影效果
相对来说把较远端缩小会造成数据的不准确,因此采用放大较近端。
对每个点,我们进行最后一步变换就是根据其远近程度进行一下放缩。
D3D把剪切也纳入此流水线中,尽管它没对顶点作任何变换,只是剔出那些不用的点。
以上就是D3D中的几何流水线。
幸运的是,我们并不需要自己去写代码来完成这些转换。
实际上我们只需要设计好参数,调用相应的D3D函数设置上面提到的各种决定因素,它会在渲染画面的时候把每个顶点自动转化成所需的屏幕坐标的。
正因为这一套流水线操作的通用性和规范性,各种3D渲染引擎都将它封装了,而当代很多先进的显卡都将其固化到硬件线路上,这样大大提高了渲染速度。
下面我们来看看一些具体的实施。
在计算机图形学中,坐标的变换通常是通过与一个矩阵(Matrix)相乘来实现的。
基本变换包括平移、缩放、旋转都用此方法完成,其他任何的变换,包括不同坐标系之间的互化,也都是通过这三种基本转换完成的。
因此说,Matrix无处不在,在我们的周围,就在这间屋子里。
你能在窗户往外看到它,在电视里看到它。
具体到三维坐标系中,定义某点的坐标为(X,Y,Z)则用(X,Y,Z,W)乘以一个相应的4X4矩阵就可以得到新的坐标(X',Y',Z',W'),这里的W自有用处,一般是1。
还有一点很重要,一个矩阵就代表着一重变换,而几个矩阵的乘积就代表着多重变换的合变换。
那么在这条流水线中,按规范我们至少需要三个矩阵来实现以上三步变换,也就是世界矩阵(WorldMatrix)、视矩阵(ViewMatrix)以及射影矩阵(ProjectionMatirx)。
世界矩阵有时候需要我们自己填写,根据我们的各种变换需要来填写一个D3DXMATRIX结构体(其成员就是各行各列的数值),之后通过调用IDirect3DDevice9:
:
SetTransform(D3DTRANSFORMSTATETYPEState,CONSTD3DMATRIX*pMatrix)设置世界矩阵为你填好的那个。
参数意义如下:
D3DTRANSFORMSTATETYPEState
代表你要设置的变换类型。
D3DTS_WORLD,D3DTS_VIEW,D3DTS_PROJECTION分别表示要射知识界、视图、射影三种变换
CONSTD3DMATRIX*pMatrix
指向一个矩阵结构的指针,就是你所要用到的矩阵。
后面的两个矩阵也要通过此函数设置。
D3D中,三个变换矩阵是要存放在固定位置的,每次执行流水线,D3D就依次从这三个位置读取矩阵信息,并乘以所有的点,得到新的点的坐标,这个过程是不用我们操心的。
我们调用SetTransform()就是要把填充好的矩阵放进这三个位置中的某一个,第一个参数表示了哪一个。
在设置视矩阵时,我们先要很清楚地(在脑子里或纸上)建立好“视坐标系”。
这个坐标系以观察着为原点,沿着视线方向(观察着——注视点方向)为纵深方向(也就是Z轴方向)。
仅有两个点还不足以确定一个三维坐标系,我们还需要一个参考点,能与另两个点构成某一个坐标平面。
这样的坐标系构件起来后,就可以根据两个坐标系的变换填充视矩阵了。
D3D提供了函数
D3DXMATRIX*D3DXMatrixLookAtLH(
D3DXMATRIX*pOut,
CONSTD3DXVECTOR3*pEye,
CONSTD3DXVECTOR3*pAt,
CONSTD3DXVECTOR3*pUp
);
或D3DXMATRIX*D3DXMatrixLookAtLH(参数同),区别仅在于前者用于左手系而后者用于右手系