设计日志一:保留模式的3D图形引擎

设计日志一:保留模式的3D图形引擎

一直以来,我一直坚信立即模式(Immediate Mode)是制作图形引擎的正确方式。什么时候该画什么就调用相关的函数画什么,这简直就是天经地义的。第一次听说保留模式(Retained Mode),还是在开始学DirectX的时候,大概是DirectX 5.0吧。那时DirectX有个保留模式,只要创建对象添加到场景里,之后场景会自己绘制。不过这个保留模式API非常的失败,性能非常的差,而且非常的不灵活。之后这个API就被废弃了。当时另外一个有名的保留模式API,是OpenGL上的OpenInventor。这个学过OpenGL的人肯定都听说过,但没几个人用过。

如今,随着渲染技术越来越复杂,立即模式的图形引擎已经变得很不方便了。因为不同的渲染方法需要不同的绘制流程,很多渲染算法又需要多趟(Multi-pass),而从模块设计和封装的角度看,不应该把具体的渲染方式暴露给外部,其他模块也不关心图形模块使用什么样的渲染技术。而这正是保留模式解决的问题。这也让我想到了C#向声明式编程(Declarative Programming)方向做的努力。很多时候,在高层,我们并不关心“怎么做”,而只关心“要做什么”。而“怎么做”会由特定的模块选择最优的方法来完成。

例如,我只要告诉引擎,场景里有个建筑模型,建筑上站着两个骨骼动画的人物,分别是什么什么模型,并投射阴影,他们的配剑会有镜面反射效果,光照环境参数如何,之后,图形引擎用什么方式渲染、如何剪裁、需要渲染多少个pass都是引擎自己的事。当今的最知名的开源引擎Ogre和Irrlicht都是类似这种模式。

那么,如果我要制作保留模式的引擎,就要解决保留模式的一些问题。前面说过,我之前一直不相信保留模式,最主要的问题有两个:性能,和灵活性。性能问题可能很大程度上是DirectX的保留模式造成的印象,不过使用OpenInventor也同样会比直接用OpenGL性能差很多。同样使用保留模式的WPF的性能问题也困扰着微软,以致微软在宣传上不断缩小WPF图像应用的适用范围(如今只提Business Graphics了)。不过我倾向于认为,这更多的是API设计和实现上的问题。理论上,保留模式可以非常接近立即模式的性能,但事实上非常困难。保留场景状态需要很多额外的内存空间,并产生很多的复制和循环。而立即模式下,大部分绘制参数只在绘制时计算出来,不需要保留一套场景结构。但这并不会造成致命性的差异。

真正的问题在于,保留模式是高层(High Level)的功能。对于底层的API,它们并不限制你做什么,你需要自己去决定如何使用它们,你可以针对你的特定需求做优化。而对于高层的保留模式API,它无法做到无所不能,而只能针对特定的情况做优化。也就是说,保留模式的引擎设计得越通用,性能损失也就越大。而且,总会不断地有新的需求出现,以至于需要打破现有的保留模式封装。所以,无论Ogre还是Irrlcht,都提供一些扩展的方法。

所以,如果研究一下如今的商业引擎,就会发现,它们大多使用了某种程度的混合,既有保留模式的成分,也有立即模式的成分。所以,要不要使用保留模式,就不再是个问题,问题是如何划分界限。

引擎里,保留模式应该保留到哪一层呢?先看看别人怎么做的。首先是最古老的OpenInventor。它的封装非常的底层,几乎把每个OpenGL的命令都封装成了一个对象,然后由一大堆的命令对象组成场景。理所当然的,灵活性很好,但比直接用OpenGL还麻烦,非常吃内存。再看Ogre和Irrlicht,这两个引擎已经将功能限定在游戏用的图像引擎上,Irrlicht的目标范围更小一点,它本来是更针对FPS式游戏的。两者都提供了专门的地形、天空等的对象,限定了场景的构成结构。而对人物,Irrlicht直接提供了针对角色模型的对象,而Ogre提供了较为通用的Entity,需要用户进一步构造针对角色的模型对象。大型商业引擎的针对性则非常强,往往直接提供非常完善的角色类,直接支持动作(不需要去关心动作混合参数)、挂件、换装、脚本接口、甚至一些基本物理特性。而小型商业引擎则一般提供基础的角色(Actor)支持,多于3D模型,而又不限定游戏的角色模式,允许游戏程序来扩展出具体的角色,如TrueVision、Blitz3D等。

再举个例子,场景管理。场景管理,特别是场景里对象的剪裁,是否要交由保留模式引擎来做呢?OpenInventor、Irrlicht都做了细致的场景树剪裁,Ogre可以选择或者自定义场景管理器,TrueVision和Blitz3D这类则分别对角色和场景模型做单一层次的剪裁。很明显,对于地形、建筑、人物的最合适的裁剪方案都是不同的,传统图形学的基于场景树的剪裁并不合适。另外,图形引擎并不是唯一一个维护场景结构的模块,逻辑模块、物理模块都会各自维护一个稍有区别的场景系统。而剪裁、查询等操作是在这几个场景表述中都会用到的。开源引擎中有个叫NebularDevice的,它则是将剪裁的工作几乎完全交给了逻辑部分,用户程序在绘制每一帧前将可见的对象注册到场景树上。这种方式使用起来非常像立即模式,但它确实是保留模式。

那么,我的选择是什么?首先,我要做的是主流游戏模式的小型游戏引擎,增强针对性可以简化设计并得到较好的性能。其次,场景是由天空、地形、建筑、人物组成的,引擎直接支持这些概念对应的保留模式对象,并对其各自的特征进行优化,但不涉及相关具体游戏逻辑的功能。引擎对地形提供专门的剪裁,对建筑(只作为积木模块Building Block用)、人物提供简单的包围盒剪裁。而由逻辑模块对建筑、人物做第一轮区域性的剪裁,因为这个结果逻辑模块使用得更多。图形引擎不牵涉脚本支持、不集成物理支持。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值