Ambient light

From Valve Developer Community
Revision as of 03:23, 10 February 2024 by TiberiumFusion (talk | contribs) (More of the previous)
Jump to navigation Jump to search

Ambient light is the general amount of light that models receive from their environment. Compared to dynamic direct lights, ambient light is the light that is "already there" and is often the most significant contributor to model lighting in the absence of intense direct lights. In Source, ambient light comes exclusively from static map light sources that are created in Hammer. It is pre-calculated by VRAD during map compile and reduced to a small but relatively accurate approximation for use at runtime.

Stage 1: Hammer

The map creator must place one or more static light sources in the map. These are the only light sources which contribute to VRAD's simulation and are thus the only way to add ambient light to a map.

Stage 2: VRAD and Ambient Cubes

Ambient cubes within the red-outlined visleaf. Note how the "left" side of several cubes is brighter than the front - this is the result of the bright sunlight reaching the cubes after reflecting off the angled wall.

VRAD runs an extensive radiosity simulation, calculating the emission, reflection, and absorption of light within the entire sealed volume of the world. Light originates from static map lights, bounces off world surfaces, and is attenuated per the material parameters of those surfaces and the lights.rad file. When the simulation is complete, it is possible to sample any arbitrary position in the world's volume and receive the total amount of incoming light from all directions at that position. This now becomes the ambient light at that position.

VRAD's work is exceptionally slow and is not feasible for realtime rendering. Additionally, storing the entire result of the simulation in the bsp would create prohibitively massive map files. To optimize both ingame rendering and storage, VRAD only stores a tiny number of ambient light samples in the map file. Each visleaf receives only a sparse handful of samples, known as "ambient cubes", which are distributed throughout the visleaf. VRAD attempts to evenly balance the distribution of ambient cubes among differently sized visleafs, but smaller visleaves will typically have more ambient cubes than larger ones. Each ambient cube only stores the incoming ambient light from the 6 cardinal directions that align with the normals of the cube's 6 faces. When ingame, the commands mat_leafvis 1 and r_visambient 1 will reveal the ambient cubes.

Stage 3: In the Engine

Forward rendering in Source. Note the "Ambient Cube" pass, wherein Alyx is subtly illuminated by gray-blue light bouncing off the gray-blue walls.

With VRAD's enormous simulation reduced to just a few thousand ambient cubes, approximate realtime ambient lighting is now feasible. The ambient cubes provide two types of incoming light: direct and indirect. All ambient light is sampled relative to the model's $illumposition and the nearest ambient cube(s); there is no per-vertex or per-pixel ambient lighting technique.

Tip.pngTip:The role of $illumposition is why models sometimes appear much darker than they should when placed against a wall or near an elevation change in the ground. The $illumposition is now proximal to an ambient cube that is on the other side of the wall or ground.

Direct Ambient Light

All entities always receive direct ambient light from the nearest ambient cube. This is light which originates from the faces of the ambient cube (as pre-calculated by VRAD during map compile) and directly hits the surface of the model.

Indirect Ambient Light

There are several available techniques to add approximate indirect ambient light to models; all are optional and controlled by the cheat-protected r_radiosity convar.

Indirect ambient light is the light which bounces off nearby surfaces before reaching the model, thus slightly modulating the color of the model with the color of the bounced surface. It primarily adds realism by contributing the subtle color changes across a model's surface that are expected in large, open areas with many varied light sources (such as an outdoor sky). It also helps "fill in" the dark spots and tight crevices on a model.

Compared to direct ambient light, indirect ambient light is typically a much lesser term and is not immediately obvious in most situations. Indirect ambient light is most easily observed in a well-lit area where a curved, predominantly white model is placed near a richly colored surface, e.g. a white egg sitting on a bright green carpet. Neither the egg nor the carpet are specular, but the underside of the egg will be tinted green as it is illuminated by light that reflects off the carpet.

  • Dynamically-lit objects, including players & dynamic props, have their indirect ambient lighting calculated every frame, since these objects move around. The lighting technique uses either the map's ambient cubes for a cheap approximation (modes 1, 3, and 4) or a much more expensive but still very limited raytracing routine (mode 2). The raytracing routine produces the most characteristic lighting, since it is the only mode which incorporates the color of local surfaces, notably the ground and the skybox.
  • Statically-lit objects, such as static props placed in Hammer, have their indirect ambient lighting calculated only once, when the map is loading. Since their lightning is rendered offline and only once, most of the r_radiosity choices (modes 2, 3, and 4) use the aforementioned raytracing routine for static props, instead of the cheap approximation. Changing the convars which control ambient lighting requires restarting the map to re-render the lighting for these static props.

