Skip to content

23. Lighting - 1

Dated: 26-06-2025

Mathematics of Color in Computer Graphics

A color can be represented by either a 3D vector1 (rgb) or 4D vector1 (rgba). The values can be represented within a range \([0, 1]\).
A 24 bit display has \(24\) bits to use for colors.

\[\frac {24 \text{ bits}} {3 \text{ colors}} = 8 \text{ bits per color}\]

This is generally called true color because \(256^3 = 16.7 M\) is the total number of colors your eyes can discern.

Representing the Colors

struct color3 {
    float r, g, b;
};
struct color4 {
    float r, g, b;
    float a; // Alpha channel for transparency
};

\(r, g\) and \(b\) must be within \([0, 1]\).

The gamut is the physical range of colors a monitor can display.

Side Note

Printers usually use HSV (hue, saturation and value) color spaces.

Why We Might want 128-BIT Color

Mike Abrash (1992) recounts a shift from 256-color palettes to hardware supporting 16 million colors and questions how we’d use them all. He cites Sheldon Linker’s story from the 1970s, where JPL printed text with background colors differing by a single index. Surprisingly, the words were still readable—our eyes are highly sensitive to subtle color changes. On screens, however, only ~16 million colors were distinguishable, showing that the eye perceives reflected light (print) better than emissive light (monitors). The takeaway: human vision is precise, and 24-bit color isn't as much as it seems—round-off errors matter.

cs602_i_23_1.png

The CIE diagrams

Multiplying Color Values

The calculation of color of a particular pixel2 depends upon

  • Surface's material properties
  • Color of ambient light (lighting model)
  • Light shining on the surface
  • Scattering surfaces (e.g. fog) between viewport and the surface

Example

Let there be a light source of lime green color \(c_l = (0.34765, 0.92578, 0.24609)\) and a surface of magenta color \(c_s = (0.86719, 0.00000, 0.98828)\).

\[c_l \otimes c_s = (0.34765, 0.92578, 0.24609) \otimes (0.86719, 0.00000, 0.98828)\]
\[= (0.34765 \times 0.86719, 0.92578 \times 0.00000, 0.24609 \times 0.98828)\]
\[= (0.30148, 0.00000, 0.243210)\]

Because the values themselves are below \(1\), therefore, we lose light intensity with each operation.

Dealing with Saturated Colors

\[C_1 = (1.0,0.49,0.0) \text{ and } C_2 = (0.0,1.0,0.49)\]
\[C = C_1 + C_2 = (1.0, 1.49, 0.49)\]

This color exceeds the range that the hardware can display.
There are 3 approaches to solve this.

  • Clamp the color within the \([0, 1]\) range but at cost of shifting the color.
  • Scale down the color by its larger component but reducing the intensity.
  • Clip the intense color components and increase the other components to maintain intensity.

References


  1. Read more about vectors

  2. Read more about pixels