Skip to content

Commit

Permalink
Merge branch 'portals-guide'
Browse files Browse the repository at this point in the history
  • Loading branch information
csauve committed Apr 16, 2024
2 parents bfee60c + 1762afa commit e1260d0
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 21 deletions.
4 changes: 2 additions & 2 deletions src/content/h1/guides/levels/box-level/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ The tags are now ready so let's test the level in-game. How you do this will dep

{% tabs id="testing" %}
{% tab label="Testing with Standalone" %}
If you're using the H1A mod tools you can [use Standalone](~h1-standalone-build#usage) to test the scenario. Standalone is preferable to testing in MCC itself during development since it includes debug features and loads tag files directly, avoiding the need to build a map `file` with Tool and install it into MCC. Run `halo_tag_test.exe` and enter the following into the [developer console](~developer-console):
If you're using the H1A mod tools you can [use Standalone](~h1-standalone-build#usage) to test the scenario. Standalone is preferable to testing in MCC itself during development since it includes debug features and loads tag files directly, avoiding the need to build a map file with Tool and install it into MCC. Run `halo_tag_test.exe` and enter the following into the [developer console](~developer-console):

```console
game_variant slayer ; only if your level is a multiplayer map
Expand All @@ -375,7 +375,7 @@ If you're using the HEK and targeting Halo Custom Edition then you need to build
tool build-cache-file levels\test\example\example
```