See the r_radiosity convar below for more information on the various indirect ambient lighting modes.

Todo: Add a section fully explaining the concept, purpose, and application of the ambient boost mechanic.

Console commands

mat_leafvis 1; r_visambient 1
These two commands together enable the display the ambient lighting sample points in the active leaf.
r_flashlightambient <int>
Seems like it would be used for making ambient light originating from projected textures or for influencing the color of the flashlight based on ambient light. Does not do anything in Half-Life 2.
r_lightcache_numambientsamples <int>
Cheat. The number of random directions to fire rays when computing ambient lighting. Default 162. Requires map restart.
Confirm:This only affects static props.
r_ambientlightingonly <bool>
Cheat. Light models with only ambient lighting; requires map restart.
r_radiosity <int>
Cheat. Selects the extent and technique used to calculate indirect ambient lighting on entities. Mode 2 typically produces the most interesting lighting.
  • 0 = No indirect ambient light
VRAD-compiled lights contribute only direct ambient light to models. In some games, this mode also disables the direct ambient light, resulting in pitch black models in the absence of any realtime lights.
  • 1 = Cheap indirect ambient light on everything
All models receive a very rough approximation of indirect ambient light, using only the light which VRAD calculated and stored along the nearest ambient cube's 6 axis-aligned normals. When there is significant difference in the amount of light exposure at the model's location versus at the nearest ambient cube, the model will be incorrectly lighter or darker than its surroundings.
  • 2 = Raytraced indirect ambient light on everything
All models receive a greatly improved approximation of indirect ambient light from their own position. Indirect ambient light is calculated in real time along r_lightcache_numambientsamples directions originating from the model's $illumposition, arranged in a sphere for equal coverage. Each sample contributes reflected light from the surface it strikes - such as walls, the ground, and the skybox - making this the only mode with the potential to accurately illuminate a model when the nearest ambient cube is too disparate. Generally, this mode produces the most accurate final model lighting, though it is not without shortcomings. Bounced surface materials with non-albedo $basetextures and/or incorrect reflectivity values will introduce erroneous additional light, frequently causing models to appear anywhere from slightly brighter to noticeably brighter than they should be. With the default value of 162 for r_lightcache_numambientsamples, subtle light details are typically captured and models appear softer and "fuller", especially compared to the sharp, orthogonal lighting produced by the simplistic r_radiosity 1 mode.
  • 3 = Raytraced indirect ambient light on static props, cheap indirect ambient light on everything else
Static props receive indirect ambient light per r_radiosity 2, while everything else receives indirect ambient light per r_radiosity 1. This is the default value for most Source games.
  • 4 = Raytraced indirect ambient light on static props, reconstructed indirect ambient light on everything else
Static props receive indirect ambient light per r_radiosity 2, while everything else receives indirect ambient light from an alternate ambient cube algorithm. Instead prescribing the nearest ambient cube's exposure to the model, this mode attempts to reconstruct VRAD's high-resolution ambient light calculation at the model's actual location, using only the handful of ambient cubes that VRAD left behind in the visleaf where the model is currently located. In practice, the end result lands somewhere between r_radiosity 1 and r_radiosity 2 in all regards. Since there are often very few ambient cubes in any visleaf compared to 162 r_lightcache_numambientsamples, this mode is often faster than r_radiosity 2, while still producing a more accurate result than r_radiosity 1, especially when the model is very close to an ambient cube. It has significant drawbacks, however. Most notably, the small number of available ambient cubes results in a reconstructed term that is highly diffuse throughout the visleaf, often causing models to receive a near constant amount of indirect ambient light in the vicinity of any given ambient cube. Additionally, the spareness of the ambient cubes and their great variation in location will fail to accurately represent the light received from bounces off brushes extremely local to the model, such as walls and the ground. As a result, the dark spots, tight crevices, and underside of the model tend to receive more light than they should, reducing the contrast of the model's curvature and making it appear brighter and "flatter". Finally, this mode fails to account for the map's lightstyle, causing models to appear much brighter than they should when lightstyle is used to reduce the overall map light.
  • Values below 0 or above 4 are myths and are equivalent to r_radiosity 0.
r_ambientboost <bool>
Boosts ambient term if it is totally swamped by local lights.
r_ambientmin <float>
Threshold above which ambient cube will not boost (i.e. it's already sufficiently bright). Default 0.3.
r_ambientfraction <float>
Cheat. Fraction of direct lighting that ambient cube must be below to trigger boosting. Default 0.1.
r_ambientfactor <float>
Boost ambient cube by no more than this factor. Default 5.