cp的小屋

not yet

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

     目前大多数3D游戏都会有一个叫做“特效编辑器”的工具,美术可以通过这个工具编辑生成丰富且华丽的特效。一个特效往往由多个元素组成,元素的数量有时会达到十几个甚至更多。每个元素又可以是多种类型中的一种,如粒子系统、模型、条带、公告板等等。每种特效元素类型又有大量的可设定参数,如粒子数量,生命期,颜色、速度、位置、发射类型等等。编辑好的特效文件中每个元素的所有参数(包括参数变化方式,如关键帧)都已经设定好了,在游戏运行时只要加载这个特效文件,按预定的方式解析这些数据并控制图像引擎表现出来就可以了。仅仅这样我们就已经得到一个有强大表现力和一定灵活性的特效模块了。

 

     但是随着我们对游戏表现力要求的提高,我们不再满足于仅仅按设定好的参数回放特效效果,而是希望特效表现与游戏逻辑挂钩,使某些特效元素的某些参数随着游戏逻辑动态变化。比如我们有一个发动机尾烟的特效,其中有一个白烟粒子系统,一个黑烟粒子系统和一个公告板。我们希望让这个特效的表现对应于一个逻辑变量“强度”,它是一个浮点数,用fPower来表示。我们希望随着强度不同白烟粒子系统的发射速度会变化,黑烟粒子系统的大小和生命期会变化,公告板的大小和透明度会变化。面对这样的需求最直接能想到的解决方案就是提供一种可以遍历特效内部所有元素的方法,遍历过程中根据元素的不同类型反回不同的接口,然后调用这些接口修改不同元素的不同参数。遗憾的是这个方法很差劲,怎么想都不够好,举出两个最致命的缺点,一是要开放大量设置元素内部状态的接口函数,二是根据fPower设置特效元素参数的代码必须非常了解这个特效的内部结构,它要知道那个粒子系统是白烟,哪个是黑烟,哪个是公告板,哪些元素是不相干的。

 

     下面提出一种解决方案,这种方案目前只是设想,并没有哪个特效系统按此方案实现。但如果你理解了它会觉得它是非常强大且灵活的,同时保持了特效系统和引擎其它部分间的低耦合,你可以很容易的将这种方案实现在其它引擎中。

 

     为了便于理解,你需要时刻注意这种方案和图形API的Shader系统中常量寄存器的用法很相似。我们为每个特效对象开辟一个10个单元的Vector4数组(就叫Constants[]吧)作为特效对象的常量寄存器数组,数组每个单元的内容可以解释为一个3d向量、一个颜色、四个浮点数、四个整数。对于编辑器所有可以编辑的特效元素的参数都可以选择绑定到常量积存器之一(比如Constants[0]),也可以选择不绑定。如果参数是浮点型的就取出Constants[0].x来用。如果参数是3d向量就取出Constants[0].xyz作为vector3类型来用,如果是颜色就作为vector4来用。绑定的方式可以选择几个固定方式之一,比如相加、相乘或者替代(也就是赋值)。这样特效播放时这个参数的实际取值是特效编辑器中设定的值与绑定常量寄存器中的值运算后得到的。前面的例子中游戏逻辑可以每帧将强度值fPower设定到特效的常量寄存器Constants[0]中,特效编辑器中将白烟的发射速度参数与Constants[0]绑定,黑烟的粒子大小和生命期与Constants[0]绑定,公告板的大小和透明度与Constants[0]绑定,绑定方式都设为相乘,这样当游戏逻辑的fPower变化时特效系统会按编辑器设定的方式改变相关元素的相关参数,游戏逻辑不需要了解特效内部结构,特效也不需要访问逻辑对象索取它关心的值。

 

     使用这种方法,逻辑与特效的耦合度极低,逻辑不需要知道特效内部的组成,特效也不需要调用引擎或者逻辑的接口索取数据。比如我们希望特效内部的某些位置参数与某NPC的位置同步,只需要逻辑将NPC的位置设定到特效的常量寄存器,同时通过特效编辑器将这些参数与此常量寄存器绑定,并将绑定方式设定为替代。

 

     目前这种方案还只限于理论,还有很多可以扩充和完善的地方。比如绑定方式可以扩展出更丰富的类型,甚至用表达式或者脚本替代之。对此文感兴趣的朋友如果有什么好的、新的想法可以和我交流。

posted on 2008-10-30 15:26  cproom  阅读(2146)  评论(7编辑  收藏  举报