---
# System prepended metadata

title: Primer on Color
tags: [Color, Rendering]

---

# Primer on Color
```
authors: IQuick 143, nth
```

This is a short but rigorous little handbook on the science of Color, both in general and as applied within Bevy.

# Introduction

To understand color, one must begin with Light. Light is curious because it has both objective physical properties and common subjective qualia (eg. sensory experience). Both, as it turns out, are measurable. The measurement of the physical aspects is called Radiometry, and of the qualia, Photometry. We will cover both in sequence before getting into Colorimetry, the which deals with color directly and lets us mostly ignore light.

If you are not comfortable with calculus or physics, you can just skim the next few sections. Knowing some optics is important for understanding bevy's Physically-Based shading system and working with lights, even if you don't fully follow all the math.

## Radiometry

Lets start with the basics: What is light? For us, light is waves which have energy and can interact with visible objects. These interactions notably include: Absorbtion (light hits the object and deposits its energy), Emission (the object emits waves), among many others (such as reflection, refraction, etc...). Since light is a wave, we can decompose it into a spectrum of pure waves with a given wavelength (the distance after which they repeat). This is useful, since most objects interact with different wavelengths differently, and we will see later that this is what gives rise to color. Each interaction of light and surface (bouncing off, emitting from, transmitting through, or being absorbed by) gives rise to a quantity of energy, in one of the following forms.

### Integral Quantities

As light carries energy and interacts with objects, it is natural to ask how much energy takes part in that interaction. Thus, our starting quantity is *Radiant energy* ($Q$), the amount light absorbed or emitted by an object over some period of time. Like all other forms of base energy, it is expressed in Joules. Since we will often be working without a clear timeframe, a much more practical quantity is *radiant power* ($\Phi$): the amount radiant energy received or emitted by an object at a particular instant

$$
\Phi = \frac{\mathrm{d}Q}{\mathrm{d}t}.
$$

Power is expressed in units of Watts, and can be integrated (over a period of time) to recover energy

$$
Q = \int_{t_0}^{t_1} \Phi(t) \mathrm{d}t.
$$

Radiant power at a particular point on the surface is called either the *irradiance* ($E$) or *radiant exitance* ($M$), depending on whether the light is being received or emitted. Both have units of Watts per Square Meter and can be integrated (over the surface) to recover a radiant power.

*Radiant intensity* ($I$) describes the directional distribution of radiant power. It has units of Watts per Steradian and can also be integrated (over the sphere) recover a radiant power, but is only well defined for negligibly small objects such as point lights and pinhole cameras. 

*Radiance* ($L$) refers either *irradience* or *radient exitance* in a particular direction. It has units of Watts per Square Meter per Steradian, and can be integrated (over all points on a surface and all incoming/outgoing directions) to compute all the other radiometric quantities. I generally think of it as the most useful and flexible description of light.

### Spectral Quantities

As has been mentioned before light is composed out of pure waves with different wavelengths, which interact differently. For this reason it is useful to define spectral equivalents of these quantities. They describe the contribution of energy by each wavelength. A given aggregate quantity can be then computed by integrating the contributions of individual wavelengths over the whole spectrum.

$$
X = \int_{0}^{+\infty} X(\lambda) \mathrm{d}\lambda
$$

where $X$ is some radiometric quantity, $X(\lambda)$ is the corresponding spectral distribution.

:::info 
**Side Note 1**
From this integral we can see that the spectral distribution has an additional factor of $1/m$ in its unit. This is because each individual wavelength makes only an infinitisemal contribution, to get a measurable quantity you need to give a range of wavelengths to consider. One way to interpret the $\mathrm{d}\lambda$ is as representing that "infinitisemally small" area.
:::

Generally light contains many different wavelengths in various quantities.
Some forms of light (like lasers or sodium street lamps) have only very few distinct wavelengths.

Most forms of light contain all sorts of wavelengths in their spectrum, notably blackbody radiation (light emited all sorts of bodies due to their temperature) and the closely related and better known *sunlight*.

:::info
**Side Note 2**
You might be wondering how we can have light have a specific wavelength, if each wavelength has only an infinitisemal contribution. The truth is that no physical wave is a truly pure wave (because that would mean it repeats infinitely, which is physically impossible.) What we are really looking at are spectra which have a single sharp (but not infinitely sharp) peak as opposed to being flat and spread-out.
:::

## Photometry

