When compiling a level's structure BSP using Tool you may encounter warnings or errors in Tool's output indicating problems with your model, for example:

### Warning found nearly coplanar surfaces (red and green).
### Warning found #1 degenerate triangles.

Use this guide to understand how to avoid problems before you start modeling and you will have an easier time getting your BSP in-game. This guide offers examples in Blender, but the concepts are equally applicable to modeling BSPs in Max. Note that the shown model is triangulated during export to JMS and quads are used in examples for modeling ease.

Sealed world rules

A classic BSP rules cheat sheet.

Halo generally requires your BSP to be one or multiple completely sealed volumes with no intersecting faces, open edges (holes), 0-area faces, or other non-manifold surfaces. There are some exceptions for certain types of surfaces which require material symbols, but the main "balloon" of the level still needs to follow these rules. It should also not be too geometrically complex or large.

The normals of the faces used to create the level geometry must face inwards towards the playable area of the level. The normals determine not just the viewing direction but also which direction the surface is collideable from.

For most types of problems Tool generates a WRL file that can be imported back into your 3D software to find the sources of the problems. The path of this WRL file depends on if you are using Gearbox Tool or H1A Tool (see WRL page). You should attempt to fix all errors and warnings in your map. Many of these errors can also show up when compiling model_collision_geometry and the solutions will be the same.

Your 3D software can help you find some issues before exporting. Blender has select non-manifold and 3ds Max has STL check.

General geometry problems

Error: Edge is open (red)

Open edges are holes in the surface of your level. Your level needs to be a completely sealed/closed volume. Even outdoor levels must including faces which form a "roof" over your playable space with the +sky material. It doesn't matter if the hole is completely airtight and not visible; if the edges are technically open then Tool will not allow it. An unmerged seam along two edges is not considered open if the vertices along those edges are in the same position. In fact, this is the result of the Edge Split modifier that gives you sharp edges.

Open edges are also allowed on render-only surfaces like lights and water, and other special 2D surfaces like ladders, glass, and fog planes that are typically modeled as simple floating quads (a rectangle made of two triangles). If you are attempting to model one of these special surfaces, make sure you are including the necessary material symbol(s).

Closing open edges usually involves merging vertices or filling. In Blender you can select multiple and press M, or use Auto Merge with snap to ensure vertices are merged when you move them to the same location as another vertex. Max users can use Target Weld. Filling can be done by selecting multiple edges and pressing F.

Error: Couldn't update edge (red)

This error indicates that an edge is shared by more than 2 adjacent faces. This is usually seen where 3 faces meet and share a common edge. Like with open edges, render-only (!) and double-sided (%) faces don't count.

This is usually fixed by deleting any accidental leftover faces present after stitching together multiple objects (e.g. a base to the ground) and by avoiding connecting the edges of two shapes by a single edge.

Another common cause for this error is incorrect level scale; Tool merges together vertices which are very close together (within 0.1 JMS units) and may interpret many faces as sharing a common edge when in Blender they don't. Remember that with default JMS export settings, 1 Blender meter = 1 JMS unit and the Chief is 70 JMS units tall. Make sure you are modeling the level at the correct scale

Warning: Nearly coplanar faces (red and green)

This is one of the most common warnings map-makers will encounter. Let's first define coplanarity. If two faces are "coplanar" it means they are on the same plane; there is a flat infinite surface that both faces would perfectly lie on. Tool warns you when connected faces are nearly coplanar, meaning they are actually facing slightly different directions and the edge they share is a slight hill or valley.

Exact coplanarity is desirable because Tool will combine together adjacent coplanar faces into a single larger collision surface as an optimization. Nearly coplanar faces are undesirable because they can cause a problem called phantom BSP, including cases undetectable by collision_debug_phantom_bsp but which cause objects to fall back to BSP default lighting.

You should deal with this problem even though it's a warning. This is not to say all your cliffs need to be flat walls and the ground featureless, but just avoid very slightly deviations in angle from face to face. Any collection of faces which should be flat, like walls and floors, should be aligned and coplanar.

