






















正如您在第一章中学到的,内容管道主要用来导入游戏资源,比如texture、模型、shader和声音文件。和Visual Studio(或XNA Studio)使用的其他文件不同的是,内容文件不仅仅是被添加到项目中就没事了,它们会被处理并编译成二进制内容文件,然后在游戏中加载它们(如图3-1所示)。

图3-1
过去,游戏编程人员必须得自己写内容导入器加载游戏内容数据或使用一种受支持的格式文件,比如DirectX中的.x格式的模型文件。但通常可以使用的格式要么不多,要么太慢,要么当需要给游戏添加新特性时又太死板,这就是为什么几乎每一个商业游戏都使用自己的文件格式及其自定义的处理逻辑。这有一个好处,就是只有游戏的开发人员才知道内部格式的设计,他们可以随时对它进行扩展或修改它。但用这种方式来获取3D内容却很麻烦,要做很多工作。加载texture通常并没有那么复杂,因为有很多现成的库可以使用,即使是写您自己的文件格式,也基本上只是包含一些使用24或32位颜色值的像素而已。但如果您尝试使用压缩或者使用硬件压缩(hardware-compressed)的texture(比如DXT格式)就有点困难了,不过DirectX有一套非常好的指令系统,里面包含很多有用的方法来帮助您处理这种情况。
另一方面,加载3D模型数据更加复杂,尤其在XNA中。因为在XNA中,您不仅要处理几何数据(geometry data),还要使用shader来渲染3D对象,然后还得使用material数据通知shader使用什么样的颜色、texture以及参数。在DirectX中大多数教程和示例都使用.x文件格式,但这种格式对很多项目都不适用。Especially if you use normal napping and require the geometry data to contain tangents, the .x file format will not be very helpful。You would have to generate tangents in your application and work around problems this might introduce。例如,我曾经做过的一个游戏Rocket Commander就存在这样的问题,它需要复杂的模型加载过程和切线重建过程。 对于其它的游戏数据,比如声音文件(.wav)、shaders(.fx)或者是自定义的数据(像.xml文件),它们的加载过程就比较容易理解,因为您的游戏或者您正在使用的开发框架已经提供了足够的类来快速地加载任何数据。但是,如果您把具有相同内容的游戏放到其他平台上运行,可能会遇到很多问题。例如,在Windows平台上您使用ACPCM声音文件,使用编译过的Pixel Shader 1.1文件或者.jpg文件作为texture,但在Xbox 360上却不支持ACPCM,在Xbox上声音类型要么是PCM,要么是自定义的XMA格式。同时处理shader的代码也要符合Xbox 360能接受的格式,而且加载texture的工作方式也可能不一样。如果将来支持更多的开发平台,那么这个问题会变得更加复杂。
在XNA中,为了简化游戏内容的加载,您可以直接把原始的内容文件添加到XNA Studio项目中,然后它们会自动被处理,编译成适合当前选定平台的输出格式。例如,您的声音文件可以根据您创建的XACT项目设置来进行处理——虽然得到的输出和压缩格式不同,但wave bank中所有原始声音文件都是相同的,这样就可以只在一个地方进行更新。这个想法很不错,不过它要求每一个原始内容文件格式都要被支持,但这个又很不现实,因为可以使用的文件格式类型太多,根本不知道哪些会被用到。例如,您的图形设计人员可能使用Photoshop并保存成.psd文件,而其他团队可能使用Gimp或者Paint-Shop,或者就使用Windows自带的画图工具,而且还有成千上百个其它画图工具和程序可以使用。另外,您也不知道到底要提取哪些数据,很多格式都“多层”结构,设计人员可能想让每一层都可用,或者干脆把所有东西都合并起来。
不要任何东西都用,您要选用一种可用的处理器以及受支持的文件格式,如果需要的话您还可以写自己的内容处理器(详见第七章):
内容管道的另一个缺点是,被编译过的内容不能再被修改。一旦您启动游戏或者把游戏部署到客户端电脑上或Xbox 360上,那么所有的内容文件包含的就只是编译过的数据。比方说您写了一个支持shader的粒子系统编辑器(particle editor),如果您想在编辑器运行的时候动态地改变texture、shader和其它粒子系统设置,您必须得重新加载这些texture、shader等等。但由于要先在XNA Studio中编译内容文件,所以您必须得停止应用程序,把所有这些文件添加到项目中并重新编译,等到所有内容都重新构建之后再启动程序。Especially in the case of just testing and tweaking effects or particles,这个非常讨厌而且会严重拖慢您的工作进度。如果在这些程序中不使用内容管道,只是动态地加载texture、shader和粒子系统设置将会更好。这里有一个技巧来处理大量的内容文件,我在大多数项目中都会使用:编译所有文件并确保不要频繁地更改(可以隔几天改一回)。这样您就可以使用一个虚拟项目编译所有的游戏内容,然后再把编译过的内容文件复制到实际的项目中。特别是在使用单元测试和最后一章讨论的敏捷方法学的时候,一天您会启动程序好几百次,所以每次运行都要尽可能地快。 内容管道也有优点,那就是除了XNA引擎其它任何程序都无法读取编译过的数据(.xnb文件),并且数据的加载过程也更快,因为此时的所有数据都已经是游戏所需要的确切的格式。例如,如果在内容属性中把texture保存成DXT格式文件并使用mip-maps内容处理器,那么游戏就可以快速地调用texture数据,然后把它传送给显卡来渲染,这又是一个快速处理过程。这对于3D模型数据更加重要。如果您分析一下游戏Rocket Commander,会发现加载3D模型和产生所有的附加数据以及切线数据会花掉大部分的初始化时间(超过了90%),然而模型数据比它多10倍的XNA游戏加载却比它还快。能尽可能快地加载所有数据对Xbox 360来说也是一件好事,因为控制台游戏的加载时间通常都会很短。
好了,您已经学习了很多使用内容管道的优势和不足,那么现在要把重点放在编程和很多常见问题上。如果您看看游戏Rocket Commander和Racing Game的内容文件夹目录(如图3-2所示),会发现Rocket Commander又一大堆内容文件夹,而XNARacer只有两个。

