第一章:多媒体资产管道

资产(Asset)指的是项目中那些非代码的文件,例如:

  • 3D场景、模型、动画
  • 材质球、着色器
  • 纹理(图片)
  • 音乐、声效
  • 视频
  • 字体

在游戏开发团队中,这些资产通常由美术团队负责设计和制作,再由客户端程序员导入到游戏中使用。一般过程大概是这样的:

  • 美术使用3D建模工具(例如 3DMAX、Maya、ZBrush、Blender )编辑三角网格,绘制纹理贴图,装配骨骼动画,然后导出3d模型文件。程序员将其导入到引擎,作为游戏世界的场景、NPC、玩家角色等。
  • 美术使用图像编辑工具(例如 Photoshop、Gimp )绘制、加工图片,然后导出 .tga、.png、.jpg 等文件。程序员将其导入到引擎,作为材质、纹理、特效或者UI元素。
  • 美术使用音频处理工具(例如 Audacity)加工音频文件,然后导出 .wav、.ogg 等文件。程序员将其导入到游戏引擎,作为背景音乐、动画音效、环境声效等。
  • 美术使用特效编辑器(例如 Houdini、SideFX),制作粒子特效,然后导出特效文件。程序员将其导入到游戏引擎,作为天气、技能、魔法、环境等特效使用。
  • 等等...

资产管道

“资产管道(Asset Pipeline)” 这个词的翻译有一些生硬,它指的游戏资产从美术设计到程序应用的过程。“Pipeline”本意是工厂中的流水线,在这里是一种比喻。

资产管道中的重要一环,是将美术团队制作的资产转化为引擎专用资产。这个过程需要不止一种工具,最必不可少的由引擎提供的原始资产解析工具。这些工具的丰富和易用性,直接决定了美术团队的工作效率。

一种理想情况是,设计一种适用于3D游戏开发的通用格式,美术团队通过生产工具导出这种格式,然后引擎再把这它导入到游戏中,这样就可以极大地减少工作量。

事实上,很多公司、组织、个人都在尝试设计出一种统一格式,用来把100种(虚指,不是实际数量)不同的格式统一,结果世界上有了101种格式。(哭笑不得)

例如:

  • jME3 的用户 @david_bernard_31 设计开发了一种 xbuf 格式,适用于不同3D模型的数据转换;
  • Khronos Group 推出的一种适用于OpenGL的交换模型格式,称为 glTF
  • Open Asset Import Library (assimp) 项目提供了另一种解决思路,这个程序可以导入数十种不同的资产格式,然后生成 AiScene 格式。

无论你的游戏采用什么样的资产管道,都应该遵循一定的规范流程。下面是jME3建议的基本规范:

要..不要..
把游戏所需的模型和纹理资产保存到工程的 assets/Textures 目录中。 不要直接导入工程目录以外的资产文件:游戏无法从这些位置加载资源。
把游戏所需的音效文件保存到工程的 assets/Sounds 目录中。 再说一遍,不要直接导入工程目录外的资产文件!
创建低多边形(low-polygon)模型。 不要使用高模,对于实时游戏引擎来说,高模的渲染速度实在是太慢了。
根据jME3的材质模型,只使用材质支持的纹理。例如:对于Diffuse光照材质,只使用DiffuseMap、NormalMap、SpecularMap、GlowMap。 不要使用 Materials Overview 中没有列出的材质属性。
对于每个模型,请使用纹理图集(texture atlas)和烘焙(bake)光照来合并多个纹理。 不要在一个模型中使用多个UV贴图,这将导致模型被拆分成多个网格。
将原始的3D模型资产转化为 .j3o 格式,并将 .j3o 文件移动到工程的 assets/Models 目录中。 不要直接导入原始的 Blender/Orge/OBJ/FBX 模型,导入这些未经优化的文件非常耗时,而且发布时不会被SDK自动打包成jar文件。
尽早与美术人员确定资产命名规范,并严格遵循规范来为资产文件命名。例如:为角色模型不同部位的骨骼定义命名规则。 不要随意导入从网上下载的模型或其他资产。应该修改它们的命名和组织结构,删除无用的数据,然后再导入游戏中使用。

资产目录结构

使用 jMonkeyEngine SDK 来开发项目,项目中将自动创建一个 assets 目录,用来存放游戏资产。 assets 是 AssetManager 加载资产的默认目录。

假设你的项目名为 MyGame,项目的资产目录结构如下:

MyGame/assets/Interface  # .font, .jpg, .png, .xml
MyGame/assets/MatDefs    # .j3md
MyGame/assets/Materials  # .j3m
MyGame/assets/Models     # .blend, .j3o
MyGame/assets/Scenes     # .j3o
MyGame/assets/Shaders    # .j3f, .vert, .frag
MyGame/assets/Sounds     # .ogg, .wav
MyGame/assets/Textures   # .jpg, .png; 包括 .mesh.xml+.material, .mtl+.obj,