To avoid this issue you can:

  • Avoid "eyeballing it" when modeling things which should be straight and aligned. Use snap when moving vertices along an axis to ensure they align with others;
  • Scale sets of faces which should be coplanar to 0 along an axis (see video);
  • Avoid sculpting tools, which produce a lot of slight angles in dense geometry;
  • Model with simple, low-poly shapes.

In some cases having nearly coplanar faces is unavoidable. When faces are axis-aligned it is easy to make them coplanar, but when they are meant to be at an 45-degree or other angle you may encounter the nearly coplanar warning due to a loss of precision in the JMS format, which is only capable of storing up to 6 digits to the right of the decimal points (e.g. 123.123456). This will result in vertices on angled surfaces going slightly out of alignment. In this case check for phantom BSP around the area identified in the WRL file. If any is found, you may be able to clear it up with simple triangulation changes or other minor alterations in the vicinity.

You should also avoid using the Halo Asset Blender Development Toolset. custom or world unit export scales when working with collision models/BSPs. Stick to JMS scale to avoid amplifying floating point precision inherent to the editor and causing the same issue as JMS precision loss.

Error: Z-buffered triangles (red)

Z-buffered triangles are when two triangles intersect each other rather than being connected by edges and vertices. This rule applies only to collideable geometry and not render-only geometry. The WRL error file represents this error as an edge along the intersection.

Modders who are used to working with other engines where this is allowed will probably find this restriction annoying, but it's a requirement for how Halo creates collision models. Avoid poking parts of your model through other parts without attaching them to form a continuous mesh.

Warning: Degenerate triangles (red)

A degenerate triangle is one that has zero (or near-zero) surface area. In other words, it's not functioning as a proper triangle because all 3 of its vertices are in a line (colinear) or at a single point. The warning applies to both collideable and render-only geometry. When edges are below 0.1 JMS units in length, they will also collapse into a single point when compiled by Tool and cause this warning.

You can avoid this warning by avoiding:

  • Extremely small or thin triangles;
  • N-gons with colinear points (points which line up perfectly) since these may triangulate in a way that produces degenerate triangles.

Like with Couldn't update edge, this warning can also be caused by improper level scale and may not actually be due to actual degenerate triangles.

Warning: A surface clipped to no leaves (cyan)

This warning occurs when a collideable or render-only surface is outside the BSP. It is usually a sign of an improper triangulation or modeling mistake and should be corrected, since the rationale is that if the player can't leave the level then they probably won't see or interact with such a surface anyway.

However, you might have legitimate reasons for putting render-only faces outside the BSP and ignoring this warning:

  • The faces are visible through +sky and you do not want to expand the BSP to encompass them, e.g. to reduce lightmap size.
  • The faces are part of a larger render-only object which is only partially outside the BSP and removing the faces outside the BSP would be tedious or limit your ability to adjust the model later. Examples might be foliage or wires/cables.

Error: Couldn't build BSP because of overlapping surfaces (orange)

This error indicates that two collideable surfaces are overlapping (Z-fighting). They are on the same plane and are intersecting each other. This is not an issue for render-only geometry. It can happen for similar reasons to the z-buffered triangle example or when special floating surfaces like ladders and glass are coplanar with walls. The solution is usually to move one of the overlapping surfaces slightly:

Warning: Found possible T-junction (pink)

This is likely a side-effect of other issues with your geometry. Correct them first and this should go away. On a more technical level, this warning happens when a leaf surface is colinear with a BSP2D plane. Such surfaces would have to be very narrow. If you are seeing a T-junction warning in isolation you should look for extremely thin or small faces and resolve them the same way as degenerate faces.

Error: Vertex has a bad point

A vertex is too far away from the origin (0, 0, 0 coordinate). All points must be within -1500 and +1500 world units (-150000 and +150000 JMS units) in each axis. If you have encountered this error it means your BSP is too large and must be scaled down.

Exception: bsp3d_plane_test_point(plane, point0, NULL)==_bsp3d_plane_test_on

In full, this rare exception appears as:

