CQ3LevelMesh分析
Quake3 BSP文件格式可以参看:BSP地图文件格式
loadTexture():Textures初始化
loadLightmaps():LightMaps初始化
loadVerts():Vertices初始化
loadFaces():Faces初始化
loadMeshVerts():MeshVerts初始化
constructMesh():
1)为每一个普通纹理与光线映射纹理的组合分配一个个SMeshBufferLightMap用于存储二重纹理的顶点的模型缓冲区,并将其加入到模型列表Mesh中,共计创建了(NumTextures+1) * (NumLightMaps+1)个模型缓冲区。因此同一个模型缓冲区中存储的是具有相同普通纹理与光线映射纹理的face
2)循环遍历所有面Face,(只对表示多边形的Face进行了提取)填充对应模型缓冲区的顶点数据:
根据面Face[i]的普通纹理、光线映射纹理找到对应模型缓冲区,将多边形划分为三角扇形(TRIANGLE_FANS)放入模型缓冲区,注意:由于某些面公用普通纹理与光线映射纹理,因此每个模型缓冲区将被进入公用这个普通纹理与光线映射纹理多边形数的次数,因此也就放入了这个数目的多边形。
loadTextures():加载、创建所需的纹理
1)加载普通纹理:
根据纹理Textures,依次加载纹理到纹理列表tex中
2)加载光线映射纹理
根据LightMaps,依次加载纹理到纹理列表lig中
3)将对应的普通纹理、光线映射纹理设置到相应的模型缓冲区中
4)删除空的模型缓冲区
总结:因此Mesh中所有模型缓冲中存储了场景地图中所有的多边形——实际存储的是三角形,即如果将它们渲染出来就渲染出了整个场景地图!!
COctreeSceneNode分析
createTree()
1)将Mesh中所有模型缓冲区数据转换为SMeshChunk形式(其实两者vertices、与indices数据安排相同所以只是复制),并依次放入模型列表LightMapMeshes中,此时LightMapMeshes包含了构成场景节点的所有的三角形!
2)后使用个代表了场景节点模型的LightMapMeshes为参数调用COctTree构造函数去构造一棵八叉树COctree。
OctTree分析
OctTree(const core::array<SMeshChunk>& meshes)
-
分配:
1)IndexDataCount初始化为模型缓冲区个数(meshes.size())、并为每个模型缓冲区分配一个索引列表SIndexData组成放入数组IndexData中。
2)分配一个SIndexChunk列表indexChunks,作为
-
初始化:
1)初始化每个IndexData数组中的元素,即每个索引列表SIndexData的成员赋CurrentSize=0、MaxSize=对应的模型缓冲区的索引数量、Indices为索引分配空间(不做初始化)
2)初始化indexChunks列表的每个SIndexChunk的索引数据为对应模型缓冲区的索引数据
-
以meshes、初始化了的indexChunks为参数调用OctTreeNode构造函数创建一个根节点
OctTreeNode分析
OctTreeNode(nodeCount,meshes,indexChunks)
1.将该节点的Box初始化为meshes中第一个非空模型的第一个顶点坐标
2.根据indexChunks包含的模型三角形计算该节点的实际Box
3.计算该节点Box的8个顶点坐标、和中心middle
4.关键:根据middle和8个顶点将空间划分为八个子空间
1)分配一个新的SIndexChunk列表cindexChunks,作为代表放入子空间的三角形集合
2)循环八个子空间,将在meshes中被完全包含在此子空间的三角形索引放入cindexChunks中对应SIndexChunk中,并将该三角形从indexChunks中删除,根据cindexChunks包含的三角形调用OctTreeNode构造函数创建一个新的子节点,即又进入了上述1.进行递归!最后indexChunks中存储了不能被放入的子空间的三角形集合,将其放入节点的IndexData中存储,因此不能被分割的三角形是放在父节点中
5总结:每个递归的划分子空间最后由于没有完全属于该空间的三角形而进行回溯,因此最后所有节点(包括叶子节点)中存储了那些同时跨域Box两个以上子空间的三角形的索引数据,其由IndexData存储;
getPolys(box, idxdata)
如果该节点Box与box有相交部分则:
1)将该节点中保存的三角形复制到idxdata中
2)进入子节点递归上述过程
因此idxdata中最后存储了初始节点(一般为root)代表的空间中可能与box相交的三角形,因此idxdata中存储的三角形比实际于box相交的三角形多很多,例如第一次递归时也许整个节点代表的空间中只有其中一个子空间与box相交了,但是却将那些跨越了其他子空间的三角形也复制了过去。有些情况可能更坏:也许box连与其中一个三角形也没有相交,但却由于与其中一个子节点中“空的”区域相交了,这样从调用节点到叶子节点路径上所有经历的节点的三角形全复制到了idxdata中。因此由这个函数得到的这种可能相交的三角形只能用于与视锥体的碰撞测试来用于可视渲染,因为即使看不见的三角形被渲染了,也会被其遮挡物覆盖,不会影响渲染效果
COctreeSceneNode:render()
再回来看COctreeSceneNoe:render()
1)首先获取视锥体的AABB包围盒box
2)代表当前节点的模型的八叉树LightMap调用OctTreecalculatePolys(box),计算出可能的可视的三角形
3)渲染这些三角形