Pro OGRE 3D Programming 重點摘錄:
场景管理器
图3-1:Ogre中场景图和场景内容关系描述
所有的图形引擎都在使用场景图(Scene Graph)的概念来组织管理它里面可渲染的物体(我甚至怀疑外星人也在用这个)。
场景图在图形引擎中的地位是毋庸置疑的,它不仅提供了对用户在空间中查找和搜索物体提供了高速的优化,
并且针对程序库(对我们而言就是Ogre)的渲染需要,提供了相应的搜索、排序以及剔除功能。
在某些时候也被用来进行碰撞检测。在一些具体的设计里面,场景图甚至可以被所有子系统使用,比如声音和物理系统都可能依赖场景图来实现相应的功能。
在管理场景中的对象以及几何体的管理功能方面,Ogre中的场景图与其他的引擎实现的功能没有什么本质的区别。
不过Ogre并没有使用“一个”场景图,通过引擎所使用的插件机制,Ogre通常会使用一些外部“插入”的场景图算法来使用。
Ogre中提供的SceneManager类只不过是场景图的接口,你可以通过它来调用Ogre本身提供的几个不同的场景图算法,
也可以在网上找到一些Ogre场景算法的其他实现,其中包括商用的内存分页场景管理器(Paging Scene Manager——http://tuan.kuranes.free.fr/Ogre.html),
以及商用收费/非商用免费的场景管理器,比如oFusion(http://ofusion.inocentric.com)。
如果你在之前已经对一些完整的游戏引擎有一些了解,比如Torque、虚幻(Unreal)或者CryENGINE这些商业游戏引擎,
亦或者使用过某些图形渲染库,比如Irrlicht3D、TrueVision3D或者Blitz3D。
可能在你潜意识里,就会已经认为场景图里面一定应该有一个复杂的继承体系来实现所需相应的功能,所有物体都应该继承于一个“场景节点”基类。
不过如果真的这样做了的话(确实大部分其他的引擎,这样做了),你就会发当你要在场景图中扩展处理其他类型的数据时(比如声音或者物理内容),
这种设计的笨拙和固化就会暴露出来。
Ogre从核心设计之初就已经将场景结构(场景图)和场景内容完全分离,把场景图的结构和它所使用的数据节点作为平等的继承体系来使用。
这种灵活且强大的设计理念,使得多种场景图的管理方式(比如BSP、八叉树或者KD-Tree)可以灵活的替换,而不会影响具体的场景内容的实现。
换句话说,Ogre在场景图的领域,打破了传统,有了崭新的突破。
Ogre在场景图中还有另外一项即将实现的设计(计划在1.6X之后的版本实现):可以在同一时间内在程序中同时使用多个场景管理器。
我在这里大胆的预言,这种特性将在以后的几年内将会成为热门的话题。
不过不论在你的程序中是否准备同时使用多个场景管理器,你都会遇到“入口(Portalling)”问题。
可以简单的理解“入口”就是两个场景区间的分界线(比如当你从一个关卡的室内场景中看到了室外场景中的一部分,那么这个窗子就成为了所谓的“入口”)。
不论在什么时候,管理“入口”都是一件复杂且麻烦得让人头痛的问题。
不过对于Ogre而言,对“入口” 管理的责任已经交给了每个单独的场景管理器自身,引擎的使用者已经幸运的摆脱了这个问题。
场景管理器可以帮助你创建具体的场景节点(Scene Node)。所谓的场景节点就是你在场景中实际移动变换的基本单元。
它们也有自己的关联层次(可以有父节点或者子节点);
节点的操作支持三种不同的坐标系空间:世界坐标空间,父节点空间和自身空间。
所以在你进行移动,缩放,旋转的时候,可以自由选择使用的坐标空间。
场景节点可以独立于场景图存在,这里体现了场景内容独立与场景图所带来的好处:
内容不会被具体的场景图所影响,可以把它重新挂接到其他的场景图上。
场景中具体的场景内容需要挂接到场景节点上才能显示。这里所说的内容在大多数情况下指的就是实体(Entity)。
实体继承于活动对象(MovableObject),并通过场景管理器来进行创建。
如果你有已经有一个的实体的具体实例,你就可以把它绑定到已经存在的场景节点上。
基本上实体都是从硬盘上的“.mesh”文件载入的模型来构建。不过你也可以通过手动来产生具体的实体,
如果你喜欢,Ogre本身也可以帮助你构建比如平面这样的内部支持的模型构造。
当场景内容挂接到场景节点之后,你就可以通过场景节点来管理实体了,注意,是变换场景节点,而不是场景内容。
Ogre在场景图中还有另外一项即将实现的设计(计划在1.6X之后的版本实现):
可以在同一时间内在程序中同时使用多个场景管理器。
在通常的情况下,Ogre的场景管理器会负责处理以下事情:
- 在场景中创建和放置活动物体、灯光以及摄像机,并维护他们的在场景图中的周游和变换。
- 载入和布置世界地图(World geometry,与活动实体不同,世界地图是巨大且可以延伸的,通常情况下是不可移动的,比如一个完整的BSP地图)。
- 对场景查询(Scene Queries)的支持,比如回答“在世界的某个原型空间内,都包含了那些物体”
- 剔除不可见物体并且将可见物体放入渲染队列。
- 根据当前和渲染物体的透视图,对无方向的光源(Nondirectional Light)进行组织和排序(按由近到远)。
- 设置并且渲染场景中的阴影。
- 渲染场景中的其他物体,如背景和天空盒
- 发送组织好的内容到渲染系统执行渲染
在Ogre的论坛中经常有人问这样一个问题“我们已经有了场景管理器可以使用了,为什么还要有‘场景类型’概念呢?
”这里可以简单的回答一下这个问题:因为Ogre中所使用的场景管理器 事实上是以插件的形式提供的,
这就代表着在同一个程序中可能存在着多个场景管理器。如果你是这样一个游戏,既有室内的密集空间,又有室外的稀疏场景。
这时候你可能需要为每一种世 界地图使用不同的场景管理器来进行具体的管理(不同的管理算法适用于不同的情况,后面将会具体介绍)。
对于程序的开发者而言,场景管理器的直接用途一般是用来创建场景中所使用的对象,
比如:灯光、摄影机、实体、粒子系统以及公告栏这些活动物体,以及天空盒、静态几何体和世界地图(World geometry)这些非活动物体。
对于场景中存在的物体,不论是否能被渲染,都会交给场景管理器进行具体的管理工作。
注意,这里的“管理”指的是对场景中物体整个生命周期的管理:提供了创建、获得、销毁以及销毁本类型全部实例的方法。
场景节点
场景管理器用场景节点来定义场景图的结构。这些场景节点以层次的结构组织在场景管理器中:
一个场景节点可以有一个父节点和任意数量的子节点。你可以对场景管理器中的节点进行绑定或者摘除操作;
这里提供一个简单的办法来关闭场景中的某个部分:只要把不希望渲染部分的根节点从场景图中摘除下来,这个部分就不会被渲染了。
场景节点必须通过创建它们的场景管理器来销毁。
在场景管理器创建的时候,会给整个场景提供一个总的父节点:场景的根节点(Root Scene Node)——场景中唯一没有父节点的场景节点。
根节点的概念对整个场景图至关重要,所以用户无权销毁它。对于场景图来说,
根节点的显式作用可以用来挂接所有场景中存在的其他节点;
隐式作用是场景图用它来挂接静态物体和整个世界地图。
尽管你可以移动根节点,但尽量不要这么做,因为大多数时候都需要保持根节点的稳定性。
就像我们之前所说,场景内容独立于场景节点。你可以把场景内容从场景节点中分离出来,这样的操作并不会引起场景内容的销毁或者删除。
但还是不能把一个场景内容同时挂接到两个以及两个以上的场景节点上面,
也不能让一个场景节点同时挂接到两个父节点上面,这些操作都会引起Ogre的内部异常。
场景查询
场景管理起另外一个很重要的功用就是用来进行空间场景查询(从场景中得到查询的反馈信息),
其中包括:
光线查询(Ray Queries)、球体查询(Sphere Queries)、边界盒查询(Bounding-Box Queries)、
边界平面查询(Bounding-Plane Queries)以及相交查询(Intersection Queries)。
其中光线查询返回与给定光线(空间中两点组成的虚拟线)相交的物体信息;
球体查询返回给定球体(通过球中点和半径确定的空间区域)中所有包含的物体信息;
边界盒查询返回给定轴向包围盒(通过两个三维向量作为对角点产生的与空间轴平行的长方体空间)中所包含的物体信息;
边界平面查询返回与给定的无限延伸的平面相交物体的信息;相交查询返回与指定物体相交的所有物体信息。
这些查询的结果都是随着场景变化而变动的,所以当你要解决类似地形跟随关卡的时候,就需要在每一帧对地图执行相关的查询操作。
所有的查询过程都是可进行屏蔽操作的(Maskable),这意味着你可以通过这个功能过滤到你不需要的对象。
据个例子来说,你需要得到一个给定球体空间内所有的物体,但是不需要里面的地形信息。
你就可以在执行前通过设置屏蔽信息来过滤掉地形片段的返回。
场景中的活动物体(Movable Scene Object)
活动物体(Movable Object)由场景管理器创建,并且绑定到场景节点上,最后再由场景管理器销毁。
因为这些内容独立于场景图,所以可以根据需要随时从场景节点上分离或者挂接,也可以在一个节点上挂接多个活动物体。
不过需要注意的是同一时间内一个活动物体只能被挂接到一个场景节点上。
其中可以被渲染的活动动物,比如只包含几何和纹理的模型,在它们里面并不包含或处理具体的场景图信息。
而另外不可渲染的活动物体(比如进入场景中的灯光或者摄影机等),虽然并不包含任何几何体或者纹理数据,
但是它们仍然有能力简单的绘制自己(例如你可以在需要的时候让一个摄影机在场景中可见)。
以资源为基础的物体(Resource-Based Objects)
以四边形为基础的物体(Quad-Based Objects)
天空面(Skyplane)
穹顶(Skydome)
天空盒(Skybox)
渲染对象(Rendering Objects)
摄象机(Camera)
灯光(Light)
点光源(Point Lights)
聚光灯光源(Spot Lights)
有向光(Directional Lights)
你可以认为世界地图中包含除了活动物体(Movable Object)之外所有的东西,比如高度场地图,
网格地图,以及在地图上面的建筑和自然景观(树木以及植被),室内的门和窗户。
而比如怪物和场景中活动的门不属于地图本身,它们是活动物体。
可以这么理解,世界地图是角色们表演的“舞台”,是演员们存在和表演的场所。
通用的空间分割策略
场景管理器会根据设计和优化的需要,把场景中的几何体分解成一些集合来进行操纵和管理。
这些几何体集合的划分方式被称空间分割(Spatial Partitioning),其分割的依据包括每个自空间有多少个几何体才能达到稳定、
内含多少个可活动的物体、期待的密度和如何布置它们。
对于Ogre来说,对场景地图的分割会建立在物体粒度上而不是多边形本身。
这是因为Ogre 3D引擎是一个依靠硬件加速的工具,而当前的3D图形硬件中能更好的处理几何体批次,
所以针对物体的分割方式可以得到比针对多边形的分割方式更好的效率。
(分割多变形的技术更适合那些软件3D光栅化的工作,不过那是在没有图形硬件对3D变换和光照提供加速的时候)。
四叉树(Quadtree)空间分割
八叉树(Octree)空间分割
二叉空间分割树(Binary-Space Partitioning)
EX: mSceneMgr -> setWorldGeometry(terrain_cfg);
沒有留言:
張貼留言