在实现了人物模型以及动画的加载之后, 分析天龙八部内场景是如何构造的, 并且使用 Ogre 1.9 重新实现场景内容(天龙八部源码是基于 Ogre 1.6 部分, 需要修改相关源码).
场景文件组成
通过源码分析, 一个场景主要分为几个文件, 主要有 .scene 文件, .terrain 文件, .GridInfo 文件, 其他文件之后再分析.
scene 文件
主要用来设置场景对象的内容, 该对象主要有环境对象, 光源对象, 天空穹对象, 静止物体对象, 粒子对象, 流动地形对象, 并且包含了地形文件的文件名称
terrain 文件
包含地形大小信息, 高度图的文件名称, 网格信息文件的名称, lightmap 文件的名称. 并且设置了所有要用到的纹理图像, 以及 pixmap 信息, pixmap 为一张纹理的一部分内容, 可以用来设置不同的地形, 比如石头路, 草地之类. 最后还有地形的材质, 这些材质分所写的着色器, 都是很简单的光照计算以及多层纹理贴图.
heightmap 文件
地形的高度信息, 表示地形上一个网格单元的高度, 而后多个网格组成一个瓷块(tile), 而后多个 tile 组成整个地形.
gridinfo 文件
每个网格的信息, 主要是每个网格单元使用的 pixmap 索引(有两层), 网格的方位信息.
场景文件的加载
XML 格式的处理
对于 scene 文件和 terrain 文件部分, 其主要是 XML 格式, 代码里面主要通过 expat 库来分析文件. 在 Fairy::ExpatParser 类内设置 XML 文件通过哪几个函数处理 XML 节点的开始和关闭, 而后在这些函数内分析出节点元素和属性, 而后发送给不同的 Handler 类来处理不同类型的 xml 文件. 例如 Fairy::SceneXMLHandler 处理 scene 文件, Fairy::TerrainData_xmlHandler 类处理 terrain 文件.
其他格式的处理
主要是二进制格式和图像格式, 例如高度图, 其图像格式由于因为保存的是整数信息, 因此每个像素取出来的值还要除以最大整数得到0到1之间的浮点数. 至于二进制格式, 一般直接读取相应位置的浮点数.
对象的管理
对象的管理主要通过两个类来管理, 分别实现不同的功能.
Fairy::PropertyInterface
由于场景的内容多种多样, 相同种类的对象也有不同的属性, 这些属性都在类中使用数据成员保存. 因此代码内使用了一个统一的接口管理所有场景中对象其数据成员的设置, 即 Fairy::PropertyInterface 类. 所有对象都由该类派生而来.
主要原理: 在类的内部保存了命令的列表(Fairy::PropertyCommand类), 对于每一个对象类, 都必须派生命令类, 而后使用命令的实例单独设置对象的一个属性值(数据成员值).
举例: Fairy:;EnviromentObject 类继承自 PropertyInterface, 从 PropertyCommand 派生了如下这些类, FogModeCmd 类设置环境中的雾, ColourRGBMemberCommand 的不同特例类设置环境中的环境光, 背景颜色, 雾颜色.
Fairy::Object
该类主要负责对象的创建和销毁, 主要通过 createRenderInstance() 和 destroyRenderInstance() 方法创建和销毁每一个对象. 每个 object 的派生类中都有工厂类, 通过一个管理器, 注册每一类对象的工厂类, 这样分析 scene 文件的时候, 可以根据不同的对象种类调用不同的工厂, 每个工厂会创建出其相应的对象. 而后在之后渲染场景的时候, 直接遍历每一个对象, 创建其场景中的相应内容. 例如有 Fairy:;EnviromentObject::Factory 类.
保存工厂实例的时候, 有个技巧, 由于工厂是长时间存在于程序中, 因此代码内使用类的静态方法内部的静态变量来保存工厂的实例, 这样还可以方便工厂的唯一性, 不会创建该工厂的多个实例.
Octree 场景管理器的使用
分析地形时, 一直考虑TLBB代码是如何优化场景的显示, 如果一个场景全部渲染的话, 游戏运行速度会非常慢. 通过代码分析可知, 一个地形划分为多个 Tile, 每个 Tile 都是由 Ogre::MovableObject 派生的类来管理, 因此, 我们除了使用高度图数据以及纹理信息设置每一个 tile 的数据之外, 我们还要设置每一个 tile 的 AABB, 而 Octree 场景管理器则会使用相机的平截头体和这些 tile 的 AABB 信息来判断该 tile 是否可见. 这样渲染的时候, 不是所有的 tile 都需要进行渲染. 对了避免无限制大小的场景对场景管理器的影响, 整个地形的 AABB 信息也应该发送给场景管理器, 让其自动优化判断过程.
中文路径的解决
由于代码所使用 resources.cfg 内使用了大量的中文路径, 而读取 cfg 的时候, 会产生错误的乱码, 这次我们需要把字符转换成 UTF-8 代码, 只需下面的一行代码解决 cfg 读到的乱码问题即可
archName = boost::locale::conv::between( archName, "GBK", "UTF-8" );
实现部分
苏州地图
桃花岛地图
Ogre角色游扬州 ** Ogre角色游杭州**