Skip to content

How does the engine work?

MarkelZ edited this page Aug 30, 2023 · 18 revisions

To understand how the lighting engine works, let's first make clear what exactly the engine must do.

The engine renders a scene with three layers: a background, a light map, and a foreground. The user can draw the game objects that require lighting (such as the player and enemies) in the background layers, and the ones that do not need lighting in the foreground (such as the HUD). Afterwards, the engine must generate the light map and combine all three layers before displaying it on the screen, which is done in the render call of the lighting engine.

For all three layers, OpenGL FBOs are used. There are also some intermediate layers used for rendering, such as a double buffer object for incrementally rendering the lights.

Rendering textures in the background and foreground layers is straight-forward. The FBO corresponding to the layer is set as the target and the texture is rendered with a dummy shader and a VBO corresponding to the location of the texture in said layer.

For the light map, the lights are rendered one at a time. A double buffer is used to merge a single light's light map with the rest of the lights.

Before rendering the lights, we send all the hull vertex coordinates to the light's shader program using an SSBO. Since all the lights share the same hulls, this information is sent only once per render.

For rendering a light and its shadows, we use the fragment_light.glsl fragment shader. A fragment shader allows us to tell OpenGL how to process each individual pixel.

A light's fragment shader does the following for calculating the light value of a given pixel:

  1. Consider the line segment from the light source to the pixel.
  2. If the line segment intersects the boundary of a hull, it is ocluded.
  3. If the pixel is ocluded, do not brighten up the pixel because it lays in the shadow.
  4. If the pixel is not ocluded, brighten up the pixel.
    • To determine how bright the pixel should be, use the distance from the light source's location to the pixel's location.
    • Calculate the brightness with a cubic spline, so that it fades smoothly until the brightness becomes 0 when the distance reaches the radius of the light.
    • Multiply the brightness value with the color of the light.
    • Blend the resulting color with all the other lights additively.

Once all the brightness values are computed in the light double buffer, the engine applies Gaussian blur to soften the shadows. The result is stored in an intermediate layer using an FBO called _fbo_ao (the ambient occlusion map).

Finally, the engine merges the background layer with the aomap with multiplicative blending, and then overlays the foreground layer.

Clone this wiki locally