Ogre BspSceneManager

来源:互联网 发布:毛孔抚子 知乎 编辑:程序博客网 时间:2024/06/07 23:41

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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 签证做假工作证明资料被拒怎么办 在广州办个建设厅电工证怎么办 水利考的五大员证到有效期怎么办 额头注射玻尿酸吸收后不平怎么办 施工员证书挂靠拿不回来怎么办 森林公安未转政法编制的人员怎么办 北京的限行新政策外地车怎么办 报考二级建造师工作年限不够怎么办 郑州航院图书馆密码忘了怎么办 无锡妇幼预约挂号过号了怎么办 云南建筑八大员考试没通过怎么办 订车ax7一个月提不到车怎么办 提车时间到了却没车怎么办 一汽大众速腾气囊灯亮该怎么办呢? 幼儿园上课时候电脑上的课件怎么办 黑米紫薯红豆粥不好煮怎么办 母狗生了小狗后不吃东西没奶怎么办 狗给扑倒了主人不想负责怎么办 山东政务网个人中心账号忘了怎么办 网易博客忘记登入名和密码了怎么办 奶水不够怎么办怎样让奶水变多 和初恋分手多年又爱上初恋该怎么办 分手六年的初恋想要和我复合怎么办 不小心把手机里的视频删了怎么办 网签过了中介不配合过户怎么办 房屋被中介恶意网签了怎么办 重介质选矿块矿品位低怎么办 去泰国酒吧选小姐只会说中文怎么办 脚被窝烫伤后发炎里面有龙怎么办 脚被窝烫了发炎有龙怎么办 辣椒落花的药喷到孩子嘴巴了怎么办 香炉里的小米生虫子了怎么办 香炉里面放的小米生虫子了怎么办 肉肉上长满了白色的小虫子怎么办 多肉上面有白色的虫子怎么办 多肉植物根部长白色虫子怎么办 朋友玩期货把我钱赔了怎么办 宝宝床上虫子咬了肿大包怎么办 喷药的杀虫剂的喷头坏了怎么办 宅e经营贷个人没有公司怎么办 浏览器下载完插件安装不好用怎么办