Quake 3 Level Format
and fun with culling!
Most information taken from
http://www.mralligator.com/q3/
Q3Radiant - Quake 3 level editor
Intermediate "editing" format: .map
.map files are strings, human-readable files
Then they're finalized and "baked" into a .bsp file, which the game executable reads
BSP
IBSP, or "Id BSP"
Binary
Search
Partitioning
Split geometry into subsections, mapping physical space in a tree data structure
This storage allows for some rendering optimizations to be made at runtime
Header
char[4] - always reads "IBSP"
int32 - indicates version of .bsp file format
- Quake 3 will always read '46'
lump[17] - offsets and lengths to arrays of data
- Lumps and version numbers differ from game
to game that uses the Quake engine
struct lump
{
int32 offset; //in bytes
int32 length; //in bytes
}
17 kinds of lumps in version 46
[0] Entities
[1] Textures
[2] Planes
[3] Nodes
[4] Leaves
[5] Leaf Faces
[6] Leaf Brushes
[7] Models
[8] Brushes
[9] Brush Sides
[10] Vertices
[11] Indices
[12] Effects
[13] Faces
[14] Lightmaps
[15] Light Volumes
[16] Visibility Data
We'll just look at a few:
[1] Textures
[3] Nodes
[4] Leaves
[5] Leaf Faces
[7] Models
[10] Vertices
[11] Indices
[13] Faces
[14] Lightmaps
[16] Visibility Data
Textures
List of filenames (without extension)
Meant to point to a "material," which is really a texture + some shading logic
Most textures are just "use this image," though
struct texture
{
char[64] name;
int32 flags;
int32 contents;
}
Vertices, Indices, and Faces
Topics for a different talk, but important
Basically a collection of 3D geometry to feed into the GPU
(Make your VBO and IBO from these)
struct vertex
{
float[3] position;
float[2] diffuseTexCoords;
float[2] lightmapTexCoords;
float[3] normal;
ubyte[4] color;
}
//indices are just int32s
struct face
{
int diffuseTexture;
int effect;
int type;
int vertexOffset;
int numVertices;
int indexOffset;
int numIndices;
int lightmapTexture;
//... and a whole bunch more
}
Nodes and Leaves
BSP data is stored in a perfectly balanced tree
Leaf
Leaf
Leaf
Leaf
Node
Node
Node
struct node
{
int32 plane;
int32[2] children;
int32[3] boundingBoxMins;
int32[3] boundingBoxMaxes;
}
struct leaf
{
int32 cluster;
int32 area;
int32[3] boundingBoxMins;
int32[3] boundingBoxMaxes;
int32 firstLeafFace;
int32 numLeafFaces;
int32 firstLeafBrush;
int32 numLeafBrushes;
}
Main use for this BSP structure:
Frustum culling
Start at root and iterate:
Does frustum intersect with node bounding box?
If yes, render this node
Nodes continue algorithm to children
Leaves draw all faces in leaf
If not, return and don't render any children
Visibility Data
Potential Visible Set (PVS) Culling
On top of BSP, the level also has PVS data
Leaves are assigned to clusters
Clusters have list of what other clusters are visible from this cluster
If BSP solves outside-frustum visibility,
PVS solves occlusion visibility
"Cluster x is visible from cluster y if the
(1 << y % 8)
bit of
visibilityData[x * sizeOfRows + y / 8]
is set."
struct visibilityDataHeader
{
int32 numRows;
int32 sizeOfRows;
}
ubyte visibilityData[numRows * sizeOfRows];
Live demo!
q3
By tdhoward
q3
- 578