EXCEPTION halt in e:\jenkins\workspace\mcch1codebuild\mcc\main\h1\code\h1a2\sources\tool\import_collision_bsp\build_collision_geometry.c,#979: bsp3d_plane_test_point(plane, point0, NULL)==_bsp3d_plane_test_on

The likely culprit is that your BSP is too large. Scale it down to a reasonable playable size.

Exception: global_plane_count < MAXIMUM_BSP3D_DEPTH

The collision BSP's role is to allow efficient lookups of collideable surfaces (e.g. where a projectile will impact) without the game having to test every single surface in the level. It does this by recursively organizing all surfaces under a tree of dividing planes, where at each branch the game checks only the surfaces in front or behind the plane. The more collision surfaces (triangles) your level has, the more planes are needed to organize them, and at some point a limit of 128 levels is reached. There is no precise polygon limit here because the BSP depth depends a lot on the specific layout of your level, but generally this error means your topology is too dense and you need to reduce polygon counts.

Tool tries to select optimal dividing planes from existing candidate planes in the BSP, namely collideable surfaces and portal planes. As a result certain shapes like spheres can exacerbate the depth issue because there's no face you can pick that splits the sphere in half and Tool is forced to build a very deep and unbalanced tree. Spherical spaces like this represent the worst case for BSP construction.

You can attempt to pass the limit using H1A Tool's -noassert option, but will probably encounter the error "Couldn't build leaf map" next. The best solution is to simplify your geometry and reduce polygon count. From the outset of modeling you should also avoid sculpting tools which generate dense geometry or heavy subdividing. If you absolutely need to maintain existing topology, an advanced workflow is introducing candidate plane hints by intentionally placing collision surfaces or portal planes so they optimally split a problematic area.

Couldn't allocate subcluster

This error means you have too many triangles in a cluster (>16k). Simplify your level geometry or add portals to divide triangles among more clusters.

Exception: dividing_edge->vertex_indices[1]==NONE

In full, this exception appears as:

EXCEPTION halt in .\import_collision_bsp\build_collision_bsp.c,#1529: dividing_edge->vertex_indices[1]==NONE

The exact cause of this is unknown, but it may be related to improper level scale or improper portal placement. Please contact a c20 maintainer if you encounter this.

Portal problems

Warning: Unearthed edge (magenta)

An unearthed edge is where a portal's open edge is exposed within the BSP. It is similar to the open edges error, but for portals. Portal edges should either extend through the BSP or be connected with another portal. If connecting the portal to another portal you must ensure that they are attached at vertices rather than simply touching.

Error: Portal does not define two closed spaces (yellow)

This error is encountered when there are more than two closed spaces (clusters) created by the portal. Portals must create only two clusters. Some scenarios to avoid are:

  • If two portals intersect without being attached at vertices then there are 2 clusters for each side of a portal, which is invalid. Portals should be connected to each other as if they were exact portals connecting to map geometry.
  • If a single portal passes through the BSP multiple times it could create more than two sealed spaces. Simply split up the portal into multiple portals.

Warning: Portal outside the BSP (magenta)

This warning is pretty much what it sounds like -- a portal is completely outside the BSP and therefore serves no purpose. You can delete it or move it into the BSP:

Warning: Portal doesn't divide any space (green)

If you are seeing this warning you likely have other issues with your portals that need addressing first, such as portals outside the BSP or unearthed edges. This warning could not be reproduced in isolation even when placing portal planes outside the BSP, or coincident with its boundary or seamsealer.

Warning: this structure_bsp needs to be reimported for new, faster visibility

This warning is logged when loading a level in Sapien, not when you import a structure or run lightmaps. It indicates some kind of problem with the PVS and your level will probably be invisible despite having run lightmaps. This warning should not be taken literally; at some time during Halo's development a new method of cluster visibility was developed and this message would have told artists to reimport their BSPs. With today's tools it just means that visibility data is invalid somehow.

