Ogre BspSceneManager

138 篇文章 0 订阅

1. 概览】
       Ogre支持Quake3的bsp格式。相关的代码在“Plugin_BSPSceneManager”工程中。主要的类有以下几个:

 

Class BspSceneNode:

       BspSceneNode是SceneNode的派生类,是专门提供给BSPSceneManager使用的。主要是提供针对于BSP tree的可见性判断。这个类并不是BSP tree的node,BSP tree中的node使用BspNode。BspSceneNode会放入BSP tree的leaf节点中。由于SceneNode使用包裹盒的方法,不可分割,所以一个BspSceneNode可能放入多个Bsp tree的leaf节点中。

       从类的定义看,BspSceneNode并没有额外的保存什么数据。重写的几个虚函数主要是用来通知BspSceneMapager,BspSceneNode::_update()会调用BspSceneManager::_notifyObjectMoved(),detach objcect会调用BspSceneManager::_notifyObjectDetached()。

 

Class BspSceneManager:

       粗略的看BspSceneManager与OctreeSceneManager类似。首先保存了一个BspLevel的指针,然后使用一个walkTree()函数,用来遍历tree结构。由于Quake使用BSP leaf tree,所以多了一个processVisibleLeaf()函数。另外一个明显的不同是有一个renderStaticGeometry()函数,“Renders the static level geometry tagged in walkTree”。此函数渲染“mMatFaceGroupMap”中的所有数据。BSP一个好处是不透明面可以front-back的顺序来渲染,而透明面back-front来渲染,OGRE是如何将此特性保存到MaterialFaceGroupMap的呢?

 

Class BspLevel:

       这是一个核心的class。他存储了BSP的所有数据,关键的数据有:

<!--[if !supportLists]-->1.         <!--[endif]-->“BspNode* mRootNode;”――BSP tree的根节点

<!--[if !supportLists]-->2.         <!--[endif]-->“VertexData* mVertexData;”――整个level的所有顶点;

<!--[if !supportLists]-->3.         <!--[endif]-->“StaticFaceGroup* mFaceGroups;”――faces

<!--[if !supportLists]-->4.         <!--[endif]-->“BspNode::Brush *mBrushes;”――用来做碰撞检测的Brush,是QuakeBSP除了渲染以外的另外一个精华!Brush的名字有点怪,其实就是一个convex volume,可以减少CD的运算量。

