From light to colour coordinates
A light stimulus reaches the eye as a spectral power distributionA description of how much radiant power a light stimulus contains at each wavelength.: power at each wavelength. RGB values are not hiding inside that spectrum. They appear only after a measurement system asks how the spectrum excites three chosen responses.
- RadiometryMeasurement of electromagnetic radiation in physical power units, without weighting it for human visual sensitivity. measures physical radiant power.
- PhotometryMeasurement of visible light after radiant power is weighted by a standardized model of human brightness sensitivity. weights that power by the standard photopic sensitivity of human vision, producing quantities such as luminous flux and luminance.
- ColorimetryMeasurement and numerical description of colour matches using a standard observer and specified viewing conditions. keeps three weighted responses so that colour matches, rather than brightness alone, can be recorded.
The colour-matching experiment
In the experiments behind early standard colorimetry, a monochromatic test light filled one half of a small field. An adjustable mixture of three chosen primary lights filled the other half. The observer changed the three primary amounts until both halves appeared to have the same colour. Repeating this for many test wavelengths produced three RGB colour-matching functions.
Some wavelengths could not be matched using only positive amounts of the three primaries. The experimenter therefore added one primary to the test side; that primary’s matching coefficient was recorded as negative. A negative coefficient does not mean negative light. It records which side of the comparison received that primary.
XYZ is derived, not read directly from the eye. CIE applied a linear
transformation to the experimental RGB matching functions. The resulting XYZ
system uses convenient non-negative functions, with Y aligned to the photopic
luminance response. It is a standardized description of visual matches, not a
claim that every spectrum contains three hidden RGB values.
From spectra to CIE XYZ
The CIE 1931 standard observerA standardized set of colour-matching functions representing average human colour-matching behaviour, not a physical camera sensor. defines three colour-matching functions,
x̄(λ), ȳ(λ), and z̄(λ). A spectrum S(λ) is reduced to three tristimulus
values by three weighted sums:
The normalising factor k depends on the measurement convention. Y is
constructed to carry the luminance-related response. Different spectra can
produce the same XYZ triplet; such spectra are metamersDifferent spectra that produce the same tristimulus values for a specified observer and viewing condition. under the stated
observer and conditions.
ChromaticityA colour description with overall magnitude removed; CIE xy therefore describes proportions of XYZ but not luminance. removes magnitude by dividing through the sum:
This makes the familiar two-dimensional horseshoe useful for comparing chromaticities, but it deliberately discards the independent luminance dimension.
How the curves become the chromaticity diagram
The next diagram is calculated from the curves above; it is not made by
reshaping them. At 520 nm, for example, the three marked heights form one ratio
X:Y:Z. Dividing each value by X+Y+Z removes intensity and turns that ratio
into one coordinate (x, y). Repeating the calculation for every monochromatic
wavelength traces the curved spectral locus.
A spectrum containing several wavelengths is first integrated into one XYZ triplet and only then normalized. Additive mixtures therefore fall on straight lines between their component chromaticities and fill the interior. The straight line of purples closes the boundary with mixtures; unlike the curved locus, it does not represent a sequence of single wavelengths.
What gives colour coordinates meaning
The triplet (0.8, 0.2, 0.1) still does not identify a colour. We must know
what the channels mean, which primaries and white point anchor them, whether the
numbers are linear or encoded, and what device or interchange conditions apply.
A modelA coordinate scheme such as RGB, HSV, or Lab. It defines what the axes mean but does not necessarily identify a unique colour space. defines the coordinate idea: RGB, CMY, HSV, Lab, or another arrangement. A colour spaceA specified realization of a colour model, anchored by items such as primaries, a reference white, transfer behaviour, and numerical conventions. supplies the anchors and reference conditions. An encodingThe rules that map colour coordinates to stored or transmitted numbers, including transfer functions, range, precision, and channel order. states how coordinates become stored numbers. A profileMetadata or measured transforms that relate a device or encoded colour space to a standard profile connection space. describes a transformation between a device or encoded space and a standard connection space; it is not another colour model.
A standard is wider than any one of those layers: it may normatively bundle a colour space, one or more encodings, transfer characteristics, signal ranges, sampling rules, and viewing or interchange conditions. A profile instead describes how a particular device or encoding connects to a reference system.
- RGB is a colour model.
- sRGB specifies an RGB colour space and its standard encoding.
- An ICC display profile describes how a particular display encoding connects to a profile connection space.
- BT.709 is a wider television standard that combines colour and signal parameters.
Colour models
RGB follows additive primaries and is natural for emitted light. Ideal CMY is its subtractive complement, although real dyes and inks need measured spectral data. HSV and HSL bend an encoded RGB cube into controls convenient for pickers; their apparently geometric hue and saturation are not perceptually uniform.
Video commonly uses a nonlinear luma value written Y′ plus colour-difference
coordinates such as Cb and Cr. The prime matters: these values are derived
from encoded R′G′B′, not directly from linear-light RGB. The coefficients,
range, and sample coding belong to a specified standard, so “YCbCr” alone is not
a complete data contract.
Do not collapse every luma/chroma representation into the word “YUV”. Y′UV
is an analogue colour-difference scaling associated with PAL, while NTSC used
Y′IQ and SECAM carried alternating, frequency-modulated colour-difference
signals. Digital Y′CbCr is related to these systems, but has its own scaling,
offsets, matrix coefficients, range, and sampling rules.
The similar symbols describe different quantities: CIE Y is a linear,
luminance-related tristimulus value; video Y′ is nonlinear luma computed from
encoded components; CIELAB L* is relative perceptual lightness. They are not
interchangeable shader channels.
CIELAB rearranges XYZ relative to a reference white. Oklab rearranges linear-light RGB through an LMS-like intermediate. Both make some numerical differences more useful than raw RGB or XYZ, but neither is a complete model of colour appearance.
Linear light, transfer functions, and gamma
A transfer function makes signal values convenient for capture, storage,
transmission, or display. It does not leave them proportional to optical power.
For example, an sRGB code value of 0.5 represents only about 0.214 relative
linear light. Calling every such mapping “gamma” hides the fact that many
standards use piecewise curves or HDR functions rather than one power law.
Operations that model light—exposure, additive mixing, convolution, and most physically motivated blur—normally need a common linear RGBRGB coordinates proportional to light, suitable for operations such as light addition, exposure, and physically motivated filtering. domain. Decode the source transfer function first, perform the operation, then encode for the destination. A stylistic operation may intentionally work in encoded or perceptual coordinates, but that is a declared visual choice rather than a light calculation.
- Stored
- 0.500
- Meaning
- encoded signal
- Light
- ≈ 0.214
- Meaning
- light-proportional
Gamut as a three-dimensional volume
A triangle on an xy chromaticity diagram shows the chromaticities of three
primaries, not every reproducible colour value. Intensity remains independent,
and nonlinear coordinate systems reshape the body again. That is why a gamutThe complete set of colours a device, colour space, or encoding can represent under its stated limits and conditions. is
best understood as a three-dimensional volume, with 2D slices used only to
inspect a chosen level.
Encoded RGB occupies a cube because each channel has an independent bounded coordinate.
- R′
- encoded red-primary coordinate0…1
- G′
- encoded green-primary coordinate0…1
- B′
- encoded blue-primary coordinate0…1
One colour in several coordinate systems
Take encoded sRGB (0.800, 0.200, 0.100). Converting it without changing the
intended colour gives approximately:
- Decode sRGB: linear RGB
(0.604, 0.033, 0.010). - Apply the sRGB-to-XYZ matrix: XYZ D65
(0.263, 0.153, 0.025). - Normalize XYZ: xyY
(0.596, 0.347, 0.153).
Applying the BT.709 matrix coefficients directly to the same encoded triplet
gives Y′CbCr-like coordinates (0.320, −0.119, 0.305). These are normalized
matrix coordinates; coded range, quantization, and chroma sampling are separate.
The values are rounded.
The workbench below makes those coordinate changes explicit and generates GLSL from the same numerical route. Try sRGB to CIE XYZ first; then choose Y′CbCr and change its matrix coefficients to see why a model name alone is not a complete signal contract.
- decode sRGB transfer
- linear sRGB → Oklab
// WHAT: Convert one colour triplet from srgb to oklab.// HOW: Normalize through linear sRGB; adapt the white point when CIELAB needs D50.// WHY: Transfer functions and white points must not be hidden inside a "magic" matrix.float srgbToLinear1(float c) { return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);}vec3 srgbToLinear(vec3 c) { return vec3(srgbToLinear1(c.r), srgbToLinear1(c.g), srgbToLinear1(c.b));}vec3 linearSrgbToOklab(vec3 rgb) { const mat3 LINEAR_SRGB_TO_LMS = mat3( vec3(0.41222147, 0.21190350, 0.08830246), vec3(0.53633254, 0.68069955, 0.28171884), vec3(0.05144599, 0.10739696, 0.62997870) ); vec3 lms = LINEAR_SRGB_TO_LMS * rgb; lms = sign(lms) * pow(abs(lms), vec3(1.0 / 3.0)); const mat3 LMS_ROOT_TO_OKLAB = mat3( vec3( 0.21045426, 1.97799850, 0.02590404), vec3( 0.79361779, -2.42859221, 0.78277177), vec3(-0.00407205, 0.45059371, -0.80867577) ); return LMS_ROOT_TO_OKLAB * lms;}vec3 convertColour(vec3 value) { vec3 linearRgb = srgbToLinear(value); return linearSrgbToOklab(linearRgb);}Colour conversion
For an RGB-to-RGB conversion, the usual colourimetric route is: decode the source transfer functionA defined nonlinear mapping between light-proportional values and encoded signal values. It is not automatically a simple power-law gamma., transform linear RGB to XYZ, adapt the white point if the source and destination reference whitesThe stimulus treated as neutral white for a colour space or viewing condition; conversions may need adaptation when reference whites differ. differ, transform to destination linear RGB, then encode the destination transfer function. GamutThe complete set of colours a device, colour space, or encoding can represent under its stated limits and conditions. mapping is a separate policy decision.
Video standards
Names such as BT.709, BT.2020, and BT.2100 can specify different combinations of primaries and reference white, transfer characteristics, and signal representation. An RGB conversion needs the primaries, white, and transfer function. A Y′CbCr stream additionally needs matrix coefficientsThe declared coefficients used to derive luma and colour-difference components from encoded RGB. They are separate from the RGB primary chromaticities., numerical range, bit depth, chroma subsamplingStoring colour-difference samples at a lower spatial resolution than luma, as in 4:2:2 or 4:2:0., and chroma sitingThe spatial alignment of chroma samples relative to luma samples; different siting rules require different reconstruction positions.. These fields must not be inferred from resolution or from the word “video”.
The source-side OETFOpto-electronic transfer function: maps scene-light values captured by a camera into a nonlinear electrical or numerical signal. maps scene light to a signal; an EOTFElectro-optical transfer function: maps an encoded display signal into emitted display light. maps a signal to display light. Some systems also specify an OOTFOpto-optical transfer function: the overall relationship between scene light and displayed light, including the intended system rendering. between scene and display intent. The converter below isolates RGB transfer and primary conversion. It does not perform Y′CbCr resampling, range conversion, chromatic adaptation between different whites, HDR tone mapping, or a viewing-dependent OOTF.
- Primaries
- BT.709
- White
- D65
- Transfer
- Context
- HDTV primaries with the BT.709 signal OETF family
- Primaries
- BT.2020
- White
- D65
- Transfer
- Context
- Wide-gamut UHD primaries with SDR transfer characteristics
- Decode BT.709
- Source linear RGB → XYZ
- XYZ → destination linear RGB
- Encode BT.709
// WHAT: Convert encoded RGB from BT.709 SDR to BT.2020 SDR.// HOW: Decode the source transfer, change linear-light primaries through XYZ, encode the destination transfer.// WHY: A colour-standard conversion is not one matrix applied to encoded RGB.// TRANSFER: BT.709 → BT.709.vec3 decodeBt709(vec3 v) { bvec3 low = lessThan(v, vec3(0.081)); return mix(pow((v + 0.099) / 1.099, vec3(1.0 / 0.45)), v / 4.5, vec3(low));}vec3 encodeBt709(vec3 l) { bvec3 low = lessThan(l, vec3(0.018)); return mix(1.099 * pow(max(l, 0.0), vec3(0.45)) - 0.099, 4.5 * l, vec3(low));}// GLSL mat3 constructors list columns. This matrix already combines// destinationXYZToRgb * sourceRgbToXYZ; both standards use D65 here.const mat3 SOURCE_LINEAR_RGB_TO_DESTINATION = mat3( vec3(0.62740837, 0.06909619, 0.01639386), vec3(0.32928530, 0.91952595, 0.08802642), vec3(0.04331342, 0.01136209, 0.89572845));vec3 convertVideoStandard(vec3 encodedSource) { vec3 sourceLinear = decodeBt709(encodedSource); vec3 destinationLinear = SOURCE_LINEAR_RGB_TO_DESTINATION * sourceLinear; return encodeBt709(destinationLinear);}Choosing coordinates for an operation
- Use linear RGBRGB coordinates proportional to light, suitable for operations such as light addition, exposure, and physically motivated filtering. for light addition, exposure, blur, filtering, and most physically motivated rendering arithmetic.
- Use encoded RGBRGB values after a specified transfer function has been applied for storage, interchange, or display signalling. at interfaces that explicitly require that encoding, not as the default domain for light transport.
- Use CIE XYZ as a colorimetric connection space and xyY when a chromaticity plus an explicit luminance coordinate is the useful view; neither is a perceptually uniform editing space.
- Use Y′UV when reconstructing or emulating the analogue PAL/BT.470-style colour-difference path, with its stated U/V scaling.
- Use Y′CbCr when implementing a named video coding or transport standard; preserve its matrix, range, and chroma-sampling assumptions.
- Use HSV or HSL for familiar UI controls, not for perceptual distance or physically meaningful interpolation.
- Use Lab or Oklab when their approximate perceptual geometry helps the operation, while retaining the reference-white and gamut assumptions.
Common shader mistakes
- Treating an RGB triplet as self-describing.
- Calling every transfer curve “gamma 2.2”.
- Confusing luminance
Y, nonlinear lumaY′, and perceptual lightnessL*. - Applying an RGB matrix before decoding the transfer function.
- Clamping intermediate values before conversion and hiding out-of-gamut data.
- Assuming HSL or HSV interpolation follows perceived hue, lightness, or saturation uniformly.
Checklist for colour-dependent effects
Later effect chapters may simplify a physical device, but they should keep the colour contract visible. Before translating a mechanism into shader code, ask:
- Are the input values scene-referredValues interpreted relative to light in the photographed scene, before a final display rendering is chosen., display-referredValues interpreted relative to the intended displayed result and its viewing conditions., or merely an encoded signal?
- Which primaries, reference white, transfer function, range, and matrix coefficients apply?
- Does the operation model light, a transport signal, a decoder failure, perception, or an artistic approximation?
- Can intermediate values leave the destination gamut, and if so, where is the explicit clipping or gamut mappingA declared policy for bringing colours outside a destination gamut into colours that destination can reproduce; it is separate from coordinate conversion. policy?
These questions place later colour-dependent effects in the correct working domain and make any approximation explicit.
Standards and primary references
- CIE 015:2018, Colorimetry, 4th Edition
- CIE 1931 2° colour-matching functions — official dataset
- CIE e-ILV — definition and derivation of the CIE 1931 standard colorimetric system
- J. Guild, The colorimetric properties of the spectrum — original matching measurements
- ISO/CIE 11664-3:2019 — CIE tristimulus values
- CIE 018:2019, The Basis of Physical Photometry
- IEC 61966-2-1 — sRGB
- ITU-R BT.709-6 — HDTV signal parameters
- ITU-R BT.601-7 — digital component video coding
- ITU-R BT.2020-2 — UHDTV system parameters
- ITU-R BT.2100-3 — HDR television with PQ and HLG
- ITU-R BT.1700 — conventional analogue composite television signals
- ICC profile specifications
- W3C CSS Color 4 — reference conversion algorithms