The only known reason this can happen is if you have a cluster floating in the level that is not touching any level geometry. For example, if you have a cube floating in the air with the +portal material applied to it. This forms a valid cluster surrouned by 6 portals but Tool seems unable to generate the PVS in this case.

Other

Two fog planes intersected in a cluster (black)

This error indicates that you have two fog planes in the same sealed space (cluster). Clusters are only capable of referencing a single fog plane, and only one fog plane can be rendered at a time. You should not only avoid having multiple fog planes within a cluster, but also visible to each other in different clusters (see "two fog planes visible from cluster").

Note that a fog plane which is not completely flat (not planar) will be counted as multiple fog planes because each triangle becomes its own fog plane. You should also make sure that your fog plane's are only as big as they need to be for the space they will be visible in so that it doesn't intersect with other clusters that contain fog planes.

Warning: two fog planes visible from a cluster

Although you can add portals to ensure two fog planes are not in the same localized cluster and avoid "two fog planes intersected in a cluster", Tool will still warn you when two fog planes are potentially visible to each other. In this case Sapien will only allow the assignment of a fog palette to a single fog plane and only one will render in-game.

Consider combining together your fog planes into a singular plane. If this is not desirable because you want different fog palette assignments or fog planes at different heights then you will need to ensure the clusters which contain them are completely isolated from each other either by separating the BSP into two volumes (e.g. connected by a teleporter) or ensuring they are not potentially visible to each other by creating a series of corners and intermediate portals that block visibility.

Warning: Cluster can see multiple skies

According to the material naming conventions, you can reference multiple skies in a BSP by including a sky index in the sky material name, e.g. +sky0, +sky1, +sky2, etc. Similar to how a cluster cannot see multiple fog planes, a cluster cannot see multiple skies either. This warning will happen when you have a cluster with a mix of e.g. +sky0 and +sky1 faces or a cluster where both are potentially visible.

The solution is to either use a single sky or separate the clusters as seen in "two fog planes visible from a cluster".

Weather polyhedra not working

Weather polyhedra are volumes within which weather particles do not render. They are created by assigning the +weatherpoly material to faces which form a convex volume.

If you are finding that a weather polyhedron you created isn't working at all (weather still renders inside of it) then there are two possibilities:

  1. The polyhedron isn't convex. A hypothetical ant standing on any side of the polyhedron should not be able to see any other side or face than the one it's standing on; the surface should always be curving away behind the "horizon" from the ant's point of view. Halo requires these weather-masking volumes to be convex so they can be represented as an efficient series of planes. Modify your polyhedron to be convex or split it into multiple which are.
  2. You have more than 8 weather polyhedra visible at the same time (you can have more than 8 total). Combine some together if possible or alter your level to not require so many.

Error: Couldn't allocate polyhedron plane

This error does not show up in WRL files, but it is usually easy to find. It means one of your weather polyhedra has more than 16 sides. To be clear, this is not a triangle limit for the polyhedron. One side of the shape might be comprised of multiple triangles, but as long as they are coplanar they will be treated as a single side. To resolve this error you can:

  1. Simplify any polyhedra which have too many sides. Players will not notice if a polyhedra doesn't perfectly follow the contour of an overhang. As long as it generally hides rain and snow from under overhangs the effect will be convincing enough. Ensure any sides which are meant to be flat actually have coplanar faces.
  2. Split the polyhedron into multiple more simple shapes. It is OK for the volumes to intersect, just stay within the 8 visible polyhedra limit.
  3. Delete any sides of the polyhedra which are not necessary because they are outside the level and wouldn't usefully "contain" the masking volume. Polyhedra don't actually need to be sealed, in fact a single plane is valid.

Radiosity problems

Degenerate triangle or triangle with bad UVs (blue)

A degenerate triangle error encountered during radiosity is due to a triangle being degenerate in UV space (texture coordinates). In other words, the triangle has zero surface area in UV space because all 3 vertices are in a line or the same location so the triangle's texture will appear extremely stretched. This by itself isn't a problem for radiosity, but when the corresponding material has the simple parameterization flag enabled you will encounter this error, since that flag forces radiosity to use texture UV coordinates as the basis for lightmap UVs and lightmap UVs must not be degenerate.

