《XNA高级编程:Xbox 360和Windows》3-2

3.2管理内容管道

      正如您在第一章中学到的,内容管道主要用来导入游戏资源,比如 texture 、模型、 shader 和声音文件。和 Visual Studio (或 XNA Studio )使用的其他文件不同的是,内容文件不仅仅是被添加到项目中就没事了,它们会被处理并编译成二进制内容文件,然后在游戏中加载它们(如图 3-1 所示)。
《XNA高级编程:Xbox 360和Windows》3-2_第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 自带的画图工具,而且还有成千上百个其它画图工具和程序可以使用。另外,您也不知道到底要提取哪些数据,很多格式都“多层”结构,设计人员可能想让每一层都可用,或者干脆把所有东西都合并起来。

受支持的文件格式

      不要任何东西都用,您要选用一种可用的处理器以及受支持的文件格式,如果需要的话您还可以写自己的内容处理器(详见第七章):
  • Texture格式:.dds.png.jpg.bmp.tga ——基本上您可以使用.Net Framework或者DirectX加载任何东西。为了获得最佳质量,输入格式通常不要进行压缩。高压缩的.jpg文件非常不好,尤其是使用DXT对它们进行再压缩。不过,您可以对输入文件应用恰当的输出压缩(比如应用DXT压缩的dds文件),然后在内容文件属性中进行相同的设置(在我的项目中都是采用这种方式来处理大多数内容文件)
  • 声音和音乐格式:.xapXACT音频项目)——XACT中您只能导入.wav格式文件,但可以设置很多特效和参数,并选择适用于Windows平台的ACPCM压缩格式或者适用于Xbox 360平台的XMA格式。详见第九章。
  • 3D模型格式:.fbx.x模型文件——DirectX SDK中的很多示例和教程都使用.x格式。DirectX提供了很多现成的类来方便地加载.x文件。大多数.x文件应该也可以在XNA中正常使用,主要区别是DirectX.x文件通常不使用shader,而XNA却总是使用。要从3D Studio Max中导出模型文件,可以使用Panda DirectX导出器,可以在这里找到Panda DirectX导出器插件:http://www.andytather.co.uk/Panda/directxmax.aspx
    .fbx是一种比较新的格式,最初是由Alias3D模型工具Maya的开发商)开发的,后来Alias又被Autodesk3D Studio Max和很多CAT程序的开发商)收购了。.fbx意思是“Universal 3D Asset Exchange”,它是Autodesk公司免费的跨平台内容交换格式,新版3D Studio Max 9Maya都支持它。另外还有很多其它的3D内容制作程序也支持.fbx格式的导入与导出。在XNA中这种格式特别适用于动画模型、骨骼和皮肤。它还支持更多的选项,但对shader却不好使,因为无法导出materialshader设置。
    .fbx格式的另一个问题是缺少格式规范,而且要使用SDK还必须得加入Autodesk Developer Network,每年还要交纳会员费。如果您看看其它交换格式,比如Collada,会发现它们更开放,也更容易扩展。同时由于它们不是由一家公司开发的,经常会增加新的内容和特性。过去Collada不支持shader设置,但现在的版本对3D数据的支持非常好,可以导出tangentshader设置以及游戏需要的任何东西。不幸的是,XNA不支持Collada格式,我也无法说服Microsoft来支持它。最初XNARacer使用的模型、track以及landscape都是使用Collada,但后来都被换成其他的格式以支持内容管道。
  • 其他格式——您可以导入自定义文件格式,比如XML文件、二进制文件,甚至写自己的自定义处理器。如果您有一个大的项目而且值得付出很多努力,或者您需要使用一种特殊的模型格式而XNA又不支持,那使用自己的自定义文件格式会很有帮助。例如,游戏Quake3/Doom3使用了md3/md5文件,如果您只是导入一些模型来测试或者玩玩,使用md5导入器会是一个不错的选择。
     如果您有更多的内容文件或者自定义的数据,您可以写一个自定义的处理器,然后在项 目中使用导入的编译过的数据,或者按照老方法自己加载内容文件。例如,本书最后几章您要写的一个竞速游戏,它就使用了一个从 bitmap 文件导入的带有高度值的 landscape 。为游戏处理 bitmap 文件和输出 landscape 高度值或许是可以的,但有很多工作要做——如果仅仅加载高度值会容易得多,而且只需要一次。

优势和不足

     内容管道的另一个缺点是,被编译过的内容不能再被修改。一旦您启动游戏或者把游戏部署到客户端电脑上或 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 只有两个。
《XNA高级编程:Xbox 360和Windows》3-2_第2张图片

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 所示)。
《XNA高级编程:Xbox 360和Windows》3-2_第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 所示):
《XNA高级编程:Xbox 360和Windows》3-2_第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 。在下面几章中使用默认值即可。
《XNA高级编程:Xbox 360和Windows》3-2_第5张图片

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

你可能感兴趣的:(windows)