`
micheal19840929
  • 浏览: 167406 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

游戏引擎十大核心竞争力 之 (一)场景分割(alpha纯预览版、持续更新)

阅读更多

游戏引擎中最关键的问题之一,是场景管理技术;其中,最基础的部分,就是场景分割。场景分割要解决的几个问题如下:

游戏场景是一次载入还是需要实时的流载入
游戏场景场景过大而无法一次载入的时候,怎样一次载入一部分
一次载入一个部分,这个部分怎样定义,根据什么原则
对于已经分割的场景,动态物体在移动的时候,在各个分割之间移动是如何处理的(尤其类似碰撞检测的功能)
编辑器怎样创建一个场景,怎样动态的管理场景的大小,是否支持场景的合并和拼接
物理系统的场景需要怎么处理,是和图形场景一致的么?
本文的目的,就是讨论上面的几个问题,并给出我现在的理解。

描述世界
描述世界,就是定义游戏场景的层次。如果游戏场景很小,只是一次载入,只需要一个octree或者其他什么乱七八糟的【分割树】就可以了。我们先给这个方法定义一个名字,叫【白痴型-单场景-单分割树】。如果场景无法一次载入,也有不同的选择。选择1. 一个超大的场景,还是只用一个octree表示,只是octree的深度会根据场景的大小变得不同,在超大的场景中,这个深度会很恐怖,我们定义这个方法为【蛮力型-单场景-单分割树】。选择2. 就是对选择1的优化,对于octree的子结点,进行了压缩或者动态的分配,而不是一次分配一个极其恐怖的庞大的分割树,我们定义这个方法为【智力型-单场景-单分割树】。选择3.这个也是最常用的,场景分成多个子场景,也就是多个小的level,游戏进行中,就只是加载一部分的level,对于活动状态的level,也是加载其中的一部分,世界描述的逻辑定义,就是这样,至于碰撞检测、可见性分析等等,都是和单场景没有区别,所有的东西,都在一个树里面,我们把这个方法定义为【多场景-单分割树】。选择4.世界描述的逻辑定义和选择3一样,也是多个level,只是分割树也是多个的,而且分割树基本上都是和level一一对应的,我们定义这个方法为【多场景-多分割树】。选择5.有些比较蛋疼的方案,用了这样的中间过渡的方法,主要是针对室内和室外处理方法的不同,即使同一个区域内,也有可能出现两个不同的分割树,我们定义这个为【妖蛾子-单场景-多种分割树】。当然,不止这样几个方法,但是没有列举出来的方法,都是这些没有太大的区别的,已经列举的方法,基本上就是几种排列组合中最典型的。接下来就具体说明各种分割的方法:

【白痴型-单场景-单分割树】:动态物体的移动,只需要处理在【分割树】内部结点、层次结点之间的移动。编辑器的要求也会相对简单,创建场景的时候,就规定好整个场景的包围体,可以选择规定物体不会被允许移出这个包围体。

【蛮力型-单场景-单分割树】:动态物体的移动,同样只需要处理【分割树】内部的节点,层次结点之间的移动,但是当树的深度增大的时候,这个计算量是几何级数的增加,而且,这个几何级数的基数还不一定是2,有时候会是8,如果你是用octree的话。编辑器在控制场景大小的时候,也不好做,究竟支不支持动态的扩充呢,还是必须要固定大小呢?

【智力型-单场景-单分割树】:相对前者,针对一个庞大的树进行了优化的处理,一般就是【动态展开】的方法, 只在相机所在的地方,树的深度,才是最大化的,看不见得大结点,连子结点都不给分配;一个结点移出视线的时候,也释放他和他的子结点,保证树的整体空间最小。这样进行可见性判断、碰撞检测的时候,复杂度就低的多得多,复杂度就是BIG-Oh(n),具体来说,n的多项式系数,就应该是树分支数k(八叉树就是8,kd-tree就是k),与一个和视距相关的常数c的乘积。编辑器方面的问题,和前者同样纠结。

【多场景-单分割树】:这种划分方法,好处就是,分割树只是一个容器,多场景系统不停地往里面拿东西和放东西,而树本身的任务很简单,就是可视性判断和碰撞检测。

【多场景-多分割树】:不一定必须是一种分割树,可以是多种分割树。所以分析算法复杂度就省了,这个情况比较复杂。这个方法美妙的地方就是,每棵树,都可以是完整的,所以,对于开发者来说,这个地方容易实现,不需要动态的展开树,或者进行线性化的压缩,而且,针对不同类型的子场景(室内和室外),可以选择最合适的树;对于复杂场景,可以选择更深的树,简单场景,就只需要稀疏的,层次很浅的树。当然,缺点也不少,最核心的一点,就是物体移动的问题,这个问题,不仅在编辑器内很难搞定,而且,在游戏运行时,还更纠结。比如,一个物体从一个子level移动到另一个子level,需要处理物体再分割树之间进行穿梭;如果物体同时处于两个场景的包围体中,怎么办,根据什么原则进行优先级的选择该放到哪个场景的分割树中?能够简单的归到上次所在的场景中这么简单么?有特殊情况么?在游戏运行时,如果一个物体运动到另一个场景中,然后,物体之前所在的场景被运行时归为非活跃关卡,紧接着,这个已经非活跃的关卡再次被加载的时候,会不会多出一个物体出来,就是那个不该在原地出现的物体?

【妖蛾子-单场景-多种分割树】:要处理室内和室外,是需要两棵树,这个是必须的,但是为什么不干脆把这个弄成两个子场景呢,做的时候也可以分开做,只需要在编辑器内进行一次导入,匹配好相对位置,甚至,可以学习cryengine的,分成layer,即使是同时出现在编辑器内,也是有一个严格的划分。所以,这样弄,只是一个过度的方案,完全可以继续做成【多场景-多分割树】,如果只是单场景,他就有所有单场景划分的缺点,和所有多分割树的缺点,这个方案,还能更奇葩一点么?不过的确使很多商业引擎还真这么弄了,只是现在的引擎,这样弄的越来越少了。

上面的讨论,我没有提到物理方面,这个问题,我还没有想明白,各种选择都和开发者的特殊需求相关;对于我来说,我使用第三方的物理引擎,havok和physX,两个引擎都倾向于让游戏对象管理-图形对象管理-物理对象管理,都是用同样的场景划分,所以,game world,分成多个level,每个level对应了一个graphics scene,一个physics scene(or physics island),这样物体的物理坐标的描述和图形坐标的描述,可以很简单的统一,跨越level的时候,需要处理的问题,也是一致的,可以尽量保证改变在同一个地方发生。

具体的分割树算法细节
octree
 

(图片来自http://www.gamasutra.com/features/19970801/octree.htm

octree划分空间的平面,是和坐标轴正交的;对于每个结点,都是一个AABB(axis-aligned-bound-box),每个结点内部,都有8个大小完全相等的子结点。

在这篇文章里面,我们只谈到了空间的分割,而没有讲可视性判断,所以,就空间分割而言,octree不是那么的有优势,而且,很多时候,空间的利用率不是很理想,尤其是场景的广度比较大(水平方向的),而深度(垂直方向的)比较浅的时候。具体谈空间相关的算法:

1. 静态物体、动态物体的添加:

添加一个静态的物体,首先计算这个物体最终的AABB,然后看这个AABB是否在octree的根节点内部,如果在,就继续判断这个AABB是不是在各个子结点中,如果在,则继续判断。。。

如果一个开始这个AABB就不在octree中呢,对于无法伸缩的octree,这个地方,就应该是一个错误,所以,编辑器在创建、移动静态物体(甚至动态物体)的时候,必须要保证这个物体不会移出根结点所在的范围。

添加静态物体的伪代码:

bool OctreeNode::AddObject( Object *object )

{

     if ( this->aabb.Contains(object->aabb) )    // 这个物体的aabb在当前结点的范围内吗?

     {

           for ( int i = 0; i < 8; i++ )  // 继续判断这个物体是不是在各个子结点内

           {

                if ( children[i]->AddObject( object ) )  // 如果某个子结点【接受】了这个物体,则任务完成

                {

                        return true;

                }

           }

           // 物体虽然在当前结点内,但是任何一个子结点都不能完全包含这个物体,那么就把它放在当前

           this->AddObjectImpl( object );

           return true;

     }

     return false;

}

 

2. 动态物体的移动,多简单。。。

void OctreeRoot::UpdateObject( Object *object )

{

       // 打开冰箱门

       rootNode->RemoveObject( object );

       // 把大象放进去

       bool result = rootNode->AddObject( object );

       // 关上冰箱门

       object->SetUpdateResult( result );

}

 

关于空间划分的,就只有这么一点东西,每个引擎在细节的部分会有一些不同,但是核心的思想就是这么简单的。

BSP
BSP的细节,放到quake3章节中详细讨论,这里就省略了。

kd-tree
kd-tree一般都是针对碰撞检测(和光线追踪)的优化进行划分,对于图形场景,很少有用kd-tree的。kd-tree,很多地方和bsp相近,有时候很难分辨具体是bsp还是kd-tree。实际上,也有一些工具是根据kd-tree的算法,生成bsp的场景的。

Case Study-Engine
Unreal Engine 3
unreal engine 3,从04年公布到今天,经历了很长的时间,算法的细节变化了很多。我主要分析04年的版本,这个版本可以从网上获得(悄悄的说,比如verycd),能不能编译我不清楚,但是肯定是没有办法运行的,因为没有04年那个时候的美术资源,用现在的ue3的游戏资源代替也不行。因为这样一些理由,分析的结果无法那么准确。

ue3的04年的版本,是使用的【蛮力型-单场景-单分割树】,但是从设计来看,已经考虑了以后扩展成【多场景-单分割树】的方案。04版ue3,一个关卡就是一个ULevel,从代码来看,一个游戏运行时只会有一个ULevel。ULevel中有一个FPrimitiveHashBase成员,这个就是Octree的马甲,FPrimitiveHashBase的一个子类,就是FPrimitiveOctree:

 

所有关于octree的具体操作,就在类FOctreeNode中完成:

 

其他引擎基于octree的实现方法,也是和这个一样一样的,每个OctreeNode中,有一个列表,存放在这个Node下的一组Object,然后是8个子结点。

核心函数AddPrimitive

 

先检查物体是不是在世界范围内,在游戏运行时,使用SingleNodeFilter进行添加物体

 

SingleNodeFilter中,首先看子结点能否完全包含该物体的,如果子结点无法包含物体,那么就【尝试】自己包含这个物体。如果子结点可以包含该物体的,则,继续递归对于子结点的SingleNodeFilter。

【尝试】自己包含这个物体,就是StoreActor,具体实现如下:

 

如果当前结点已经包含了过多的物体,同时,这个结点还没有子结点,(同时,这个结点比定义的最小粒度的结点要大),那么划分这个结点的空间,然后把当前已经包含的物体,以及新的物体,都尝试再放到当前结点一次(因为已经分配了子结点,所以,这个时候,很多物体,有可能放到子结点中了,而另一些物体,则再次放到这个结点)。

如果该结点的分配子结点的操作不符合要求,或者之前已经分配过,那么就直接把这个新添加的物体放到object list中,同时通知这个物体,Primitive->OctreeNode.AddItem(this)【你现在已经在我里面了】 :P 

以上就是04版ue3的场景分割相关的主要算法。

接下去看06版ue3和09版ue3的改进。

06年,Unreal Tournament 3开发接近尾声,Gears Of War的开发已经进行了相当长的一段时间。GOW最大的特点就是多场景系统。

在代码中,最醒目的地方,就是多了UnWorld:

 

FSceneInterface *scene,和可视性、sorting相关的场景管理,从Level中移到了UWorld中,场景分割的场景树,FPrimitiveHashBase *Hash也从Level中移到了UWorld中,Level里面,现在还剩什么呢?

 

Level中,还剩下BSP,主要用于室内Brush的碰撞检测、静态光照、渲染等等;以及Kismet可视化脚本的对象。其他的部分,已经不直接和场景管理、尤其是场景分割相关了。但是其中有一个成员,比较让我感兴趣:

 

这个地方,很明显应该就是Unreal怎么处理跨越边界的物体,尤其是那些动态的物体的;最关键的,"streaming a level in/out”,啊哈!注意看前面提到过的,【多场景-多分割树】的难点。我相信这里会是相当纠结的(后面具体分析)。

Level中唯一和游戏对象直接打交道的地方,就是Level的父类,LevelBase:

 

所以,我们可以得到06版Unreal的场景分割的大概方法,UWorld管理Level(主要是runtime streaming),以及一些其他的乱七八糟的事务(事务相当多而且类别各异,这是unreal设计策略的一个通病),level简单的作为游戏对象的提供(从streaming的结果中得到新的游戏对象)。

Unreal 06到09在这个方面变化不大。(ps:由于我一直没有找到一个可以调试的版本,unreal的进一步介绍可能要停一阵。不过可以肯定的,unreal是这个系列中的最重要的参考引擎。)

 

CryEngine
首先说说CryEngine。。。啊。。。CryEngine~~~~ 在这么多的引擎中,CryEngine的设计是我最喜欢的,恩,甚至超过了nebula device系列。21世纪游戏引擎什么最重要?模块设计!我理解的模块设计最重要的就是两点:分层和分块。CryEngine、C4、nebula device 3在分层方面都是做的相当好的。在分块方面,ND3就开始凌乱了;C4就不清楚了,手头连个sdk都没有。CE在分块方面的划分也是非常合理。我对CE设计的全部理解,来自Crysis Mod SDK,引擎部分的代码全部只有部分头文件,一般都是公用的接口,直接动态加载DLL可以使用的。就暴露的接口类而言,设计那是相当华丽!恩,废话不说了,大家自己去看。

在应用层的场景管理,就只有这么一点点的接口,是在是没有办法分析:

 

 

Quake 3 && Half Life
Ogre
Gamebryo
Gamebryo,在这个系列中多半是反面教材。在这一辑中,gb也没有什么好说的,压根就没有场景分割的说法。和场景相关的类都放到了core appFramework中,的entity system;而且没有场景分割,所有的东西看起来都像是他们已经被分割好放到了场景中;其他的工程中,好像也没有相关的实现。而且多半看起来,这个场景管理还是倾向scene graph的(在今天看来,scene graph就是主流中的非主流),的确是挺符合Gamebryo在人们心中的形象的。

Cube 2
Case Study-Editor
gtk-radiant
World Craft( my project )
Getic
Torque 3D


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/xjyhust/archive/2009/09/01/4509286.aspx

分享到:
评论

相关推荐

    国泰君安_1128_国泰君安数量化专题之一百二十一:上市公司核心竞争力投资策略.pdf

    "国泰君安数量化专题之一百二十一:上市公司核心竞争力投资策略" 本文档是关于上市公司核心竞争力投资策略的数量化专题报告。报告从技术竞争力、产品竞争力、内控竞争力和持续发展性四个维度度量企业核心竞争力,并...

    OSG实现场景分割并多窗口合并显示代码

    "OSG实现场景分割并多窗口合并显示代码" 指的是使用OpenSceneGraph(OSG)库实现一个图形学技术,该技术能够将一个3D场景分割成多个独立的部分,并在不同的窗口中进行显示,最后通过特定的处理将这些窗口的内容合并...

    isoj2me_alpha_0_4.zip_Alpha_手机引擎_手机游戏引擎

    《J2ME手机游戏引擎:ISOMetric Alpha 0.4》 在移动设备的娱乐领域,游戏一直是不可或缺的一部分。为了满足用户对游戏体验的需求,开发者们不断探索和完善适合小型设备的游戏开发技术。其中,J2ME(Java 2 Micro ...

    角色扮演游戏引擎的设计原理

    角色扮演游戏引擎的设计原理涉及到游戏开发的核心技术,包括游戏引擎的原理、角色扮演游戏的制作流程以及具体的技术应用。首先,游戏引擎是游戏开发的基础,它是一组控制游戏运行的代码集合,类似于现实世界的发动机...

    用C++设计游戏引擎

    从给定的文件信息来看,文章标题为“用C++设计游戏引擎”,描述指出这是一个关于用C++设计游戏引擎的完整过程,具有实践价值。标签包括C++、PDF和游戏开发,暗示文章可能包含了C++编程语言在游戏开发领域的应用案例...

    J2ME斜45度游戏引擎

    在移动游戏领域,尤其是在早期,J2ME是开发手机游戏的主流技术之一。而“J2ME斜45度游戏引擎”则是一种专门用于创建45度角视角游戏的框架,这种视角在许多策略游戏和早期的动作冒险游戏中常见。 45度角视角游戏引擎...

    2D角色扮演游戏0.4.0alpha2有地图引擎对话系统等方面

    在开发一款2D角色扮演游戏(RPG)时,0.4.0 alpha2 版本引入了关键功能,包括地图引擎和对话系统,这两大组件是构建沉浸式游戏体验的基础。下面将详细介绍这两个核心模块以及它们对游戏的重要性。 首先,地图引擎是...

    OpenCV 5.0 预览版压缩包几功能模块介绍;OpenCV 5.0 预览版压缩包几功能模块介绍;OpenCV 5.0 预览版

    OpenCV 5(预览版)功能模块 一、主功能模块: (1)核心:核心功能 (2)imgproc:图像处理 (3)imgcodecs:图像文件读写 (4)videoio:视频输入/输出 (5)highgui:高级GUI (6)video:视频分析 (7)3d:三维...

    Opera 10.50 pre-Alpha 预览版 (附:中文语言包&图文安装使用说明)

    10.50 pre-Alpha版本是Opera在2009年推出的一个早期预览版,它包含了众多新特性、性能优化和改进,旨在为用户带来更佳的浏览体验。 ** 中文语言支持 ** Opera 10.50 pre-Alpha 预览版特别强调了对中文语言的支持,...

    CocosBuilder-3.0-alpha5 cocos2d-x场景编辑器

    CocosBuilder-3.0-alpha5是cocos2d-x框架下的一款强大场景编辑器,它专为游戏开发者提供了一个直观、高效的图形化界面,用于构建和设计2D游戏场景。Cocos2d-x是一款广泛使用的开源游戏引擎,以其跨平台性和高性能而...

    Cocosbuilder 3.0 alpha4 场景编辑器 Mac

    Cocosbuilder 3.0 alpha4 是一款专为游戏开发者设计的强大场景编辑器,尤其针对Mac用户。这个版本标志着Cocosbuilder的重大升级,不仅保留了原有的场景构建功能,还引入了更多高级特性,如动画编辑(包括骨骼动画)...

    Alpha Go围棋战核心源码片段

    《Alpha Go围棋战核心源码解析》 在2016年的春天,一场前所未有的围棋对弈震惊了全世界。谷歌的Alpha Go与韩国围棋九段大师李世石展开了一场五局的人工智能与人类智慧的对决。这场对决的胜利不仅标志着人工智能在...

    FB Alpha 029742 32位官方版

    《FB Alpha 029742 32位官方版》是一款专为32位操作系统设计的游戏模拟器,由官方编译并提供,确保了软件的稳定性和兼容性。这款模拟器允许用户在个人电脑上运行众多经典街机游戏,无需原生硬件设备。下面我们将深入...

    角色游戏引擎设计原理

    角色扮演游戏引擎是构建RPG的核心组件之一,它负责处理游戏的各种功能模块,包括但不限于游戏场景渲染、角色动作控制、用户界面交互等。一个好的游戏引擎能够极大地简化游戏开发流程,提高开发效率。 #### 三、游戏...

    AlphaZero-In-Unity_alphazero_五子棋AI_AlphaZero-In-Unity_missingopg

    AlphaZero是一种先进的机器学习算法,源自谷歌DeepMind的研究成果,它在2017年首次惊艳全球,通过自我对弈学习,在多种棋类游戏中达到了顶尖水平。AlphaZero的核心在于强化学习,结合了蒙特卡洛树搜索(MCTS)与深度...

    “学海拾珠”系列之二十六:基金竞争格局对Alpha持续性的影响.zip

    本篇文章将深入探讨“学海拾珠”系列之二十六中的核心议题——基金竞争格局如何影响Alpha的持续性。 首先,让我们理解Alpha的基本含义。Alpha是衡量一个基金或投资经理超越市场基准(如指数)的能力的指标。一个正...

    VB6-2D游戏引擎源码

    欢迎你加入VB6游戏开发中来,也很感谢你能够使用这个尚未成熟的Alpha游戏引擎 -------------------------------------------------------------------------- 一、目录 1、EngineSourceCodes是引擎源代码,DD_...

    内部测试预览版为 Firefox 4.0 alpha1 pre

    内部测试预览版为 Firefox 4.0 alpha1 pre

    SAR-image-segmentation-method.rar_Alpha_SAR 分割_alpha expansion_r

    为了减少alpha-expansion算法的计算量,本文在标号为alpha的像素向其它像素膨胀的过程中,先隔离非alpha类间的联系,而只考虑alpha类与非alpha类之间的关系,从而避免alpha-expansion算法需要构造辅助结点的问题,...

Global site tag (gtag.js) - Google Analytics