说明:

  • Interface 存放UI相关资源,比如字体、按钮、图标、布局描述文件等。
  • MatDefs 存放材质定义文件,用来引用不同的 Shader。
  • Materials 存放配置好的材质属性文件,用来引用 j3md 。
  • Models 存放转换过的 j3o 模型文件。
  • Scenes 存放转化过的 j3o 场景文件。
  • Shaders 存放着色器代码。
  • Sounds 存放音效文件。
  • Textures 存放纹理贴图、原始模型文件。

这个结构只是一个大致的轮廓,对于每个独立项目来说, assets 目录内的结构可能很不一样。你需要进行如下准备:

  • 在开发游戏之前,你最好和美术Leader好好商量一下 assets 的具体结构;
  • 确定 assets 中主要子目录的结构,并符合一定的命名规则;
  • 确定文件命名和计数规则,所有资产文件都要符合这个规则;

举个例子,要开发一款吃鸡那样的枪战游戏,assets 的结构可能是这样的。

assets/Models/Player/     # 角色模型
assets/Models/Vehicles/   # 载具模型
assets/Models/Weapons/    # 武器模型
assets/Scenes/Forest      # 森林场景
assets/Scenes/Room/       # 室内场景
assets/Scenes/Town/       # 城镇场景
assets/Sounds/Ambients/   # 环境音
assets/Sounds/Effects/    # 效果音
assets/Sounds/Musics/     # 音乐
assets/Textures/Player/   # 角色纹理
assets/Textures/Vehicles/ # 载具纹理
assets/Textures/Weapons/  # 武器纹理
assets/...

要保存车辆的模型和纹理(命名为 Car1),也许需要创建这些目录和文件:

assets/Materials/Vehicles/Car1/Car1.j3m
assets/Models/Vehicles/Car1/Car1.j3o
assets/Sounds/Effects/Vehicles/Car1/beep.ogg
assets/Sounds/Effects/Vehicles/Car1/engine.ogg
assets/Textures/Vehicles/Car1/base_color.png
assets/Textures/Vehicles/Car1/matallic.png
assets/Textures/Vehicles/Car1/roughness.png
assets/Textures/Vehicles/Car1/normalmap.png

jME3专有数据格式

美术团队使用的生产工具多种多样,产出的文件类型也是千奇百怪。这些文件大多包含与制作工具相关的数据,而引擎只需要使用一部分就可以满足渲染需要。多数游戏引擎都会设计专有的数据格式,而不是直接使用原始文件。

以 .blend 文件为例,它是 Blender 的工程文件。其中可能包含光源、摄像机、三角网格、骨架、动画、材质球、Shader、纹理、烘焙光照、脚本、修饰器、插件参数、python脚本、自定义数据、用户UI布局等诸多信息。

jME3实际上只需要从 .blend 文件中读取到三角网格、骨骼动画、材质数据,即可渲染3D模型。如果直接在 jME3 中使用 .blend 文件,就需要开发一个专用的 Blender 工程文件解析器(事实上 jme3-blender 模块的功能就是如此),从 .blend 文件中提取 jME3 需要的数据,是一个相当耗时的操作。如果提前把它转化为 jME3 的专有数据格式(.j3o),就可以避免这些无谓的解析。

由于底层渲染引擎不同,即使 .blend 文件中包含着色器,jME3也没法直接使用。为了让模型在 jME3 和 Blender 中渲染的效果相同,就需要使用特定的 .j3md 和着色器,并仔细调整材质属性。

jMonkeyEngine 有这些专有数据格式:

格式说明
.j3o 二进制格式,jME3的专用3D模型格式,包含网格、骨骼、动画等jME3所需的数据。
.j3f 二进制格式,jME3的专用后处理滤镜(FilterPostProcessor)文件,可用于保存水面、雾化、景深、动态高光、卡通渲染、描边等特效。
.j3md 文本格式,jME3的专用材质定义(Material Definition)文件。用于引用Shader,并定义Shader所需的Uniform、Attribute参数。
.j3m 文本格式,jME3的专用材质实例文件。它存储了针对某一种材质(j3md)的各项参数,可以用材质编辑器灵活调整参数。
.j3sn jME3的专用Shader Node文件。其功能类似Unity3D的 ShaderForge,TA可以通过jME3 的 Shader Node 编辑器,以“连连看”的方式来开发着色器。

jME3支持哪些文件格式?

jME3的资产管理(Asset Manager)设计得非常灵活强大,允许用户导入任意来源、任意格式的资产数据。但是世界上已有的资产文件格式实在太多了,受开发团队精力的限制,jME3目前直接支持的文件格式并不多。