So, we've estabilished light as waves and that it can be described at any given point by distributions depending on wavelength. These distributions have practically infinitely many different shapes and parameters, something practically intractable to use for colour. However, we are on the right path, we understood what light is, now we just need to understand what happens in human eyes, which will turn out to greatly simplify certain aspects.

The first thing to note about vision is that Light with the same over-all radiant power can register as vastly different depending on the spectrum, the observer, and the ambient conditions. This exemplifies the need to consider the spectral distribution instead of the over-all power. To simplify things somewhat, we will suppose lighting conditions are controlled and that we have some standard observer with "normal eyesight". With this simplification in hand, the first task becomes establishing a clear relationship between the spectral distribution and perceived "intensity" of light.

It turns out that we can objectively measure how sensitive a person's eyes are to different wavelengths of light, and the results are luckily highly consistent between observers. The standard for these measurements is the CIE **photopic luminous efficiency curve** ($V(\lambda)$), established by the *Commission Internationale de l'éclairage* (the international commission on illumination) in 1924. It was modified in 1988, but mostly people still use the original.

Given a beam of pure light with a single wavelength $\lambda$ and a certain radiant power $\Phi(\lambda)$, $V(\lambda)$ indicates the *luminous power* ($Y(\lambda)$) of the light:

$$
  Y(\lambda) = V(\lambda) \cdot \Phi(\lambda).
$$

Given light with a spectral power distribution $\Phi(\lambda)$, the intensity becomes a weighted integral as we sum up the contribution $Y(\lambda)$ of each wavelength:

$$
  Y = \int_\lambda Y(\lambda) \mathrm{d}\lambda = \int_\lambda V(\lambda) \Phi(\lambda) \mathrm{d}\lambda.
$$

Luminous power is the "perceptual twin" of radiant power, representing the subjective "brightness" of light. It is expressed in Lumens, which we will take as a base unit for now. This implies that $V(\lambda)$ must be an expression of Lumens per Watt (lm/W).

The $V(\lambda)$ curve peaks at $683.002 \mathrm{lm/W}$ at around $555 \mathrm{nm}$, and tails off smoothly in either direction, reaching $0.0 \mathrm{lm/W}$ around $380 \mathrm{nm}$ and $780 \mathrm{nm}$ (the ends of the visible spectrum) in a shape loosely reminiscent of a Gaussian. 

Fun fact: the maximum value $683.002 \mathrm{lm/W}$ was picked to match an outdated physical standard involving wax candles. Sometimes you will also see luminous efficiency expressed as a percentage, or as a unitless quantity between $0$ and $1$. This can be achieved by simply dividing by $683.002 \mathrm{lm/W}$. We won't use this form here, but it's good to be able to recognize it.

## Colorimetry

We have covered how to model the perception of brightness, but humans can tell apart different beams of light based on more than just brightness. This leads us to the following question:

When will two different lights with two different spectral power distributions look the same?

This is a hard question to answer; the limited nature of the human eye's three vision cells means there's an infinite number of spectral power distributions which look exactly the same.

In 1931, the CIE proposed a general solution: assign each spectral power distribution coordinates in $R^m$ such that two distributions with coordinates $v_1$ and $v_2$ look the same if and only if $v_1 = v_2$. In other words, define a *color space*.

A color space is fully defined by the transform $m$ from spectral power distribution to coordinates in $\mathbb{R}^n$. In practice, we do not define this transform directly. Instead, we take inspiration from the luminous efficiency curve and define $n$ *color matching functions* $m_i : \lambda \to \mathbb{R}^+$ such that the coordinates are the weighted integral of each
$$
  \sum_{i=1}^n \hat{i} 
  \int_{\lambda} m_i(\lambda) \Phi(\lambda) \mathrm{d}\lambda.
$$

The tristimulous theory of visual perception suggests that, because the human eye has three different types of light-sensitive cells, all visual colors can be represented in $\mathbb{R}^3$ with three different matching functions. We will assume all color spaces are in $\mathbb{R}^n$. 

### The CIE Color Spaces

The first color space rigorously defined in this manner was the CIE RGB space. The color-matching functions were derived experimentally by a complex visual test involving varying the the brightness of monochromatic lights at the 435.8 nm (blue), 546.1 nm (green) and 700 nm (red) wavelengths. This data was used to derive three matching functions $\bar{r}(\lambda)$, $\bar{g}(\lambda)$, and  $\bar{b}(\lambda)$, with integrated coordinates $R$, $G$, and $B$. 

