Background Background Background Background Background Background


Understanding rgbGen (vertex colour)

There are two color sources for any given shader, the texture file and the vertex colors.

Vertex color is the per-vertex RGB (and optionally alpha) data that the renderer assigns to each vertex before it’s sent through the shader stage. It’s like each vertex carrying its own mini light value, which is then interpolated across the surface. idTech 3 can get per-vertex color data from a few sources, the map lightgrid / static lighting, dynamic lights and vertex painting in models.

Output at any given time will be equal to TEXTURE multiplied by VERTEXCOLOR. Most of the time VERTEXCOLOR will default to white (which is a normalized value of 1.0), so output will be TEXTURE (this usually lands in the Source side of the shader equation).

Sometimes you do the opposite and use TEXTURE = WHITE, but this is only commonly used when doing specular lighting on entities (i.e. shaders that level designers will probably never create.)

Where rgbGen fits in the pipeline

Within a single shader stage, the renderer roughly:

  1. Loads the stage texture.
  2. Determines the color via rgbGen (and alpha via alphaGen).
  3. Multiplies the texture by that generated color.
  4. Blends the result to the framebuffer using blendFunc.

How it combines with the texture

FinalStageColor = TextureRGB × rgbGenOutput

rgbGen produces a color multiplier before blending, so it tints/brightens/dims the stage’s texture ahead of any blendFunc. White leaves the texture unchanged, colored values tint, animated values pulse.

Because of this sequence, it is always advised that rgbGen comes before any blendFunc modes in shader stages.

The main rgbGen modes

The most common reason to use rgbGen is to pulsate something. This means that the VERTEXCOLOR will oscillate between two values, and that value will be multiplied (darkening) the texture.

The next most frequent would be to specify a model to light itself with vertex lighting rather than identity. This is because if no rgbGen is specified, either "identityLighting" or "identity" will be selected, depending on which blend modes are used.

LightingDiffuse uses per-vertex lighting info so the weapon shading changes with the environment. If you swapped it with rgbGen vertex, you’d just use the pre-lit vertex colors.

Other modes are listed below, most of which have more specific use cases.

CommandBehaviorTypical Use
rgbGen identity Uses pure white (1,1,1). Texture is unmodified by a stage‑color. Decals, unlit sprites.
rgbGen vertex Uses per‑vertex color from lighting/lightgrid. Light‑affected geometry and models.
rgbGen exactVertex Like vertex but bypasses scaling/gamma tweaks. Precise lighting control.
rgbGen lightingDiffuse Per‑vertex diffuse lighting result (dynamic‑light aware). It uses the vertex normals to illuminate the object correctly. Model shading, lit surfaces.
rgbGen wave <func> <base> <amp> <phase> <freq> Time‑varying color multiplier from a waveform. Pulses, glows, animated tints.
rgbGen const r g b Fixed RGB multiplier. Permanent tinting.
rgbGen oneMinusVertex Uses 1 - vertexColor. Inverse/masking tricks.

How vertex color is used in shaders

When you use rgbGen vertex it tells that stage to multiply the texture by the interpolated per-vertex RGB values.

FinalColor = TextureRGB × InterpolatedVertexColor

That interpolation is per-fragment, so each pixel between two vertices gets a blended value based on distance. This is why lights can create soft shading across a surface even without lightmaps.

Waveform syntax

rgbGen wave <func> <base> <amplitude> <phase> <frequency>
  • func: refer to waveform functions; sin, triangle, square, sawtooth, inversesawtooth, noise
  • base: starting offset (0 - 1)
  • amplitude: how far it varies from base
  • phase: initial position in the cycle
  • frequency: cycles per second
rgbGen wave sin 0.5 0.5 0 1

This oscillates brightness from 0.0 to 1.0 once per second.