jME3支持的3D模型格式如下:

3D模型格式

格式是否支持动画说明
.obj, .mtl 不支持 Wavefront公司开发的一种标准3D模型文件格式,很适合用于3D软件模型之间的互导。
.fbx 支持 Autodesk公司出品的一款用于跨平台的免费三维创作与交换格式的软件
.mesh.xml, .skeleton.xml, .material, .scene 支持 ORGE引擎的专有格式
.blend 支持 Blender的工程文件
.gltf, .glb, .bin 支持 由Khronos Group组织推出的一种特别适用于OpenGL的交换模型格式。

如果你在上面列出的文件格式中没有找到自己团队所使用的格式,有三种解决方案:

  • 方案一:让美术通过中间工具做一次格式转换。例如用 Blender 导入 .3ds 或 .fbx 文件,再把生成的 .blender 转成 .j3o。
  • 方案二:让美术用插件导出 jME3 能够识别的格式,例如 obj、glTF、orgexml,再转成 .j3o。
  • 方案三:让程序开发 jME3 插件,使其能够直接解析资产文件。

可参考:

对于前两种情况,在转化为j3o之后,一般还需要在 jMonkeyEngine SDK 或 jMonkeyBuilder 中预览,并根据实际渲染画面来调整材质属性。

在技术允许的情况下,第三种情况是最好的。程序人员根据美术和引擎的需要,开发批量转换工具,可以极大提高美术人员的工作效率。比如我曾经开发过 jME3-3dsmax 插件、点云(Point Cloud)插件等。

注意:jME3目前对 fbx 格式的支持有bug,请谨慎使用。这个插件是由第三方个人用户贡献的代码,对一部分fbx不能完整地解析。

纹理贴图

格式说明
.jpg, .jpeg 是应用最广泛的图片格式之一,它采用一种特殊的有损压缩算法,将不易被人眼察觉的图像颜色删除,从而达到较大的压缩比。
.bmp Windows系统下的标准位图格式,未经过压缩,一般图像文件会比较大。
.png 与JPG格式类似,压缩比高于GIF,支持图像透明,可以利用Alpha通道调节图像的透明度
.tga 美国Truevision公司开发的一种图像文件格式,该格式支持压缩,使用不失真的压缩算法,可以带通道图,另外还支持行程编码压缩。
.gif GIF文件的数据,是一种基于LZW算法的连续色调的无损压缩格式。其压缩率一般在50%左右。可以存多幅彩色图像,如果把存于一个文件中的多幅图像数据逐幅读出并显示到屏幕上,就可构成一种最简单的动画。
.dds 它是DirectX纹理压缩(DirectX Texture Compression,简称DXTC)的产物。DXTC减少了纹理内存消耗的50%甚至更多,有3种DXTC的格式可供使用,它们分别是DXT1,DXT3和DXT5。
.hdr 高动态范围图像(High-Dynamic Range,简称HDR),相比普通的图像,可以提供更多的动态范围和图像细节,根据不同的曝光时间的LDR(Low-Dynamic Range)图像,利用每个曝光时间相对应最佳细节的LDR图像来合成最终HDR图像,能够更好的反映出真实环境中的视觉效果。
.pfm 关于pfm格式,从来没有官方权威的定义,但是常常在一些场合用到,如生物医学成像,红外成像等,尤其是其浮点方式的存储的位图使得其在科研和学习场合应用都很方便,Middlebury数据库中的视差图像就是以pfm格式进行存储的。

注:关于pfm格式,可以查看这篇文章。不明白为什么jme3会支持pfm这么冷门的格式,可能核心团队有人用jme3来做数据可视化分析吧。

音频文件

格式说明
.wav WAVE文件格式是一种由微软和IBM联合开发的用于音频数字存储的标准,它采用RIFF文件格式结构,非常接近于AIFF和IFF格式。
.ogg Ogg全称是OGGVobis(oggVorbis)是一种音频压缩格式,类似于MP3等的音乐格式。Ogg是完全免费、开放和没有专利限制的。OggVorbis文件的扩展名是".ogg"。Ogg文件格式可以不断地进行大小和音质的改良,而不影响旧有的编码器或播放器。

鼠标光标

格式说明
.ani *.ani是动态光标格式,它含有多个图形信息,以及各个图形的显示顺度,显示时间长度的信息,它的结构比较复杂,但每一个图形的格式则与*.cur中图形的描述方式是一样的。在多幅图片之间的关系定义上,它与Gif动画图片是很类似的。
.cur cur是cursor(光标)的缩写,格式是静态光标文件,它的格式与图标文件*.ico的格式是一致的。
.ico ICO是Windows的图标文件格式,图标文件可以存储单个图案、多尺寸、多色板的图标文件。一个图标实际上是多张不同格式的图片的集合体,并且还包含了一定的透明区域。

