📄 quake3format.htm
字号:
works:
</p>
<p class="MsoBodyText">
With cluster A, B and C, here is how they would be represented in binary (a
bitset):
</p>
<p class="MsoBodyText">
ABC<br>
000
</p>
<p class="MsoBodyText">
Each 0 represents a slot that is assigned to a cluster. Let's assume
that:
</p>
<p class="MsoBodyText">
- Cluster A can see cluster B and not C<br>
- Cluster B can see cluster A and C<br>
- Cluster C can see cluster B and not A
</p>
<p class="MsoBodyText">
Below is a representation of each one of their bitsets:
</p>
<p class="MsoBodyText">
- A 110<br>
- B 111<br>
- C 011
</p>
<p class="MsoBodyText">Does that make sense? Notice for A there is a 1
in the first slot which means it can see itself, and also in the second slot
which means it can see cluster B. The last slot is a 0, which tells us
that cluster A can not see what's in cluster C because some walls or whatever
are blocking it. This is where the good spatial partition speed comes
in. If you are in the very bottom corner of the level in a small little
room, you just cust out probably 95% percent of the polygons that need to be
rendered because you can only most likely see the cluster that is right
outside of that room.
</p>
<p class="MsoBodyText">To test if a cluster is visible from another cluster,
there is obviously going to have to be some bit-shifting and other binary math
involved. The basic algorithm to test a cluster against another cluster
is as follows:
</p>
<p class="MsoBodyText">int visible = pVecs[currentCluster*vectorSize + (
testCluster/8 )] & (1 << (testCluster & 7))
</p>
<p class="MsoBodyText">If the result of <b>visible</b> isn't 0, then the <b>testCluster</b>
can be seen from the <b>currentCluster</b>. We divide and % (mod) by 8
because we are using <b>byte</b>s which are 8 bits. Basically, the first
part is indexing into the array of clusters to find the correct bitset, then
we do a binary & (and) with the cluster we are testing to get the result.
</p>
<p class="MsoBodyText">Here is some basic code to do a cluster to cluster
test:
</p>
<p class="MsoBodyText">
<font face="Courier New" size="2">inline int <b>IsClusterVisible</b>(tVisData *pPVS, int current, int test)<br>
{<br>
if(!pPVS->pVecs || current < 0) return 1;<br>
<br>
byte vector=pPVS->pVecs[(current*pPVS->vectorSize) + (test/8)];<br>
int result = vector & (1 << (test & 7));<br>
<br>
return ( result );<br>
}</font>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Entities</font></b></td>
</tr>
</table>
<p class="MsoBodyText">The entity lump just stores a huge string with each
line delimited by '\n'. Some types of things stored in this string is
the deathmatch positions for the players in the beginning, weapon positions,
sky box information, light positions, etc... I suggest you save it off
to a file so that you can get a good idea on how to parse it. Be careful
when writing a parser, things aren't always saved in the same order.
Player positions usually store the 3D position on the map, along with the
orientation described by a rotation angle. To find the length of the
entity string to read in, just divide the entity lump's <b>length </b>by
sizeof(<b>char</b>).
</p>
<p class="MsoBodyText">char *<b>strEntities</b>;
// This stores a huge string of all the entities in the level
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Brushes</font></b></td>
</tr>
</table>
<p class="MsoBodyText">The brushes store information about a convex volume,
which are defined by the brush sides. Brushes are used for collision
detection. This allows the level editor to decide what is collidable and
what can be walked through, such as trees, bushes or certain corners.
</p>
<p class="MsoBodyText">
<code><font size="2" face="Courier New">struct <b>tBSPBrush</b> <br>
{<br>
int brushSide;
// The starting brush side for the brush <br>
int numOfBrushSides; // Number of
brush sides for the brush<br>
int textureID;
// The texture index for the brush<br>
};</font></code>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Leaf Brushes</font></b></td>
</tr>
</table>
<p class="MsoBodyText">Like the leaf faces, leaf brushes are used to index
into the <b>tBSPBrush</b> array. Once again, brushes are used for
collision detection. To calculate the number of leaf brushes in the lump
you divide the <b>length</b> of the lump by the sizeof(<b>int</b>).
</p>
<p class="MsoBodyText">
<code>int *<font size="2"><b>pLeafBrushes</b></font>;
// The index into the brush array</code>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Brush Sides</font></b></td>
</tr>
</table>
<p class="MsoBodyText">The brush sides lump stores information about the brush
bounding surface. To calculate the number of brush sides, just divide
the lumps <b>length</b> by sizeof(<b>tBSPBrushSides</b>).
</p>
<p class="MsoBodyText">
<font size="2" face="Courier New">struct <b>tBSPBrushSide</b> <br>
{<br>
int
plane;
// The plane index<br>
int textureID;
// The texture index<br>
};</font>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Models</font></b></td>
</tr>
</table>
<p class="MsoBodyText">The model structure stores the face and brush
information, along with the bounding box of the object. These objects
can be movable such as doors, platforms, etc... To calculate the number
of models in this lump, just divide the <b>length</b> of the lump by sizeof(<b>tBSPModel</b>).
</p>
<p class="MsoBodyText">
<font size="2" face="Courier New">struct <b> tBSPModel</b> <br>
{<br>
float min[3];
// The min position for the bounding box<br>
float max[3];
// The max position for the bounding box. <br>
int faceIndex;
// The first face index in the model <br>
int numOfFaces;
// The number of faces in the model <br>
int brushIndex;
// The first brush index in the model <br>
int numOfBrushes; //
The number brushes for the model<br>
};</font>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Mesh Vertices</font></b></td>
</tr>
</table>
<p class="MsoBodyText">This stores a list of vertex offsets that are used to
create a triangle mesh. To calculate the number of mesh vertices in the
lump you divide the <b>length</b> of the lump by the sizeof(<b>int</b>).
</p>
<p class="MsoBodyText"><code>int *<font size="2"><b>pMeshVerts</b></font>;
// The vertex offsets for a mesh</code>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Shaders</font></b></td>
</tr>
</table>
<p class="MsoBodyText">The shader structure basically gives you the file name,
for a *.shader file. The .shader file then stores all of the information
about blending, animating and such. The shader files can be found
usually in the scripts\ folder, assuming that there are any textures in the
level that use shaders of course. To calculate the number of shaders for
this lump, just divide the <b>length</b> of the lump by sizeof(<b>tBSPShader</b>).
</p>
<p class="MsoBodyText"><font size="2" face="Courier New">struct <b> tBSPShader</b><br>
{<br>
char strName[64]; // The name of
the shader file <br>
int brushIndex; // The
brush index for this shader <br>
int unknown;
// This is 99% of the time 5<br>
};</font>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Light Volumes</font></b></td>
</tr>
</table>
<p class="MsoBodyText">Not everything in Quake3 is lit by lightmaps.
There are other lights that have their own special properties. I believe
you can get the rest of the light information from the entities lump. To
calculate the number of lights in the lump, just divide the <b>length</b> of
the lump by sizeof(<b>tBSPLights</b>).</p>
<p class="MsoBodyText">
<font size="2" face="Courier New">struct <b> tBSPLights</b><br>
{<br>
ubyte ambient[3]; // This is the
ambient color in RGB<br>
ubyte directional[3]; // This is the directional color in
RGB<br>
ubyte direction[2]; // The direction of the
light: [phi,theta] <br>
};</font>
</p>
<p class="MsoBodyText"><font face="Times New Roman" size="3">The light data </font><font face="Times New Roman" size="3">makes up a
3-Dimensional grid with dimensions of: <br>
</font><br>
<font face="Courier New" size="2">x = floor(models[0].max[0] / 64) -
ceil(models[0].min[0] / 64) + 1<br>
y = floor(models[0].max[1] / 64) - ceil(models[0].min[1] / 64) + 1<br>
z = floor(models[0].max[2] / 128) - ceil(models[0].min[2] / 128) + 1 </font>
</p>
<p class="MsoBodyText">
</p>
<table width="570">
<tr bgColor="#2165ae">
<td height="17" width="562"><b><font size="5">Conclusion</font></b></td>
</tr>
</table>
<p class="MsoBodyText">
This is an on going project to add to this file, so if you have any pointers,
corrections, or additions, let me know and I will post them. Once again,
this was used as a tag along with the BSP tutorial series on <a href="http://www.GameTutorials.com">www.GameTutorials.com</a>.
I would
like to thanks these people for their HUGE help on creating this document and
understanding the .bsp file format:
</p>
<p class="MsoBodyText">
Kekoa Proudfoot - <font size="3">kekoa@graphics.stanford.edu </font></O:P>
</p>
<p class="MsoBodyText">Bart Sekura - bsekura@poland.com</p>
<p class="MsoBodyText">Ignacio Castano - titan@talika.fie.us.es</p>
<p class="MsoBodyText">Emmanuel Weber - weberemmanuel@hotmail.com</p>
<p class="MsoBodyText"><br>
Ben 揇igiBen
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -