sm64coopdx/docs/lua/guides/lighting-engine.md
PeachyPeach 32f395fb0c
Some checks failed
Build coop / build-linux (push) Has been cancelled
Build coop / build-steamos (push) Has been cancelled
Build coop / build-windows-opengl (push) Has been cancelled
Build coop / build-windows-directx (push) Has been cancelled
Build coop / build-macos-arm (push) Has been cancelled
Build coop / build-macos-intel (push) Has been cancelled
ModFs improvements (#907)
* zip + json properties; check existing file in create file

* smlua_audio_utils_replace_sequence

* audio_stream_load, audio_sample_load, smlua_model_util_get_id

* get_texture_info + can also load PNG files

* smlua_collision_util_get

* add wildcard in properties files + set text mode

* filepath restrictions

* Some mod_storage improvements

- Cache mod storage files into a map to reduce file I/O
- Fix a bug in mod_storage_save
- Add mod_storage_load_all that returns all keys/values as a table

* shutdown; fix buffer overflow; fix warnings; lua table

* reject binary files starting with MZ or ELF

* function members

* better doc

* adding file rewind

* ModFS guide; replace yaml by ini; read string buffer changes
2025-10-21 19:42:06 +02:00

6.9 KiB

Lua Reference

How to use the Lighting Engine

Section 1: Preparation

The Lighting Engine is a vertex point lighting system built directly into sm64coopdx and its renderer. It works on all backends and is relatively easy to use.

To use the Lighting Engine, you need to figure out how you want to approach using it given the different modes it has. There are also 2 methods to enable the lighting engine, either by setting the ambient color, or spawning a point light in.

Section 2: Modes

The lighting engine has 3 modes you can switch between using le_set_mode(mode).

  1. LE_MODE_AFFECT_ALL_SHADED_AND_COLORED: (Default) Applies lighting to every shaded and vertex colored surface minus some geometry and menus.

  2. LE_MODE_AFFECT_ALL_SHADED: Applies lighting to every shaded surface minus some geometry and menus.

  3. LE_MODE_AFFECT_ONLY_GEOMETRY_MODE: Only applies lighting to geometry that has the G_LIGHTING_ENGINE_EXT geometry mode.

LE_MODE_AFFECT_ONLY_GEOMETRY_MODE was the only "mode" until djoslin0 improved the lighting engine and came up with a system for affecting shaded surfaces without needing to apply the lighting engine geometry mode to every actor and level manually.

Section 3: Tonemapping

The lighting engine has 4 tonemapping modes you can switch between using le_set_tone_mapping(toneMapping).

  1. LE_TONE_MAPPING_TOTAL_WEIGHTED: Weighs the combined ambient color and lights together, can look slightly dim.

  2. LE_TONE_MAPPING_WEIGHTED: (Default) Weights the lights on top of the ambient color instead of with it, generally looks the best with good color balance.

  3. LE_TONE_MAPPING_CLAMP: The sum of the lights and ambient color clamped between 0 and 255. Colors can look overexposed if lights are too bright.

  4. LE_TONE_MAPPING_REINHARD: The sum of the lights and ambient color divided by itself + 255, multiplied by 255, and then clamped between 0 and 255. Looks like clamped but dimmed.

You can see the visual differences of the different tonemappings in this video.

Section 4: Ambient Light

There are two ways you can set the ambient color for the scene.

1. le_set_ambient_color(r, g, b)

To set the ambient color directly through code.

2. bhvAmbientLight object with 0xRRGGBB00 behavior parameters

The first 3 bytes are for the red, green, and blue values. This will set the ambient color once on init but not on loop so changing the ambient color is possible.

Be mindful of an annoying SM64 engine quirk: If you set the third byte to 255, which the game uses to store respawn bit information, it will think the light has already been spawned and it won't spawn. There isn't really a way around this except using 254 instead of 255, but le_set_ambient_color does not have this quirk and you can use 255 for the third value.

Section 5: Point Lights

There are two ways you can add point lights in the scene.

1. le_add_light(x, y, z, r, g, b, radius, intensity)

To spawn a point light directly through code.

Parameter Description
x X coordinate
y Y coordinate
z Z coordinate
r Red value
g Green value
b Blue value
radius How many units out the light should spread, 500-1000 units recommended.
intensity How much influence/brightness the light has, 2.0 recommended.

2. bhvPointLight object with 0xRRGGBBWW behavior parameters

The first 3 bytes are for the red, green, and blue values. The Ws are an arbitrary letter I picked for the fourth byte to represent radius. Due to only having one byte to represent radius, I opted to make it so whatever you have for radius in the 4th byte gets multiplied by 10 for a bigger range. If you have 0x64 (100) then your light will have a radius of 1000. The default intensity is 2.

The point light object has some special exclusive behavior made possible from it being tied to the object system instead of a separate list. If you give it a parent object, the light will copy its position to the parent and delete itself when the parent is deleted. Other than that, changing the position of the light object will change the actual light's position but you are able to modify the other properties without it being forced by the object.

Initially, I made it so it always copied the color and radius to match behavior parameters but I figured it would be easier if you could just edit the properties directly without having to go through tedious behavior parameter bit shifting and whatnot.

You can also make your own light behavior and call bhv_point_light_init() and or bhv_point_light_loop() if you just want to add onto the behavior for your version.

Section 6: Light Functions

Function Description
le_is_enabled() Gets whether the lighting engine has been enabled or not. It becomes enabled once a light is added or the ambient color is set
le_calculate_lighting_color(pos, out, lightIntensityScalar) In case you wanted to calculate lighting color in Lua for whatever reason. Calculates the lighting with lightIntensityScalar at a position and outputs the color in out
le_calculate_lighting_color_with_normal(pos, normal, out, lightIntensityScalar) Calculates the lighting with lightIntensityScalar at a position and with a normal and outputs the color in out
le_calculate_lighting_dir(pos, out) An additional function not used by the lighting engine. Calculates the lighting direction from a position and outputs the result in out
le_remove_light() Removes a lighting engine point light corresponding to id
le_get_light_count() Gets the total number of lights currently loaded in the lighting engine
le_light_exists() Checks if a lighting engine point light corresponding to id exists
le_get_ambient_color(out) Outputs the lighting engine's ambient color to out
le_get_light_pos(id, out) Outputs a lighting engine point light's position to out
le_set_light_pos(id, x, y, z) Sets a lighting engine point light's position to x, y, z
le_get_light_color(id, out) Outputs a lighting engine point light's color to out
le_set_light_color(id, r, g, b) Sets a lighting engine point light's color to r, g, b
le_get_light_radius(id) Gets a lighting engine point light's radius
le_set_light_radius(id, radius) Sets a lighting engine point light's radius
le_get_light_intensity(id) Gets a lighting engine point light's intensity
le_set_light_intensity(id, intensity) Sets a lighting engine point light's intensity
le_get_light_use_surface_normals(id) Gets whether a lighting engine point light will use a surface's normals to determine its brightness with useSurfaceNormals
le_set_light_use_surface_normals(id, useSurfaceNormals) Sets whether a lighting engine point light will use a surface's normals to determine its brightness with useSurfaceNormals