图3-2
看了图3-2,您可能会以为Rocket Commander的内容文件会比XNARacer多很多,实际上XNARacer使用的3D模型文件数量几乎是Rocket Commander的10倍,而且还包含更多的texture、音乐和声音文件。
那么您或许要问为什么Rocket Commander使用这么多的文件夹。原因是这个游戏中没有使用内容管道,游戏的每一部分都单独使用一个文件夹,这样做可以更有组织地管理这些内容,而且容易查找。例如,“Textures”文件夹包含了菜单和游戏界面使用的所有2D texture,它的子文件夹“Models”包含了3D模型texture,“Effects”子文件夹则包含了特效texture。 在XNA中您不能使用这样的目录结构,因为大多数内容文件,尤其是3D模型文件,需要递归地加载其它相关的内容文件(如图3-3所示)。

图3-3
正如您所看到的,Apple模型是从Apple.x文件加载的,而Apple.x文件又会递归地加载Apple.dds、AppleNormal.dds和NormalMapping.fx。内容处理器希望所有这些文件都放在同一个文件夹中,这迫使您不得不使用一个文件夹来存放所有的3D模型文件以及它们使用的texture和shader文件。另外,大多数shader文件还会被其它3D数据使用,所以在另外一个文件夹也存放一份这些shader的相同的拷贝会比较混乱。有时候您还需要加载自定义3D数据需要使用的texture文件,比如,在游戏XNARacer中guard rail holder模型和generated guard rail对象使用相同的texture。
不管怎样,一定要记住每一块内容必须要有唯一的名称,您不能同时使用一个名为“Apple”的模型和一个名为“Apple”的texture。正如您在图3-3中看到的,在“Input File”那一行只添加了一个Apple.x文件,其它的文件都是由模型处理器自动添加的。另外,XNA会很灵活地重命名所有的递归文件,因为它们通常会使用和模型文件名称相同的texture文件,递归文件的名称以“~0”结尾。您也无法设置这些递归文件的内容属性,因为它们不会被添加到项目中,所以要确保输入文件已经使用了正确的格式(在上述的例子中是DXT1和DXT5)。
现在您已经知道了导入内容并在游戏中访问它们。在前几章您已经访问了一些内容文件,并快速地了解了内容管道。现在您将更进一步地学习实际的处理过程,以及如何使用内容文件。在第七章,您会通过扩展X模型文件处理器(X Model File Processor)为您的图形引擎写自己的内容处理器,并添加一些有用的特性。 在第一章您已经学了如何添加texture,只要选择一个texture文件(.dds、.jpg、.bmp或.png)然后把它拖放到XNA Studio项目中。现在右键点击它来配置其Content Processor属性(如图3-4所示):

图3-4
给texture设置正确的Content Processor模式非常重要。对于2D数据,像sprite、文本以及游戏使用的所有UI图像,通常最好使用32bpp Sprite格式(未压缩的,即使用1024×1024分辨率及32bpp的texture,需要4MB存储空间)。
在一个3D游戏中,使用3D texture数据要比2D UI texture数据多得多,而且随着游戏的不同texture的数量和级别也在不断地膨胀。所以texture的尺寸得非常地小,但并不是要降低texture 的分辨率,因为这样会使游戏粗糙难看,而要使用硬件texture压缩(hardware texture compression)。您可以为颜色texture选择压缩率为1:6的DXT1格式,为包含Alpha值(或compressed normal maps)的texture选择压缩率为1:4的DXT5格式。这就是说在消耗相同图像存储容量的情况下,采用DXT1压缩的texture的数量是未压缩的texture的数量的6倍,而且还不会有太多的质量损失。另一个技巧是在shaders里合并或生成textures;例如,细节textures可以改进landscape的细节而不消耗额外的显存。 对于模型文件,目前可以使用X Model Importer或者FBX Model Importer(如图3-5所示),将来可能会有更多的格式可以使用。如果写自定义的模型处理器(见第七章),you can select them the same way you select texture processors。For normal mapping you want to select your custom XNARacer Tangent Model Processor from Chapter 7。在下面几章中使用默认值即可。
图3-5
如果您按照前两章的方式来加载texture,那么您或许已经知道了如何在XNA中来加载内容,代码如下:
backgroundTexture = content.Load<Texture2D>("CityGroundSmall");
加载3D模型也使用相同的方式,只要改变Load方法参数的类型即可:
appleModel = content.Load<Model>("apple");
显示模型稍微有点复杂,没有简单的绘制方法可以使用,必须检查所有的模型网格并更新所有shader特效,然后再渲染每一部分。更详细的内容参照第五章和第六章。在第七章中您将使用一个专门的类来加载和渲染模型,只需使用一行代码就可以把3D模型显示在3D世界中:
appleModel.Render(Vector3.Zero);
现在您已经了解了内容管道的基础知识,接下来几章将学习有关内容管道的更多内容,比如在您的图形引擎中使用自定义的Tangent Model Processor添加3D模型,以及第九章更加详细地学习XACT。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。