字体

格式说明
.fnt Bitmap Font是由AngleCode(http://www.angelcode.com/products/bmfont/)公司开发的一种字体,广泛应用于游戏开发。它一般包含 2 个文件 .png 和 .fnt。.png文件保存了文字的位图图像,.fnt文件描述了位图字体的位置,大小等等信息。
.ttf TTF(TrueTypeFont)是Apple公司和Microsoft公司共同推出的字体文件格式,随着windows的流行,已经变成最常用的一种字体文件表示方式。

注:在jME3中使用ttf,需要第三方插件支持,详见jme-truetypefont-rendering-library

着色器

jME3的底层渲染是基于OpenGL的,可以在材质中使用GLSL着色器。着色器所需的uniform、attribute变量是通过 j3md 文件定义的,需要配合起来使用。

格式说明
.vert 顶点着色器
.frag 片元(像素)着色器
.geom 几何着色器
.tsctrl .tseval 细分曲面着色器
.glsl GLSL着色器
.glsllib jME3定义的一种GLSL库文件,可以在shader中通过#include来包含它。

FAQ

问题:一定要把模型转成j3o吗?

回答:是的。.j3o 格式是针对jME3优化过的二进制格式,用于保存游戏中的3D模型或场景。

  • j3o 文件可以存储单个几何体、单个模型或者整个场景。
  • 只有 j3o 文件才能完整支持jME3的材质选项和其他特性。
  • j3o 文件可以实现无缝跨平台使用,可以自动适应不同发布平台。
  • (可选)你可以把模型的物理属性、材质、光照、粒子发射器、音源节点等东西统统保存在一个j3o文件中。
  • 通过 Java 代码或者 SDK 的“场景组装器”,你能够方便地编辑 j3o 中的属性。
  • jMonkeyEngine SDK 的自动编译脚本在工作,会把 assets 目录中的 j3o、j3m、音效、纹理等文件组合成资源包,而原始默认资产是被排除在外的。使用非 j3o 模型,可能会导致运行时异常:AssetNotFoundException

问题:怎么把模型转成j3o?

回答:可以使用官方 jMonkeyEngine SDK 或第三方工具 jMonkeyBuilder 来转换。

  • 确认你把模型和纹理都导出到了 assets/Textures 目录(或者子目录)中。
  • 在 SDK 中,右键单击模型文件,然后选择 "Convert to j3o Binary"。这将会生成一个j3o文件,而它将会引用保存在 assets/Textures/.. 目录中的纹理贴图。
  • 把转化好的 j3o 文件移到对应的 assets/Modelsassets/Scenes 目录中。
  • 现在可以在程序中使用 AssetManager 来加载这个 j3o 文件了。

这个过程确保了模型中的纹理路径都是正确的,同时保证 assets/Models 中只包含模型而不包含纹理,这样你就可以在其他模型中复用这些纹理贴图。

问题:美工告诉我jME3的材质太low了,只能用Diffuse光照模型,连最流行的PBR都没有。

回答:请确认你的jME3已经升级到 3.2.0 及以上,并且使用的是 Common/MatDefs/Light/PBRLiging.j3md 而非 Common/MatDefs/Light/Lighting.j3mdPBRLighing.j3md 材质支持 BaseColorMap、MetallicMap、RoughnessMap、EmissiveMap 等PBR材质属性。

问题:可以导入Hounidi制作的粒子特效吗?

回答:不能。jMonkeyEngine使用自己的粒子特效编辑器,无法直接使用Hounidi等工具制作的粒子。如果一定要用,则需要开发者自行开发扩展功能。

问题:如果美术需要的材质属性,jME3中不支持怎么办?

回答:如果美术一定要使用jME3材质所不支持的属性,请与你们团队中的TA(技术美术)沟通,专门开发美术所需材质和着色器。

问题:jME3有没有烘焙功能?

回答:没有。请在3D建模工具中直接烘焙出,jME3可以使用烘焙好的LightMap。

问题:为什么要把原始模型文件放在 Textures,而不是 Models 目录?

回答:Blend/Orge/OBJ等原始模型文件是不建议直接在jME3程序中使用的,这样做只是想把它们的纹理存放在 Textures 目录。在把原始3D模型转化成 j3o 以后,你应该把 j3o 移到 Models 目录中,而 j3o 会引用保存在 Textures 目录中的纹理贴图。

问题:不用jMonkeyEngine SDK开发,应该如何建立 assets 目录?

回答:AssetManager 实际上是默认从 classpath 下加载资源的,只要任意建立一个assets目录,将其添加到 Java 工程的 classpath 中即可。不用 SDK 的唯一问题是,你要自己进行资源打包。

问题:我不明白什么 classpath,能不能直接告诉我怎么做?

回答:后续文章将详细回答这个问题。