zoukankan      html  css  js  c++  java
  • Ogre 场景管理器

    转自:http://blog.sina.com.cn/s/blog_694aab1b0100rdvm.html


    在通常的情况下,Ogre的场景管理器会负责处理以下事情:

    ·在场景中创建和放置活动物体、灯光以及摄像机,并维护他们的在场景图中的周游和变换。

    ·载入和布置世界地图(World geometry,与活动实体不同,世界地图是巨大且可以延伸的,通常情况下是不可移动的,比如一个完整的BSP地图)。

     

    ·对场景查询(Scene Queries)的支持,比如回答“在世界的某个原型空间内,都包含了那些物体”。

     

    ·剔除不可见物体并且将可见物体放入渲染队列。

     

    ·根据当前和渲染物体的透视图,对无方向的光源(NondirectionalLight)进行组织和排序(按由近到远)。

     

    ·设置并且渲染场景中的阴影。

     

    ·渲染场景中的其他物体,如背景和天空盒

     

    ·发送组织好的内容到渲染系统执行渲染

     

    场景管理器类型

    在Ogre的论坛中经常有人问这样一个问题“我们已经有了场景管理器可以使用了,为什么还要有‘场景类型’概念呢?”这里可以简单的回答一下这个问题:因为Ogre中所使用的场景管理器事实上是以插件的形式提供的,这就代表着在同一个程序中可能存在着多个场景管理器。如果你是这样一个游戏,既有室内的密集空间,又有室外的稀疏场景。这时候你可能需要为每一种世界地图使用不同的场景管理器来进行具体的管理(不同的管理算法适用于不同的情况,后面将会具体介绍)。

     

    每个场景管理器插件都会向Ogre系统注册一个用来产生管理器的工厂实例,并且同时注册一个代表场景管理器的创建类型的字符串ID到系统中。作为历史遗留的原因,为了兼容早期版本的使用方法,插件也同时向系统注册了一个代表它自己的掩码ID(mask identifying)。

     

    注意:如果你是从当前版本才开始接触Ogre的使用者,你可以跳过这个段落继续阅读。但如果你有使用早期版本Ogre的经验,你就要注意这里的问题:从Ogre1.2(Dagon)版本之后(也就是本书所介绍的版本)。多场景管理器能支持场景管理器把自己的类型注册为字符串ID(比如“OctreeSceneManager”或“TerrainSceneManager”)。这样你就可以使用迭代的方法在管理器中找到自己所需要的具体实现,亦或者可以简单的使用最后一个被注册进来的管理器类型。不同于之前Ogre版本中使用枚举类型作为索引(如TR_INTERIOR或者ST_EXTERIOR_CLOSE),使用这种方式注册和索引可以让用户摆脱只能使用固定数量场景管理器类型的限制。不过当前Ogre仍然可以对以前的使用方法兼容,所以就算你仍然坚持使用以前的方法,也不会有什么问题。

     

     

    你可以自己创建一个场景管理器实例,并为它提供一个名字(也可以让Ogre帮你分配)。不过通常情况下,你需要在代码中保存一个指向场景管理器的指针,因为在大多数情况下只有一个场景管理器名字可能不怎么够用。

     

    Ogre自身提供两个场景管理器类型:OctreeSceneManager和TerrainSceneManager。OctreeSceneManager是一个通用的场景管理器。TerrainSceneManager是一个为高度场场景优化的场景管理器,我们将在之后的章节中具体的了解它们相应的细节。

    对于程序的开发者而言,场景管理器的直接用途一般是用来创建场景中所使用的对象,比如:灯光、摄影机、实体、粒子系统以及公告栏这些活动物体,以及天空盒、静态几何体和世界地图(World geometry)这些非活动物体。对于场景中存在的物体,不论是否能被渲染,都会交给场景管理器进行具体的管理工作。这样做的好处就是场景管理器可以根据自己的需要对物体进行相应的优化处理(例如,可以在你场景管理器的具体实现里面对摄像机进行有针对性的优化工作)。注意,这里的“管理”指的是对场景中物体整个生命周期的管理:提供了创建、获得、销毁以及销毁本类型全部实例的方法。任何从场景管理器得到的对象必须由同一个场景管理器销毁:换句话说,不可以直接“删除”任何有场景管理器创建返回给你的指针所指对象。当你需要释放和清空整个场景的时候,必须让相应的场景管理器自己来做(也可以让Ogre的Root对象在关闭的时候自动得帮你调用相应的方法)。

     

    场景节点

    场景管理器用场景节点来定义场景图的结构。这些场景节点以层次的结构组织在场景管理器中:一个场景节点可以有一个父节点和任意数量的子节点。你可以对场景管理器中的节点进行绑定或者摘除操作;这里提供一个简单的办法来关闭场景中的某个部分:只要把不希望渲染部分的根节点从场景图中摘除下来,这个部分就不会被渲染了。场景节点必须通过创建它们的场景管理器来销毁

     

    小心:虽然这么做不会导致Ogre系统崩溃,不过当你删除了还有内容或者数据挂接在上面的场景节点的时候,还是需要人为来保证这个被挂接的对象不会导致内存泄漏。尽管你可以根据你自己的需要随意管理所需的节点的生命期,不过同时也许要你对这些“脆弱”的场景节点行使谨慎而严密的相关处理。



     

    在场景管理器创建的时候,会给整个场景提供一个总的父节点:场景的根节点(Root Scene Node)——场景中唯一没有父节点的场景节点。根节点的概念对整个场景图至关重要,所以用户无权销毁它。对于场景图来说,根节点的显式作用可以用来挂接所有场景中存在的其他节点;隐式作用是场景图用它来挂接静态物体和整个世界地图。尽管你可以移动根节点,但尽量不要这么做,因为大多数时候都需要保持根节点的稳定性。



     

    场景中新建立的节点必须作为子节点挂接在已经存在的节点上面。这就意味着,第一个放入场景的节点,必须挂到根节点上面,然后再不断挂接扩充,直至形成一个你所需要的场景树状结构图。图5-1中展示了经过几次挂接后场景图的层次结构。

     


    在你创建了一个场景节点之后,场景管理器不会往上面挂接任何内容。当你需要的时候,应该自己创建内容并向需要操作的节点挂接。不过并没有要求场景中存在的节点一定要有绑定内容在上面,你可以挂接一个空节点,并可以根据需要时随时挂接内容到它上面。单独的节点上面并没有限制帮定内容的数量。你可以把所有内容对象都帮定到一个节点上面,不过这也就意味着无法单独的移动它们(如同连体婴一般)。

    就像我们之前所说,场景内容独立于场景节点。你可以把场景内容从场景节点中分离出来,这样的操作并不会引起场景内容的销毁或者删除。但还是不能把一个场景内容同时挂接到两个以及两个以上的场景节点上面,也不能让一个场景节点同时挂接到两个父节点上面,这些操作都会引起Ogre的内部异常。

     

    在这里你必须了解:在场景图中有三个重要的空间操作(移动、旋转、缩放),它们的操作目标都是场景节点,而不是场景内容。换句话说,用户操作场景节点,场景内容跟随着所挂接节点一同移动、旋转和缩放。

     

    场景查询

    场景管理起另外一个很重要的功用就是用来进行空间场景查询(从场景中得到查询的反馈信息),其中包括:光线查询(Ray Queries)、球体查询(Sphere Queries)、边界盒查询(Bounding-Box Queries)、边界平面查询(Bounding-Plane Queries)以及相交查询(Intersection Queries)。其中光线查询返回与给定光线(空间中两点组成的虚拟线)相交的物体信息;球体查询返回给定球体(通过球中点和半径确定的空间区域)中所有包含的物体信息;边界盒查询返回给定轴向包围盒(通过两个三维向量作为对角点产生的与空间轴平行的长方体空间)中所包含的物体信息;边界平面查询返回与给定的无限延伸的平面相交物体的信息;相交查询返回与指定物体相交的所有物体信息。

     

    这些查询的结果都是随着场景变化而变动的,所以当你要解决类似地形跟随关卡的时候,就需要在每一帧对地图执行相关的查询操作。

     

     

    提示:地形跟随的概念指的是在某些场景中需要某个对象与世界地图(通常是室外场景)保持一个固定距离(通常是零)。要实现这种动作需要知道所在地形的垂直高度,简单的作法是利用一条射线(光线检测)射向地面,得到与世界片段的交点。然后通过与世界的相对高度来设置对象的高度。这是一个很普遍的技术。(举一个简单的例子:在《三角洲特种部队》中,士兵作为场景中的物体,在移动时脚一定要和起伏的地面接触,也就是要让人物和地图保持一定的距离。)



     

     

     

    这里所提到的所有查询过程都已经进行了很好的优化(比如采用轴向包围盒的原因,就是因为它比一般的包围盒可以使用更少的计算量)。所有的查询过程都是可进行屏蔽操作的(Maskable),这意味着你可以通过这个功能过滤到你不需要的对象。据个例子来说,你需要得到一个给定球体空间内所有的物体,但是不需要里面的地形信息。你就可以在执行前通过设置屏蔽信息来过滤掉地形片段的返回。

  • 相关阅读:
    koa2学习(二) 中间件router
    行内元素与块级函数的三个区别
    Mobile Matrices
    jquery中attr()与prop()函数用法实例详解(附用法区别)
    jquery 鼠标右键事件、左键单击事件判定
    JS回调函数(callback)
    js关闭当前页面 (窗口)的几种方式总结
    em(倍)与px的区别
    jQuery学习笔记
    通过JS判断联网类型和连接状态
  • 原文地址:https://www.cnblogs.com/nafio/p/9137699.html
Copyright © 2011-2022 走看看