Principle · How it works

Colour models and spaces

A colour model defines coordinates; a colour space makes them specific through reference conditions and, where applicable, primaries, white and transfer behaviour.

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.

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.

A schematic bipartite colour-matching experimentAn observer compares a monochromatic test light in one half of a field with an adjustable mixture of three primary lights in the other half.MONOCHROMATIC TEST LIGHT · λTHREE ADJUSTABLE PRIMARY LIGHTSTESTMATCHOBSERVER ADJUSTS THE MIXTUREUNTIL BOTH HALVES MATCH
The diagram summarizes the matching procedure rather than one particular historical apparatus.

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.

Standard-observer dataCIE 1931 2° colour-matching functions
CIE 1931 x-bar, y-bar, and z-bar colour-matching functionsThe z-bar function peaks in the short wavelengths, y-bar near 555 nanometres, and x-bar in both shorter and longer wavelength regions.example: 520 nm00.51.01.5400500600700nmx̄(λ)ȳ(λ)z̄(λ)
Official CIE data are shown at 5 nm intervals with smooth interpolation between samples. At the marked 520 nm wavelength, the three curve heights give the relative X, Y, and Z responses.

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.

ChromaticityCIE 1931 xy diagram
CIE 1931 xy chromaticity diagram with sRGB and Display P3 gamutsThe curved spectral locus and the straight line of purples enclose physically realizable chromaticities; the sRGB and Display P3 primary triangles occupy smaller regions around D65 white.mixture lies inside46048050052054056058060062070000.20.40.60.8 x00.20.40.60.8 yDisplay P3sRGBD65normalized 520 nmspectral locus · one wavelength per boundary pointline of purples · mixtures, not a single wavelength
Repeating the normalization for every monochromatic wavelength traces the curved spectral locus; its labels are wavelengths in nanometres, not frequencies. Additive mixtures lie on chords between their component chromaticities and therefore fill the interior. Broadband, comparatively balanced mixtures lie near the neutral region. The straight line of purples closes the boundary with mixtures that have no single spectral wavelength. The interior fill is displayed in sRGB and cannot reproduce every plotted chromaticity exactly.

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.

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.

One stored number, two domainsAn encoded midpoint is not half the light
01 · sRGB code value
Stored
0.500
Meaning
encoded signal
02 · Relative linear light
Light
≈ 0.214
Meaning
light-proportional
encoded inputdecodelinear operationencodeencoded output
For sRGB, a stored value of 0.5 decodes to about 0.214 relative linear light. Exposure, additive mixing, convolution, and physically motivated blur normally belong between decode and encode. Perceptual or stylistic operations may use another explicitly declared domain.

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.

Coordinate explorerColour-model geometry
Try first: choose HSL, then compare its 3D volume with a 2D slice.
Drag to rotate. Keyboard: arrow keys; Home resets the view.

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
Points sample the coordinate volume. Out-of-sRGB coordinates are omitted in 3D and hatched in the slice.

One colour in several coordinate systems

Take encoded sRGB (0.800, 0.200, 0.100). Converting it without changing the intended colour gives approximately:

  1. Decode sRGB: linear RGB (0.604, 0.033, 0.010).
  2. Apply the sRGB-to-XYZ matrix: XYZ D65 (0.263, 0.153, 0.025).
  3. 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.

Shader builderCoordinate converterDisplayed colour swatches are clipped to the sRGB gamut.
Try first: sRGB → CIE XYZ exposes decode and matrix stages; Y′CbCr exposes only the selected matrix coefficients.
R′ G′ B′ · IEC sRGB, normalized float
L a b · D65, L normalized to 0…1
Input triplet
Output triplet0.557011 0.163903 0.102415
Inside the sRGB gamut
Conversion route
  1. decode sRGB transfer
  2. linear sRGB → Oklab
Generated GLSL
// 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.

Video-editor conversionRGB standard converterEncoded RGB transfer and primary conversion; no Y′CbCr resampling or range conversion.
Try first: BT.709 SDR → BT.2020 SDR isolates the change of primaries. Then change one transfer to examine it independently.
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
0.645384 0.282833 0.145555
  1. Decode BT.709
  2. Source linear RGB → XYZ
  3. XYZ → destination linear RGB
  4. Encode BT.709
Generated GLSL
// 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

Common shader mistakes

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:

  1. 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?
  2. Which primaries, reference white, transfer function, range, and matrix coefficients apply?
  3. Does the operation model light, a transport signal, a decoder failure, perception, or an artistic approximation?
  4. 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