第9章 3D游戏开发
?
正如您在这本书里看到的那样,用XNA里面的2D图像就能做许多很酷的事情了。然而,得益于当今强大的显卡和处理器,最近3D图像领域已经取得了长足的进步。随便拿一款最近的第一人称射击游戏,只要您的硬件支持,在任何特定时间游戏所能达到的精细水准和屏幕上飞过的物体数目将让您为之震惊。3D图像确实是未来发展的方向,如果您想认真地从事游戏开发,这可能正是您需要花大量的时间和精力去关注的。
那么,让我们开始吧。因为在XNA里面2D图像与3D图像是有所区别的,为此本章将从无到有创建一个新项目。启动Visual Studio然后选择File→New→Project。当新建项目窗口出现后,在窗口左边的菜单选择Visual C#→XNA Game Studio 4.0,接着选择窗口右边的Windows Game 4.0作为模版。将项目命名为3D Madness,为项目选择存放目录,然后点击OK。如图9-1所示。
现在您已经创建的项目并准备好开始了。让我们看看XNA中2D游戏与3D游戏编程的一些主要差异。
?
图9-1 为您的3D游戏创建一个新的项目
?
坐标系
?
当您处理3D图像而不是2D图像时,您首先注意到的就是前者多了一维。嗯,确实如此。您考虑过这意味着什么吗?我不是故意要使得您晕头转向,但是从2D向3D过渡确实要花时间去适应,这往往使人感到彻头彻尾的困惑、满头雾水。
在XNA里面编写2D游戏非常类似于在画布上绘图:您在一个二维空间里面绘画;坐标原点(0, 0)在屏幕的左上角,X轴向右为正方向,Y轴向下为正方向。
如果说在2D里面绘图就像画一幅画,那么在3D里面绘图就像用手持摄像机录制视频。3D空间的坐标是一个三维的坐标系。该坐标系有时也叫做世界坐标系,以坐标(0, 0, 0)为中心原点。与绘制二维图形不同,在原点绘制三维的物体时,您无法保证用户是从屏幕的中间,左上角,或者其它任何的地方来看您所绘出的物体。为什么会这样呢?在三维空间里面,绘制一个场景需要两个基本的组成部分:空间里面放置的物体和空间里面放置的摄像机(使它指向某一个特定的方向)。只有那些出现在摄像机里面的物体才会出现在场景中。
根据摄像机所在的位置和摄像机所指向的方向,3D游戏中在原点绘制的物体有可能出现在屏幕的中央、底部或其它地方,甚至完全在屏幕外面。
在我们进行更深入的探讨之前,先说一说3D坐标系。如果您已经对三维坐标系熟悉,您会发现通常情况下X轴以向右为正方向,Y轴以向上为正方向。但是,至于Z轴的方向就不是那么明确了。存在两种不同的三维坐标系,两者之间的Z轴正方向相反。Z轴的指向决定了坐标系的朝向,或者说是使用左右手的习惯。这两种可能的坐标系分别为:左手系,右手系。
区分左手系还是右手系的方法之一就是,伸出您的手平放,掌心向上,四指指向X轴正方向同时向Y轴正向卷起。大拇指所指向的方向就是坐标系Z轴正方向,如图9-2所示。
图9-2. 左手坐标系与右手坐标系的比较 ? XNA采用的是右手坐标系,这就意味着当您以正常的角度向坐标原点看去的时候,X轴向右为正方向,Y轴向上为正方向,Z轴的正方向指向您。 摄像机 ? 既然您已经理解了坐标系,那我们来谈谈摄像机吧。就像前面提到的那样,绘制一个3D场景就像用手持摄像机录制视频一样。您必须定义摄像机所在的位置、它的指向,以及其它各种属性。 表9-1 Matrix.CreateLookAt的参数 ?
这些属性存放在一个Matrix(矩阵)对象中。矩阵是一个非常复杂的数学概念,这已经超出本章,甚至是本书的讨论范围了。可以肯定地说,它几乎是您在3D图像中所做的全部事情的核心。幸运的是,XNA已经把矩阵的所有细节隐藏在屏幕之后,因此您没有必要去关心这一切是如何展开的。现在,只需要明白用一两个矩阵就可以表示一台摄像机就行了。
XNA中的摄像机由两个Matrix对象构成:视图(view)矩阵和投影(projection)矩阵。视图矩阵存放以下信息:摄像机所在的位置、所指的方向和角度。投影矩阵存放以下信息:视角和视觉范围等等。投影矩阵代表了从3D空间到2D平面的变换。
为创建一个视图矩阵,您需要用到Matrix 类里面一个名为CreateLookAt的静态方法。该方法返回一个Matrix对象,并接受表9-1中列出的参数。
?
先来看看每个参数的数据类型。什么是Vector3呢?就像您在二维开发坏境中用Vector2来表示坐标(X, Y)那样,Vector3代表的是三维坐标(X, Y, Z)。
接着,看看CreateLookAt方法中的第三个参数。尽管您已经为摄像机指定了位置和朝向,但是摄像机还无法决定如何在屏幕上绘出一个物体。对于一个手持摄像机,您可以把摄像机侧身甚至颠倒,它所指向的方向影响到了物体录制的方式。同样的道理也适用于XNA中的摄像机。您需要为摄像机定制一个向上的向量,这样XNA不仅知道如何放置摄像机也知道摄像机的角度。
为了创建一个投影矩阵,您需要使用到Matrix 类里面另外一个名为Matrix.CreatePerspectiveFieldOfView的静态方法。该方法返回一个Matrix对象,并接受表9-2中列出的参数。
表9-2 Matrix.CreatePerspectiveFieldOfView的参数
?
参数 类型 描述 fieldOfView float 摄像机的视角弧度,通常是45度或者π/4 aspectRatio float 摄像机长宽比,通常使用屏幕宽度除以屏幕高度 nearPlaneDistance float 当距离摄像机多近时,无法看清物体 farPlaneDistance float 当距离摄像机多远时,无法看清物体?
投影矩阵为您的摄像机建立一个视锥或者视野。本质上,它决定了三维空间中哪些区域是摄像机可见的,可以绘到屏幕上的。在该区域内的物体都可以出现在屏幕上,除非物体被出现在它们与摄像机之间的物体挡住了。处于视锥范围之外的物体不会出现在摄像机屏幕上。
在图9-3中,您可以看到一个假想的视锥(或者视野)。这个立体的盒子代表会出现在摄像机屏幕上的区域。该盒子之外的任何物体都不会出现在摄像机屏幕之上,不管物体是在立体盒子之前、之后还是侧面。参数nearPlaneDistance与farPlaneDistance分别决定了盒子的前方和后方,有时也称之为近裁剪面和远裁剪面。近裁剪面之前的物体或者远裁剪面之后的物体都不会出现。
图9-3 三维视椎示意图
视野的定义