Given a spectral power distribution, the matching functions tell you roughly how much of each of the three pure wavelengths is needed to produce the same color. This then tells you, roughly, what that light is going to look like. For instance, we know that anything that matches $[1,0,0]$ is going to look like pure blue 435.8 nm light. We can then flip this around to say that $[1,0,0]$ represents the color produced by that wavelength. Under this shift, the pure wavelengths corresponding to the unit-vectors become the "primaries" of the space.

So now, suddenly, we have a 3D coordinate system capable of representing any color visible to the human eye. Hooray! Unfortunately we still have more to do, because CIE RGB has two big flaws. The first is that $\hat{r}$ is negative in the 330 nm to 550 nm range, which means RGB coordinates can be negative as well. This leads to the awkward question "how do I add a negative amount of red to my color?" The second issue is that the **photometric intensity** of a color in CIE RGB space cannot be easily determined (to put it another way, the coordinates of a color don't tell you how bright it will look).

The CIE addressed these flaws by developing a new color space called CIE XYZ. This time, instead of basing the matching functions $\bar{x}(\lambda)$, $\bar{y}(\lambda)$, $\bar{z}(\lambda)$ on an experiment, the CIE derived them from the existing RGB space. To do so, they selected a transformation of the RGB space which produced non-negative coordinates for all visible colors, and caused $\bar{y}$ to approximate $V(\lambda)$ (the efficiency curve we talked about back in the Photometry section).

The CIE XYZ space is extremely important, but tends to confuse people. The issue is that, unlike RGB, the primaries are not real colors. They are imaginary. No visible color corresponds to $(1, 0, 0)$, no mix of different light wavelengths can produce it. It just doesn't exist. This is essentially a consequence of how we set up the space and an additional physical constraint: No three light sources, when combined, are able to produce all colors in the visible spectrum. But that's what we are pretending to do in the XYZ space, by setting up the coordinates to be non-negative. The price is that the primaries must exist outside the visual color gamut.

It's alright if this business with imaginary colors and XYZ doesn't make sense, we'll be returning to it again shortly.

### Chromaticity

Though an XYZ still doesn't directly relate to any actual physical color primaries, it does describe lots of other useful information: like *luminance* and *chromaticity*. I'm just going to quote this fantastic explanation from Color Imaging: Fundamentals and Applications, because I don't think I can explain it better. Remember, Y is a measure of luminance because we chose $\bar{y}(\lambda)$ to match the luminous efficiency curve $V(\lambda)$.

> In XYZ space, Y is a measure of luminance. By performing a projection from three to two dimensions, we can generate a space that approximates chromatic information: information that is independent of luminance. This two-dimensional projection is obtained by performing a type of perspective transformation that normalizes the tristimulus values and removes luminance information. 

$$
\begin{aligned} 
x &= \frac{X}{X+Y+Z} \\
y &= \frac{Y}{X+Y+Z} \\
z &= \frac{Z}{X+Y+Z} \\
x + y + z &= 1.
\end{aligned}
$$

> It should be obvious that the projection of three-dimensions of information down to two always results in the loss of information. For chromaticity coordinates, the ratio normalization essentially throws away the luminance information. It should also be obvious that because the chromaticity coordinates always sum to 1, if we know two of them we can easily determine the third. On their own, chromaticity coordinates do not possess enough information to adequately describe a color measurement or a color match. Traditionally, we can use two coordinates (usually x and y) along with one of the tristimulus values to fully describe a color. Since the Y tristimulus value describes luminance, you will often see colors described with their x, y, and Y values. We can calculate tristimulus values back from chromaticities using

$$
\begin{aligned} 
X &= \frac{x}{y} Y \\
Z &= \frac{z}{y} Y
\end{aligned}
$$

Following this line of reasoning, we stumble upon a new space, often called CIE xyY for reasons that show now be obvious. If you've ever seen a picture like the following, you should now be able to recognize that the x and y axis are the x and y from xyY.

![image](https://hackmd.io/_uploads/B12OvVS3A.png)

This, by the way, is called the Chromaticity Diagram. It is an approximation of how colors might appear if you plotted them holding Y constant. It is only an approximation, since your monitor cannot reproduce the vast majority of colors in question.

It's good to keep this diagram in mind as you continue on, we will refer back to it often.

### Color Temperature

You may be wondering what that anomalous black curve is doing in the middle of the Chromaticity Diagram. That is called the Planckian locus (a fun term to impress your friends with) and it represents the chromaticity of an incandescent black body (eg. something incredibly hot) at different temperatures. The markings along the curve are temperatures in Kelvin (K). The meaningful range is usually 1,000 K to 12,500 K.

This curve is often included on the Chromaticity Diagram because it is the standard way of measuring the "color temperature" of light-sources. Somewhat confusingly, low temperatures (note: low roughly means "colder than the sun's surface" here) correspond to "warm" orange/red lights and high temperatures correspond to "cool" blueish lights. Candle-light sits around 1,900 K, the sun is around 5,800K, and a clear sky is about 10,000 K.

This will come up again when we get into standard illuminants and white-points.

### Beginnings of Color Management

That concludes our little tour of Light and Color. We have established the basic tools for talking about color independent of a specific input (eg. camera) or output (eg. screen) device. Next we will discuss how to represent and reproduce colors accurately using Bevy.

# Color Spaces

We've already had some contract with color spaces. While color as a phenomenon exists without reference to any space, *color data* must be specified in terms of a specific color space. This section will be a whistle-stop tour of all the different important color spaces, covering why they exist and when to use one over the other.

## Color Space Properties

As we briefly touched on, the CIE XYZ color primaries are imaginary and exist outside the visible spectrum. This means there are a large number of possible XYZ values that do not correspond to any physical color. Also, no display hardware can accurately reproduce all XYZ color values. For these and many other reasons, the use of a different space is often appropriate. The main four considerations when selecting an alternate space are:
+ Physical Realizability
+ Efficient Encoding
+ Perceptual Uniformity
+ Intuitive Specification

## Display-Referred Spaces

All modern displays consist of an array of tiny individual red, green and blue elements. The exact chromaticities of red, green and blue these elements produce are called the device-primaries. Because of this structure, modern displays are only capable of producing the subset of the visual spectrum in the triangle "between" the three device primaries on the Chromaticity Diagram.

This triangular region, usually specified in chromaticity space, is the device's *color gamut*. I am always going to refer to gamut as a property of a display, rather than a space, but the two are intimately connected; every display also defines a color-space, where the color-space primaries coincide with the display primaries. Such color-spaces are called "display-referred", because they are defined in reference to a display standard.

As you will see when we cover the sRGB color space, display-referred spaces are extremely common. When most people think of representing a "color" on a computer, they are usually implicitly imagining working in a display-referred space. This is only natural, since the display-referred space of your computer monitor is closest to  

In contrast, you can think of the CIE XYZ space as a *display-independent* methods of representing colors. Any given display standard can be described by it's relationship to XYZ. To specify this relationship, four things must be known about the device: the chroma of the three primaries and the white-point of the device. Here again I will quote directly from Color Imaging.

> The xy chromaticity coordinates of the primaries represent the colors obtained for the color vectors $(1,0,0)$, $(0,1,1)$ and $(0,0,1)$. Basically, they represent the chromaticity of the maximum value of any given channel when displayed alone. [...] Without the luminance component, it is impossible to know the relative power or energy of the three primaries, ans so we cannot know what color will be shown when all three primaries are displayed at their maximum. Thus, we need to include a fourth description of the device; the display white point.

## All About Gamuts

+ Gamuts are bounded by both chroma and luma.

## The Color-Space Zoo

### sRGB & linear-sRGB

- [Wikipedia on sRGB](https://en.wikipedia.org/wiki/SRGB)
- [Wikipedia on Gamma correction](https://en.wikipedia.org/wiki/Gamma_correction)

### HWB, HSV, & HSL

### CIE Yuv & Yu'v'

### CIE L\*a\*b\*, L\*C\*h, & L\*u\*v\*

### Lαβ

### Oklab & Oklch

## Future Topics
+ The Color-Space Zoo.
+ Finite representations and bounds.
+ The use of HSL.
+ Color difference metrics & perceptual uniformity.
+ White-point.
+ Device-Independent vs Device-Referred Colors.
+ Scene-Referred vs Display-Referred Colors.
+ Color Gamut as a property of displays rather than spaces.

# Illuminants

Light sources and white-points.

# Digital Color

Dynamic range, display technology, gamma curves, tone-mapping, rendering & exposure, color management.

## Alpha Blending

## Display Standards

### IEC 61966-2-1 & sRGB-D60-Linear

### IEC Rec. BT.709

### IEC Rec. BT.2020 & BT.2100

### CDI-P3 & Display P3

# Color in Bevy

Our color api, the use of color within rendering, best practices, tips and tricks.

## Future Topics
+ Overview
+ How do I use the `Color` enum?
+ High-dynamic range and wide-color gamut output.
+ Gradients and fancy things.