<!--[if !supportLists]-->5.         <!--[endif]-->“VisData mVisData;”――PVS数据,是又一个Quake中的精华!当初Carmark在设计Quake的时候还使用软件渲染,hiden surface removal和减少over draw是最另他头痛的问题。BSP的思想应该是他从网上看来的,不过PVS应该是他所创。PVS大大减少了over draw。(见《Michael Abrash's Graphics Programming Black Book》)

<!--[if !supportLists]-->6.         <!--[endif]-->“PatchMap mPatches;”――Quake3支持贝赛尔曲面

关键的函数:

<!--[if !supportLists]-->1.  <!--[endif]-->bool isLeafVisible(const BspNode* from, const BspNode* to) const;使用PVS来检测可见性。

<!--[if !supportLists]-->2.  <!--[endif]-->void _notifyObjectMoved(const MovableObject* mov, const Vector3& pos);
void _notifyObjectDetached(const MovableObject* mov);
à void tagNodesWithMovable(BspNode* node, const MovableObject* mov, const Vector3& pos);
把MovableObject(注意:不是SceneNode)挂到BSP的leaves上。

 

Class BspNode:

       这是Bsp中的另外一个重要的类了。Node和Leaf都使用这个类。

       重要数据:

<!--[if !supportLists]-->1.  <!--[endif]-->Plane mSplitPlane;     BspNode* mFront;     BspNode* mBack;
分割平面和前后节点;

<!--[if !supportLists]-->2.  <!--[endif]-->int mVisCluster;
每个cluster占pvs的一个bit,这是为了减少pvs占用的内存。

<!--[if !supportLists]-->3.  <!--[endif]-->int mNumFaceGroups;    int mFaceGroupStart;
用来找到BspLevel中哪些face group是属于我这个leaf的,这样做也是为了优化存储;

<!--[if !supportLists]-->4.  <!--[endif]-->IntersectingObjectSet mMovables;
和本节点相交的movable对象

<!--[if !supportLists]-->5.  <!--[endif]-->NodeBrushList mSolidBrushes;
本节点包含的brush。

另外剩下的OgreQuake3Level.h、OgreQuake3Shader.h、OgreQuake3ShaderManager.h、OgreQuake3Type.h主要是为了把Quake3格式的bsp,shader信息读入,并转换成Ogre本地的bsp定义以及Material。现在quake3的源码已经公开(非常感谢id software以及carmark),可以结合quake3的源码来看。

 

【2. Quake3 bsp的加载】
       以Demo_BSP为例,首先需要修改“quake3settings.cfg”,两个参数,“Pak0Location”是pk包的路径(是一个zip文件),“Map”为想要加载的地图。

       OGRE使用BspLevel来存储Bsp场景信息,这个类是与文件格式无关的。所以需要另外一个类来把Quake3的bsp文件读入。

       Quake3Level的读盘的主要由两个函数完成:

1、“void Quake3Level::loadHeaderFromStream()”。调用的流程是:

BspApplication::loadResources()

à ResourceGroupManager::loadResourceGroup()【A】

à BspSceneManager::estimateWorldGeometry()

à BspLevel::calculateLoadingStages()

àQuake3Level::loadHeaderFromStream()

       Quake3 BSP的文件格式很简单明了,前面是一个文件头,后面是几个数据块。文件头主要存储了几个lump,包含数据块的起始位置和大小,通过lump,可以直接seek到对于的数据块。
       此函数在加载了文件头之后,调用了Quake3Level:: initialiseCounts ()函数,主要是计算了每个lump包含的对象的个数,例如face,vertex,bursh等等。

       2、第二个函数“void Quake3Level::loadFromStream()”。调用的过程是:

ResourceGroupManager::loadResourceGroup()【A】

àBspSceneManager::setWorldGeometry()

àBspResourceManager::load()

àResourceManager::load()

àResource::load()

àBspLevel::loadImpl()

àQuake3Level::loadFromStream()

在这地方OGRE延续了他罗嗦的风格,BspSceneManager要通过BspResourceManager来加载场景,BspLevel实现为一种Resource,BspResourceManager通过标准的ResourceManager――》Resource来找到BspLevel,然后调用其加载函数。

 

此函数首先构造了一个“MemoryDataStream”对象,在MemoryDataStream的构造函数中把文件数据全部读入其缓冲中(Quake也是这样干的),然后调用“void Quake3Level::initialisePointers(void)”函数,得到所有lump索引的对象的指针。

 

Quake3Level把文件读入并明确了所有数据的指针之后,在void BspLevel::loadImpl()中调用“BspLevel::loadQuake3Level()”函数讲Quake3level中的数据拷贝到自己的数据对象中。主要执行了以下几个操作:

<!--[if !supportLists]-->1.         <!--[endif]-->“BspLevel::loadEntities()”,这个lump存的是一个字符串,用来描述一些游戏信息,Ogre的这个函数只读取了Player start信息(位置和角度)。

<!--[if !supportLists]-->2.         <!--[endif]-->“Quake3Level::extractLightmaps()”。Quake3 BSP的每个light map都是128×128大,此函数将Light map lump中的数据逐个调用“TextureManager::loadImage()”创建成Texture对象(class D3D9Texture for D3D9 RenderSystem)。

<!--[if !supportLists]-->3.         <!--[endif]-->创建VertexData:
[Create vertex declaration] OGRE BspLevel使用的顶点格式为:Position3,Normal3,Diffuse,uv0,uv1;
[Build initial patches] 调用BspLevel::initQuake3Patches()。此函数遍历Quake3Level中的所有faces,对于每个face type为“BSP_FACETYPE_PATCH”的face,创建一个PatchSurface对象,并调用PatchSurface:: defineSurface()函数进行,然后保存到BspLevel:: mPatches数组中。此函数还计算了BspLevel:: mPatchVertexCount和BspLevel:: mPatchIndexCount;
[硬件顶点缓冲] 调用HardwareBufferManager创建HardwareVertexBuffer对象;使用“BspLevel::quakeVertexToBspVertex()”函数把q3 bsp顶点格式转换为Ogre BSPLevel的顶点格式。然后绑定到BspLevel::mVertexData;

<!--[if !supportLists]-->4.         <!--[endif]-->创建Faces:创建BspLevel:: mLeafFaceGroups数组;创建BspLevel:: mFaceGroups数组,此数组的数据在后面一步中填充;创建indexbuffer,并将Quake3Level::mElements拷贝进来;

<!--[if !supportLists]-->5.         <!--[endif]-->Create materials for shaders:对于Quake3Level::mFaces每一个bsp_face_t,找到它索引的Quake3Shader,并创建Material,如果没有找到Quake3Shader的话则使用shader name去查找贴图文件;
在此循环中还进行了“Copy face data”的操作,填充BspLevel:: mFaceGroups中的数据;

<!--[if !supportLists]-->6.         <!--[endif]-->Nodes:创建BspLevel:: mRootNode数组,并将数据拷贝进来。

<!--[if !supportLists]-->7.         <!--[endif]-->Brushes:将数据拷贝到BspLevel:: mBrushes中;

<!--[if !supportLists]-->8.         <!--[endif]-->Leaves:设置每个leaf节点的数据,主要包括包裹盒,mFaceGroupStart,mNumFaceGroups,mVisCluster,mSolidBrushes。参见BspNode类;

<!--[if !supportLists]-->9.         <!--[endif]-->Vis data:将数据拷贝到BspLevel:: mVisData中。

Quake3 BSP的load流程基本上就是这些了。

【3. Bsp tree scene的渲染】
       仍然以Demo_BSP为例来分析。渲染的核心操作流程从SceneManager::_renderScene()开始(参见“Ogre学习笔记(3):Mesh的渲染流程”),接下来还有SceneManager:: _updateSceneGraph(),SceneManager::prepareRenderQueue(),BspSceneManager没有重写这几个函数。不过,有一点需要注意,SceneManager:: _updateSceneGraph()调用了BspSceneNode::_update()与OctreeSceneManager类似的,如果有必要的话,会调用BspSceneManager:: _notifyObjectMoved()--》BspLevel:: _notifyObjectMoved(),将SceneNode中的MovableObject attach到正确的leaf node中。
       接下来是BspSceneManager:: findVisibleObjects(),这是一个从SceneManager重写的函数。顺理成章的,这个函数调用了BspSceneManager::walkTree()。在这个函数中,首先找到了camera所在的leaf node(通过BspLevel::findleaf()函数);然后遍历BspLevel中的每个leaf node,先使用PVS检测可见性(通过BspLevel::isLeafVisible()函数),如果可见再使用camera――bounding box检测,如果还是可见的,则对此leaf node调用BspSceneManager::processVisibleLeaf()函数。此函数主要执行两个操作,一个是把World Geometry加入到渲染数据表中(mFaceGroupSet和mMatFaceGroupMap),另外一个是把与此leaf node相交的MoveableObject加到渲染队列中(mMovablesForRendering)。一件比较有疑问的事情是,walkTree是循环遍历所有leaf node,而没有按照BSP tree递归遍历,这大大削弱了BSP的提前排序的优势。

       然后是BspSceneManager重写了另外一个重要的函数_renderVisibleObjects()。此函数包含两个操作,一个是renderStaticGeometry(),另外一个是调用父类的SceneManager::_renderVisibleObjects()。前者循环遍历mMatFaceGroupMap,然后调用RenderSystem::_rendr();后者已经在“Ogre学习笔记(3):Mesh的渲染流程”中详细分析过了。

  

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yanonsoftware/archive/2006/09/13/1217406.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值