This will produce `maps\example.map`. You can then launch Custom Edition and load this level, either via UI for MP maps or [via the console if enabled](~developer-console#usage):
This will produce `maps\example.map`. You can then launch Custom Edition and load this level, either via the UI for MP maps or [via the console if enabled](~developer-console#usage):

```console
map_name example ; if SP
Expand Down
2 changes: 2 additions & 0 deletions src/content/h1/guides/levels/bsp-troubleshooting/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ EXCEPTION halt in .\import_collision_bsp\build_collision_bsp.c,#1529: dividing_e
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
Be sure to follow the [portal placement rules](~portals-and-clusters#placement-rules) or you may encounter these types of issues:

## 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](#error-edge-is-open-red), 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.

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/content/h1/guides/levels/portals-and-clusters/portals.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
70 changes: 70 additions & 0 deletions src/content/h1/guides/levels/portals-and-clusters/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
title: Portals and clusters
thanks:
Conscars: Writing this guide
---
The concepts of _portals_ (not to be confused with teleporters) and _clusters_ are a frequent source of difficulty and misunderstanding for new level artists. Let's demystify them so you can get the most from your levels.

# What are portals?
{% figure src="portals.jpg" %}
Rat Race's portals visible with `debug_pvs 1`.
{% /figure %}

[_Portals_](~scenario_structure_bsp#portals) are invisible "doorways" that divide a level's space into a series of closed room-like _clusters_, and are placed by artists when modeling the level in their 3D software.

[Portal rendering][wiki] is a common decades-old techique which Halo has adapted for its mixed indoor/outdoor levels. Imagine your home's interior as a 3D model with various rooms with doorways between them. How would you render a viewpoint from a given room?

1. You could render just the faces belonging to the current room, but you would miss parts of an adjacent visible room.
2. You could render all the faces in the house to make sure, but this isn't performant.
3. You could identify just the set of rooms that might be visible from the current room and render only their faces.

Option 3 is clearly the best, and since the scene is static (non-moving) you can precalculate which rooms are visible to each other through adjacent or even multiple doorways. This is called a [potentially visible set](~scenario_structure_bsp#potentially-visible-set) and it's [calculated by Tool][portal-pvs] when importing your BSP tag. It relies on your level effectively being a series of rooms (_clusters_) only connected by doorways (_portals_) and is part of the reason you follow the [sealed world rules](~bsp-troubleshooting#sealed-world-rules).

Halo further groups the faces within each cluster into [_subclusters_](~scenario_structure_bsp#tag-field-clusters-subclusters) contained within bounding boxes. It then uses [portal-based occlusion culling][portal-occlusion] to limit which subclusters and [objects](~object) in the PVS will actually get rendered based on the camera's location. This is still important to do even with modern hardware, and you can get a lot of benefit from just a few well-placed portals.

# What are clusters?
{% figure src="clusters.jpg" %}
The a30_a BSP divides its walkable outdoor space into 11 clusters, with various background sounds assigned to each (color coded). The surrounding space where the camera occupies is also a single large cluster.
{% /figure %}

[_Clusters_](~scenario_structure_bsp#clusters-and-cluster-data) are sections of your level, sealed by the level geometry and/or portals connecting to other clusters. Placing valid portals causes the level to be split into multiple clusters. A level without any portals usually has a single large cluster, or multiple clusters in the case of a level like Chiron TL-34 which has multiple completely separated rooms.

Each cluster can be assigned unique weather, sound environment, background sound, sky, and fog using [Sapien](~h1-sapien). Therefore portals are also an artistic tool that let you define areas of your map with differing environmental properties which will apply when the camera is in that cluster.

# Portal placement
To create portals you need to add extra geometry to your level's model with certain [material names or symbols](~h1-materials):

* The `+portal` material name creates normal portal planes suitable for a variety of locations, like outdoors, hallways, and doorways.
* The `+exactportal` material name requires the portal geometry to exactly follow the edges and vertices of a doorway it seals off.
* The `.` material symbol causes an existing material to also act like an exact portal, e.g. `floor_grate%.`. It's suitable when the existing material is always used in a way where it would form a good exact portal too, like floor gratings over sealed-off pits.

## Placement rules
You need to follow some rules when adding portal geometry, or else you will encounter [problems](~bsp-troubleshooting#portal-problems) when importing the BSP:

* There must not be any leaks around a portal, called "unearthed edges". They need to form a perfect seal against the level and/or other portals. Exact portals must follow the edges and vertices of a doorway, while regular portal planes can intersect the level like a knife to form their seal.
* All entrances to a sealed space must have portals. If you have a small base with 1 doorway and 2 windows, then you need 3 portals to seal off the interior space of the base from the outdoor space. These could be a mix a regular and exact portals.
* A single portal cannot seal multiple entrances and must separate exactly 2 spaces.
* Portals must not intersect each other, but can be connected to each other along their edges.
* Portals must be grounded to the level geometry in some way. Don't create floating cubes of portals which form an empty cluster in mid-air.
* Prefer portals which are perfectly planar (flat) since it will reduce the amount of portal data needed and help you avoid hitting limits.

# Related HaloScript
{% relatedHsc game="h1" tagFilter="portals" /%}

# External tutorials
{% dataTable
dataPath="tutorials/tutorials"
rowSortKey="updated"
rowSortReverse=true
columns=[
{name: "Name", key: "name/en"},
{name: "Description", key: "description/en"},
{name: "Author(s)", key: "authors"},
{name: "Last updated", key: "updated"},
{name: "Links", key: "links/en"}
]
/%}

[portal-pvs]: https://www.youtube.com/watch?v=Mr1vHM0P8U4
[portal-occlusion]: https://www.youtube.com/watch?v=8xgb-ZcZV9s
[wiki]: https://en.wikipedia.org/wiki/Portal_rendering
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
tutorials:
- name:
en: Saving space by making portals fully coplanar
description:
en: How to stay under the [BSP](~scenario_structure_bsp) portal limit by optimizing the amount of data Halo needs to store them.
authors: MosesofEgypt
updated: "2014"
links:
en: "[Imgur](https://i.imgur.com/MxYJRNM.png)"
1 change: 1 addition & 0 deletions src/content/h1/guides/levels/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ thanks:
childOrder:
- box-level
- bsp-troubleshooting
- portals-and-clusters
- advanced
- additional
redirects:
Expand Down
10 changes: 0 additions & 10 deletions src/content/h1/guides/levels/tutorials.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,6 @@ tutorials:
- level
links:
en: "[halonet.net](http://reclaimed.halonet.net/content/tutorial/detail_objects_collection/zexgx_dobc.pdf)"
- name:
en: Saving space by making portals fully coplanar
description:
en: How to stay under the [BSP](~scenario_structure_bsp) portal limit by optimizing the amount of data Halo needs to store them.
authors: MosesofEgypt
updated: "2014"
tags:
- level
links:
en: "[Imgur](https://i.imgur.com/MxYJRNM.png)"
- name:
en: Intro to water
description:
Expand Down
6 changes: 5 additions & 1 deletion src/content/h1/h1-ek/h1-sapien/crashes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,8 @@ crashes:
- error: >-
EXCEPTION halt in \halopc\haloce\source\tag_files\tag_groups.c,#3142: offset>=0 && offset+size<=data->size
solution: >-
You may have a corrupted [sound](~) tag which was extracted with [HEK+](~obsolete#hek). Always use [invader-extract](~) instead.
You may have a corrupted [sound](~) tag which was extracted with [HEK+](~obsolete#hek). Always use [invader-extract](~) instead.
- error: >-
EXCEPTION halt in c:\mcc\main\h1\code\h1a2\sources\render\render.c,#249: !memcmp(&window->render_camera.viewport_bounds, &window->rasterizer_camera.viewport_bounds, sizeof(rectangle2d))
solution: >-
You resized the game window while `debug_render_freeze` was enabled. Disable it first.
9 changes: 4 additions & 5 deletions src/content/h1/h1-ek/h1-tool/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,17 @@ A [scenario](~) can be built into a [map](~maps) using the `build-cache-file` ve
```cmd
Usage: build-cache-file <scenario-name> <classic|remastered> [resource-map-usage<none|read|read_write>] [log-tag-loads]
tool build-cache-file "levels\test\tutorial\tutorial"
tool build-cache-file "levels\test\tutorial\tutorial" classic 0 # classic graphics with update resource disabled
tool build-cache-file "levels\test\tutorial\tutorial" remastered
tool build-cache-file "levels\test\tutorial\tutorial" classic none
```

Arguments:
* scenario-name - A local tag path to your scenario without the file extension.
* classic|remastered - H1A Tool only. Whether or not S3D is disabled. There is no way to edit S3D files currently so only use remastered if you know what you're doing:
* `classic` - Disables the S3D graphics engine. Users will not be able to toggle to the remastered graphics or sounds. This is intended for custom maps that don't support remastered graphics.
* `remastered` - Enables the S3D graphics engine. Users will be able to toggle to the remastered graphics and sounds. This is intended for building maps compatible with S3D-based remastered graphics and sounds. Some HUD bitmaps will be read from S3D data files instead of tags.
* `remastered` - Enables the S3D graphics engine. Users will be able to toggle to the remastered graphics and sounds. This is intended for building maps compatible with S3D-based remastered graphics and sounds. Some HUD bitmaps will be read from S3D data files instead of tags. Make sure you're not including any objects in your map which don't have remastered graphics support, such as the flamethrower, or else MCC will crash.
* resource-map-usage - H1A Tool only. How Tool uses [resource maps](~maps#resource-maps) such a bitmaps.map and sounds.map during map packaging.
* `none` - Tool will build self-contained maps and resource maps will not be used during packaging. All assets will be internalized. This is the default and also the behaviour when resource maps are missing from their expected location under the editing kit's `maps` folder.
* `read` - Tool will allow your map to rely on tags within `bitmaps.map` and `sounds.map` if present. Any assets that don't exist will instead be internalized.
* `read` - Tool will allow your map to rely on tags within `maps\bitmaps.map` and `maps\sounds.map` if present. Any assets that don't exist will instead be internalized. Make sure the resource maps are exact copies of the ones the game will use at runtime, or else the assets will be incorrectly referenced and all textures will appear corrupted in-game.
* `read_write` - Tool will add bitmaps and sounds from the map being built into the respective resource maps if they weren't already present. [Lightmaps](~) bitmaps are still kept in the map's own cache file rather than added to `bitmaps.map`.
* log-tag-loads - H1A Tool only. A `true` or `false` arg that writes the tags loading during packaging to `tool_tags_loaded.txt` in the H1AEK root. This helps build a list of tags needed for a scenario if you are releasing a tag set.

Expand Down Expand Up @@ -481,7 +480,7 @@ tool physics "vehicles\wraith"

For the example above, Tool would expect to find a corresponding JMS file at `data\vehicles\wraith\physics\wraith.JMS`. Assuming no errors, it would be imported as `tags\wraith\wraith.physics`.

## Plate
## plate
H1A Tool only. The plate verb takes a set of images and places them in a sequence surrounded by a border to be imported as either sprites or animated images.

```cmd
Expand Down
8 changes: 8 additions & 0 deletions src/data/hsc/h1/functions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3086,13 +3086,17 @@ functions:
(<void> object_pvs_activate <object>)
```
Just another (old) name for object_pvs_set_object.
tags:
- portals
- slug: object_pvs_clear
info:
en: |-
```hsc
(<void> object_pvs_clear)
```
Removes the special place that activates everything it sees.
tags:
- portals
- slug: object_pvs_set_camera
info:
en: >-
Expand All @@ -3104,6 +3108,8 @@ functions:
Sets the specified cutscene camera point as the special place that activates
everything it sees.
tags:
- portals
- slug: object_pvs_set_object
info:
en: >-
Expand All @@ -3115,6 +3121,8 @@ functions:
Sets the specified object as the special place that activates everything
it sees.
tags:
- portals
- slug: object_set_collideable
info:
en: |-
Expand Down
10 changes: 7 additions & 3 deletions src/data/hsc/h1/globals.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1803,9 +1803,8 @@ external_globals:
```hsc
(debug_no_frustum_clip [boolean])
```
If frustum clipping is disabled by setting this to `true`, certain
objects and parts of the BSP will be drawn even when behind foreground
geometry (use `rasterizer_wireframe 1` to see this).
Disables portal-based occlusion culling for objects and parts of the BSP
(use `rasterizer_wireframe 1` to see this).
This isn't about clipping to the whole view frustum but rather _portal diminished frustrums_;
in addition to the [PVS](~scenario_structure_bsp#potentially-visible-set),
the game seems to cull objects and the BSP by whether object bounding
Expand Down Expand Up @@ -2156,6 +2155,8 @@ external_globals:
origin, FP models, and some debug overlays will still be based on the
previously frozen camera location. This command is useful for inspecting
portal behaviour where the camera cannot directly see.
tags:
- portals
- slug: debug_score
info:
en: |-
Expand Down Expand Up @@ -2235,6 +2236,7 @@ external_globals:
tags:
- sound
- scenario_structure_bsp
- portals
info:
en: |-
```hsc
Expand Down Expand Up @@ -3480,6 +3482,8 @@ external_globals:
Toggles rendering in wireframe mode, which only draws pixels along triangle
edges rather than filling trangles. This can be useful for troubleshooting
portals.
tags:
- portals
- slug: rasterizer_zbias
info:
en: |-
Expand Down

0 comments on commit e1260d0

Please sign in to comment.