详细介绍Quake 2 BSP文件格式和应用

简介
  
  BSP文件格式是QUAKE 2用于存储地图的一种文件格式,说得具体点,就是用于渲染Q2世界的。尽管有其他的信息包含在BSP文件中,用于其他游戏部分(如敌人AI,等等),在这篇文章中,我不将讨论他们。如果你有这方面的知识,请告诉我,我的E-MAIL在下面。在这篇文章中难免有错误之处,请告诉我。
  为了更清楚的描述BSP文件格式,在这篇文章中将试图对Q2渲染引擎进行技术方面的描述。现在让我们假想这个渲染器使用的是基本的3D图形技术,包含BSP树结构。
  我们在这篇文章中描述的是Q2的BSP文件格式,这个文件格式由Kingpin使用(他建立了Q2引擎)。对于Q1和Q3的文件格式,虽然他们很相同,但还是有点不兼容。不管怎样,BSP的文件结构和技术不是很难,这篇文章将对于那些对这些格式赶兴趣的人。
  
  法律方面的问题
  
  协定
  
  在这篇文章中,我用C语言结构来描述这些问题。为了使描述简单并规范意义,我用int32 and uint32来表示有符号和无符号32位整形数;同样的符号将用于16位和32位整形数。下面为用于存储BSP文件格式的顶点和矢量的结构:
  struct point3f
  {
  float x;
  float y;
  float z;
  };
  struct point3s
  {
  int16 x;
  int16 y;
  int16 z;
  };
  第二版中一些地方,如保存内存,就不需要很高的精度。相比于12位的版本,他只需要6位。通常情况下,都是用整形,而非浮点。
  
  渲染
  
  在这一节中,我们将介绍数据结构中的一些术语,并描述一下在Q2中进行渲染的过程。
  Q2地图中划分成很多的凸区域,这些区域用BSP树页来表示。任何时候摄象机的位置随这些凸区域的水平方向改变。那一些树叶都相互的簇拥在一起,成一丛一丛的。这些丛如何构成是由建立BSP文件的工具决定。对于每个丛,他们都是以列表形式潜在,直观地存储。我们把这称为potentially visible set(PVS).
  要渲染Q2地图,首先篇历BSP树,以决定摄象机的导入。一旦知道摄象机导入的叶,相应的丛也导入了(记住一片叶包含一个丛)。对应于丛的PVS然后解压出摄象机对应的那些PVS的列表。叶然后存储根据视角平截面裁减的叶的范围。
  
  BSP树
  
  许多人在通过用Q2和相似的引擎时,没有把BSP树和相应的算法联系起来。通过上面的叙述,我们知道可视的界面是由PVS决定。BSP树用于分割地图并快速地决定哪一块应该显示。结果,在Q2中没有好的渲染算法,而不得不用其他数据结构代替(如OCTREE OR K-D TREE)。BSP树不管怎样是非常简单的,他也被用在Q2引擎中其他不用渲染的任务中。
  当讨论BSP树中存储叶结点的BSP树(leaf-based BSP trees)和存储内部结点的BSP树(node-based BSP trees)时。用在Q2中的BSP树的变化实际上是两方面的。这两方面是渲染和冲突检测。用于渲染时,他直接把存储在叶结点中的面渲染出来,因为他们是以PVS形式存储的。如果你没有执行冲突检测,存储在内部结点中的面将完全被忽约。
  
  文件头
  
  就我所知,所有的BSP文件是以字节的形式存储的,当用在大的终端平台上时,随着导入而变换。这使的相同的地图能够被使用不同平台的Q2用户共同使用。如果你在大的终端中导入BSP文件-------如Macintosh ,UNIX---你将不得不仔细的变换字节顺序。
  BSP文件格式是用目录结构组织的,文件中所有的数据包含“自由的浮动”(free floating)团。在文件开始处,有一个目录告诉团的开始的偏移和长度。这个目录后的文件开始的8个字节是用于描述这些团的位置和长度。
  BSP文件头的格式描述如下:
  struct bsp_lump
  {
  uint32 offset;      //从文件开始的数据的偏移(用字节表示)
  uint32 length;     //数据的长度(用字节表示)
  };
  struct bsp_header
  {
  uint32 magic;    //magic号(“IBSP”)
  uint32 version;   //BSP格式的版本(38)
  bsp_lump lump[19];  //团的目录
  };
  BSP文件开始的4个字节是一个标记,用于标识文件是否一个软件BSP文件。这些字节被拼为“IBSP”。接下来是32位无符号整形数,用于指定版本号。正如上面说的一样,本文件的版本号为38。
  接下来的表显示BSP文件中包含的不同的团,并且这些团的索引排列在文件头中。这些团的目的是用于标识不知道的问题标记(这个名字来源于QBSP源代码),不管怎样,他们是不用建构简单的Q2标准渲染器。
  
  索引名          描述
  0 Entities       MAP实体文本缓冲器
  1 Planes       平面队列
  2 Vertices      顶点队列
  3 Visibility       压缩的PVS数据和所有的丛目录
  4 Nodes       BSP树的内部结点数组
  5 Texture Information 表面材质运用队列
  6 Faces        表面队列
  7 Lightmaps     光图
  8 Leaves       BSP树的内部叶队列
  9 Leaf Face Table 索引查找表,用于参考叶中的表面队列
  10 Leaf Brush Table    ?
  11 Edges      边队列
  12 Face Edge Table 索引查找表,用于参考叶中的边队列
  13 Models     ?
  14 Brushes    ?
  15 Brush Sides  ?
  16 Pop       ?
  17 Areas      ?
  18 Area Portals      ?
  许多团是用结构队列的形式存储的,这些结构都是固定大小。例如,顶点团是一个POINT3F结构队列。由于每个POINT3F是12位,顶点值被12个顶点团分开进行计算。相似的计算也被用于面,结点,材质信息,表面,叶和边团。
  在下一节,我们将讨论团的结构和作用。
  
  顶点团
  
  顶点团是一列世界的所有的顶点。每个结点是3个float浮点值,相当于12个字节。你能计算这些顶点值通过把这些顶点团的长度分为12来计算。(You can compute the numbers of vertices by dividing the length of the vertex lump by 12. ^_^不好意思,可能翻译错了)
  Q2用一个协调系统通过Z-轴调整为向上。记住,就是你用其他的系统进行调节,你可能需要改变束缚盒和面方程式。
  
  边团
  在表面的顶点要共享,而且边也要共享。每一条边是存储在顶点队列中。存储量是两个16位的整形数,因此,在边队列中的边数是由边团的值除以4。这里要说的是可能有一条边被有卷绕着的线的两个面共享,因此对于一条边,没有特殊的方向。这一点将在表面团中讨论。
  
  表面团
  
  bsp_face结构队列中表面团的格式如下:
  
  struct bsp_face
  {
  uint16 plane;      //表面平行的面的索引
  uint16 plane_side;  //设置表面是否与面平行
  
  uint32 first_edge;  //第一条边的索引(在表面边队列中)
  uint16 num_edges; //连续的边的数量(在表面边队列中)
  
  uint16 texture_info;   //材质信息结构的索引
  uint8  lightmap_syles[4]; //光图的类型
  uint32 lightmap_offset;  //光图在光图团中的偏移
  };
  这个bsp_face结构的长度是20字节,面的数量可以由表面团除以20得到。

你可能感兴趣的:(数据结构,struct,table,存储,float,引擎)