The scenario structure BSP tag, commonly just called the BSP, contains level geometry, weather data, material assignments, AI pathfinding information, lightmaps, and other data structures. You can think of the BSP as the "stage" where the game takes place objects are placed within it. Aside from sounds and bitmaps, the BSP tends to be one of the largest tags in a map. Singleplayer scenarios often use multiple BSPs which are switched between at loading zones.
The term "BSP" stands for Binary Space Partitioning, a technique where space within a sealed static mesh is recursively subdivided by planes into convex leaf nodes. The resulting BSP tree can be used to efficiently answer geometric queries, such as which surfaces should be collision-tested for physics objects.
While a scenario can reference multiple BSPs, Halo can only have a single BSP loaded at a time. Transitions between BSPs can be scripted (
switch_bsp), e.g. using trigger volumes. Objects in unloaded BSPs are not simulated.
Although multiple BSPs are intended for singleplayer maps and do not synchronize, some custom multiplayer maps have used nearly identical BSPs which only differ in lighting to add a day/night switch scripted by a button in the escape menu.
The most commonly used shader type for BSPs is shader_
Transparent shaders can also be used, for example:
transparent_ chicago for flowing rivers or waterfalls
transparent_ chicago_ extended for waterfalls
transparent_ water for lakes and oceans
If you think of the BSP as a sealed volume, portals are like doorways that split that space into distinct sealed "rooms" called clusters. This lets the game know what areas of a level can be culled to maintain good framerates, and the resulting clusters can each have unique properties assigned like background sound.
You can create portals in a few ways:
- Surfaces which cut through the level and use the material name
+portal. The portal planes can be connected along edges and even form box shapes but cannot have "leaky" gaps between the spaces they are meant to seal. Portal planes must not intersect each other.
- Surfaces which exactly match at their boundary with the vertices and eges in level geometry (e.g. around a doorway) and use the material name
+exactportal. The faces of the exact portal do not need to be coplanar.
- Existing materials in the level that happen to consistently seal off closed volumes wherever they're used as if they were exact portals, like floor grates or glass windows covering a pit. Add the
.material symbol, e.g.
It may be necessary to add multiple portals to close a space. For example, if a building had multiple doors and windows you would need to add portals to each of them for the inside of the building to be considered sealed off from the outside. For help troubleshooting portals, see here.
Clusters are sealed volumes of a BSP separated by portal planes. They are used both as a rendering optimization and artistically; map authors can assign weather_
Note that it may still be desirable to reference weather for indoor clusters if there are outdoor areas visible from them, otherwise snow and rain particles will abruptly disappear. To mask weather in such clusters, use weather polyhedra.
Clusters are either outdoor/exterior or indoor/interior. When a cluster contains +sky faces it is an outdoor cluster and has a sky index of
0 or greater. Furthermore, any cluster from which an outdoor cluster is potentially visible will also be an outdoor cluster.
An indoor cluster is one where none of its potentially visible clusters are outdoor. These clusters have a sky index of
-1 instead and use the indoor parameters of sky index
0 (the first sky), which always has the special role of doubling as the "indoor sky". For example, indoor clusters will use use its indoor fog color rather than its outdoor fog color.
When the game transitions between indoor and outdoor clusters the fog colour fades based on cumulative camera movement, not time. This effect can be seen easily in Danger Canyon: load it in Sapien and fly the camera through the hallways while
debug_pvs 1 and
rasterizer_wireframe 1 are enabled.
The potentially visible set data (PVS) is precomputed when a BSP is compiled and helps the engine determine which clusters are visible from each other. A cluster can "see" any other cluster behind portals visible from itself plus one level of clusters further. Any clusters beyond that will not be rendered.
Tool also takes into account the indoor sky's indoor fog opaque distance and indoor fog maximum density when computing the PVS. If the density is
1.0 (fully opaque) then Tool knows that indoor clusters cannot see beyond the opaque distance even if there are clusters within a line of sight. Tool logs the indoor maximum world units when the BSP is compiled (if there a sky referenced).
Create a fog plane by modeling a flat plane and giving its faces the material name
+unused$. The fog will exist behind/antinormal to the plane. It must be completely flat and it is invalid for any cluster to be able to see multiple fog planes (see more), so adjust the size and shape of the plane accordingly. You can even create slanted or upside-down fog planes as long as they follow the rules. Once your BSP is compiled, you'll be able to assign fog to your plane(s) in Sapien.
Weather polyhedra are artist-defined volumes where weather particle systems will not render, such as under overhangs where you would not expect to see rain.
To create them, simply model outwardly facing convex volumes where all faces use the
+weatherpoly material name and Tool will generate the weather polyhedra when compiling your BSP. The volumes can overlap and up to 8 can be visible at any time before the game starts ignoring some (Sapien will print warnings when this happens).
It is important that you still create weather polyhedra even if you have portals separating inside and outside spaces. Simply not assigning weather to the clusters which are under cover is not enough to prevent rain from appearing there. This is because the game renders weather based on the camera's current cluster, so if the player is outside a building looking in through a doorway they will still see rain indoors because the camera is currently located outside. Conversely, if the cluster within the building has no weather assigned then players will not see rain outdoors when looking out the doorway from inside. The solution is still assigning weather to covered clusters, then masking those areas with large weather polyhedra. This can be seen in the example figure.
Within the tag, the polyhedra are represented as a center point, bounding radius, and up to 16 planes which enclose a volume. Therefore your polyhedra technically don't need to be sealed volumes because they are limited to their bounding radius. A polyhedron can be created with as little as 1 plane.
Lightmaps are the visual representation of the BSP, and are stored in a separate representation from its collision data. The lightmaps data includes the renderable triangles and a precalculated radiosity bitmap.
See main page: Lightmaps.
When a shader_
0, a single lens flare is placed on the surface<sup>(how?)</sup>. Otherwise, the lens flares are evenly spaced within the surface according to the spacing value (world units).
A BSP can contain up to 65535 lens flare markers, and up to 256 types of lens flares. However, there is a much lower limit to how many the game will draw at a given time, exactly how many is unknown.
Phantom BSP is a collision artifact sometimes produced when compiling BSPs. It manifests itself as invisible surfaces which projectiles and vehicles collide with (but not players), and mostly appears around sharp corners near cases of "nearly coplanar faces" warnings in your WRL file.
Bungie was aware of this artifact and implemented a feature to help spot it (
collision_debug_phantom_bsp 1 in Sapien or Standalone). If you find phantom BSP in your map, there are a few steps you can take to resolve it:
- Preemptively, keep your geometry simple and robust without an abundance of dense, complex, or spiky shapes. Flat surfaces like floors and walls should be kept as flat as possible by using alignment tools when modeling rather than "eyeballing it".
- Fix any "nearly coplanar" warnings in your source model by scaling affected faces to 0 along their normal axis or using alignment. Since Tool slightly rounds vertex coordinates when compiling BSPs, sometimes this warning cannot be resolved for surfaces which are not axis-aligned.
- There is an element of chance to phantom BSP appearing which depends on how your geometry is recursively subdivided form a BSP tree. Modifying unrelated parts of your level like adding portals or moving vertices can sometimes affect how the level is subdivided and make phantom BSP disappear.
- Using phantom_
tool or H1A Tool's fix-phantom-bsp option to compile your BSP will prevent phantom BSP at the cost of slightly increasing the tag size.
- If you do not have access to source JMS, and are trying to fix a BSP tag, the tool Ghostbuster may fix it but has known issues.
On a technical level, cases of phantom BSP are dividing planes where a child index is
-1, but the space on that side of the plane is not actually completely outside the level. The artifact is bounded by all parent dividing planes.
BSP holes or leaks are another type of collision artifact where items or players can fall through the map. It is not known what causes this, but it can be resolved by altering triangulation around the affected area (rotating edges). Compiling the BSP with phantom_
The BSP contains data on traversable surfaces which aid AI in pathfinding (walking to a destination). This data is generated automatically during BSP compilation and is retained even in when the BSP is compiled into multiplayer maps.
See more about the pathfinding system.
If enabled, the center of the view is used to test for collisions. A red normal-aligned marker will be shown where the ray from the center of view collides with a surface. The collision surface itself, whether BSP or model, will be outline in red. Information about the collision surface will be shown in the top left corner of the screen, including plane and surface indices from the BSP structure, material type, and how many degrees the surface's normal differs from vertical.
The types of surfaces which the test ray hits or ignores can be toggled with the
Toggles the display of collision features near the camera, which can be spheres (red), cylinders (blue), or prisms (green). Collision size can be adjusted with
Causes a floating pink cube and label "phantom bsp" to appear whenever a test ray from the center of the screen intersects with phantom BSP. It can be helpful to pair this with
Setting this to
Toggles the display of structure BSP node traversal for the camera location. At each level, the node and plane indices are shown as well as a
Shows debug information about the camera in the top left corner, including:
Draws structure BSP portals as red outlines.
When enbled, all scenario_
A reference to the bitmap storing the level's baked lightmaps. The level will not be visible without this.
The lowest Z-axis height (absolute, not frame relative) that vehicles can reach while occupied. Does not affect other object types. An unoccupied vehicle will still drop below this soft barrier, but when it becomes occupied again it will quickly shoot back up into the play area. An example of a map using a vehicle floor is Gephyrophobia to prevent players from flying too far below the bridge.
The maximum Z-axis height (absolute, not frame relative) that vehicles can reach while occupied. Does not affect other objects types. Above this point, occupied vehicles will elastically move back below the ceiling. This can be used to limit the height that players in flying vehicles like Banshees can reach for gameplay reasons. An example of this can be seen in Blood Gulch.
|default ambient color|
If the red component of this colour is non-zero, this and all following default lighting fields will be used to light objects when a ground point does not exist within 10wu below them.
|default distant light 0 color|
Primary distant light colour when default lighting applies.
|default distant light 0 direction|
Primary distant light direction when default lighting applies.
|default distant light 1 color|
Secondary distant light colour when default lighting applies.
|default distant light 1 direction|
Secondary distant light direction when default lighting applies.
|default reflection tint|
Reflection tint when default lighting applies.
|default shadow vector|
Shadow vector when default lighting applies.
|default shadow color|
Shadow colour when default lighting applies.
|world bounds x|
|world bounds y|
|world bounds z|
Lists the available lens flares used by this BSP's lens flare markers.
|lens flare markers|
Points within the BSP where a lens flare will be rendered.
|background sound palette|
|sound environment palette|
|sound pas data|
Named points with orientation within the BSP. They are similar to gbxmodel markers but are not to be confused with scenario cutscene flags. These markers become visible in Sapien when enabling snap to markers in the tool window.
|leaf map leaves|
|leaf map portals|
Thanks to the following individuals for their research or contributions to this topic:
- Conscars (Collision BSP structure and phantom BSP research)
- Galap (Researching the effect of cluster sky index on lighting)
- Hari (Collision BSP compilation reversing)
- Kavawuvi (Invader tag definitions)
- MosesOfEgypt (Tag structure research)