It is common for modeling operations like extruding and merging to produce degenerate/stretched UVs. You can use Blender's "Correct Face Attributes" tool option to help avoid stretched UVs while modifying your model, or use a simple cube projection to unwrap faces during map development.

Exception: !point_is_coplanar || _realcmp(transformed_point.z, 0.f, k_real_epsilon * 2)

In full this error appears as:

EXCEPTION halt in e:\jenkins\workspace\mcch1code-release\mcc\release\h1\code\h1a2\sources\structures\radiosity\intermediate_radiosity.c,#890: !point_is_coplanar || _realcmp(transformed_point.z, 0.f, k_real_epsilon * 2)

Tool checks that your level will not run into floating point precision problems. If you're getting this error it means your map is probably too big. This was less likely to occur in the legacy HEK because MCC-era tools use SSE2 which has lower floating point precision than the x87 FPU. You can try working around this issue with -noassert, but this may cause problems down the line. It's better to reduce the scale of your level to a reasonable size that the engine was intended to support.

Exception: bitmap_format_type_valid_height(format, _bitmap_type_2d, height)

This means that radiosity has internally completed, but the final resulting lightmap texture would exceed the maximum supported dimensions. This will happen if you have large continuous sections of your level that require a lot of lightmap space, possibly due to them using a high radiosity detail level and/or simple parameterization. Avoid this by:

  • Making your level smaller.
  • Introducing seams to large continuous surfaces, especially those with continuous UV unwraps and simple parameterization. This will let Tool treat the UV islands as different packable charts rather than a single larger one that needs to fit in a single lightmap page. These seams can be separations in UV space or through adding modeled details like short cliffs.
  • Reducing radiosity detail level.
  • Disabling simple parameterization where not needed.

Error: smooth triangle group too big for page

An example error appears like:

radiosity error: smooth triangle group too big for page radon\levels\grounded\shaders\grounded_snow
EXCEPTION halt in e:\jenkins\workspace\mcch1codebuild\mcc\main\h1\code\h1a2\sources\structures\radiosity\intermediate_radiosity.c,#2311: surface_index==last_material->first_surface_index+last_material->surface_count

This likely has the same cause as above; you have a smooth continuous area which should form a single lightmap chart but is too big to fit in a bitmap page.

Warning: Clusters have no background sound or sound environment

During radiosity you may see this warning logged:

<number> clusters in structure_bsp <bsp-tag-path> have no background sound or sound environment.

It is totally harmless and just means you have not assigned background sounds and sound environments to all of your clusters. This step is done in Sapien and is recommended but optional for your map.

JMS problems

Error: reached end of file during parse

This means the JMS file was incomplete or improperly formatted. Tool expected it to have more data but the file ended. You should never see this error unless the JMS exporter addon/script you are using has a bug, in which case you should upgrade it to the latest version or use a different JMS exporter. This error has been known to occur with some 3ds Max scripts.

Error: model file has wrong version number

Your JMS file was exported for the wrong game version (e.g. Halo 2). If using the Halo Asset Blender Development Toolset, pay attention to the export settings and choose Halo CE.

Unknown causes

If you encounter any of these errors, please contact a c20 maintainer so examples can be added.

The following error messages were found in tool.exe but could not be reproduced in experiments:

  • Edge has more than four triangles (red): Attempting to cause this results in "couldn't update edge" errors instead.
  • Error: Edge is too short (red): Creating very short edges leads to degenerate face errors instead.
  • Warning: Found duplicate triangle building connected geometry (orange): Attempting to recreate only causes "couldn't update edge" errors. If you encounter this, probably something is wrong with your JMS exporter.

Acknowledgements

Thanks to the following individuals for their research or contributions to this topic:

  • Conscars (Documenting various problems and solutions)
  • EmmanuelCD (Subcluster limits)
  • Hari (Reverse engineering the cause of T-junction warnings)
  • kornman00 (Theorizing cause of floating point precision differences in MCC-era tools.)