Computer Graphics · Shading Models
Radiance, Irradiance, and the Units a BRDF Is Written In
How solid angle separates radiance from irradiance, why a BRDF is a ratio of two different radiometric quantities, and what the resulting numbers look like for ordinary surfaces.
Shading code is full of silent unit errors. A surface renders too bright by a factor of three, or a diffuse term looks washed out in the highlights, and the cause is almost always a confusion between two quantities that both measure light arriving at a point. The two are radiance and irradiance, and they differ by a factor with units of solid angle. A bidirectional reflectance distribution function is defined as the ratio between them, which means its own units are inverse steradians. Once that is clear, a whole family of coefficient bugs becomes predictable rather than mysterious.
Solid angle as a measure on the sphere of directions
Solid angle is area on the unit sphere, measured in steradians. A patch of surface dA seen from a point at distance r subtends dω = dA cos θ / r², where θ is the angle between the patch normal and the line of sight. The cos θ is not an extra convention; it is the projection that turns a tilted patch into the area it covers on the sphere. A full sphere is 4π steradians and a hemisphere is 2π, which are the only two solid angle values most shading code ever needs to remember.
The awkward part is that directions are usually parameterized by spherical angles, and the map from (θ, φ) to solid angle is not uniform. In that parameterization dω = sin θ dθ dφ. Near the pole (θ small), a fixed step in θ sweeps a much smaller solid angle than the same step near the horizon. Any code that samples θ and φ uniformly and then treats the samples as uniform over directions is biased, and the bias is worst exactly where most of the interesting reflection happens. The correct uniform measure over the hemisphere is obtained by sampling cos θ uniformly on [0, 1], not θ. That single substitution is the difference between a correct cosine-weighted sample and one that over-weights grazing directions.
A useful sanity figure: the sun subtends about half a degree across, which is a solid angle of roughly 6.8 × 10⁻⁵ steradians. Small sources are genuinely small in solid angle, which is why direct light sampling in a renderer needs a delta or near-delta distribution rather than a uniform one.
Radiance is the quantity transport preserves
Radiance, written L, is power per unit projected area per unit solid angle, in W·m⁻²·sr⁻¹. It answers the question “how much light is flowing along this ray, per unit of cross-section and per unit of direction”. Irradiance, written E, is power per unit area falling on a surface, in W·m⁻², with no directional term.
The distinction matters because radiance is the quantity that is invariant along a ray in a non-participating medium. Move the camera closer to a wall and the wall’s radiance does not change; what changes is how much of the wall projects into how many pixels. This invariance is why a distant streetlight and a nearby one of the same surface brightness look equally bright, and why a renderer can transport radiance along rays and only apply geometry at the endpoints. Irradiance is not invariant in this way, because the same bundle of rays can spread over more or less surface depending on incidence angle.
The relation between them is an integral over the hemisphere Ω:
$$E(x) = \int_{\Omega} L_i(x, \omega_i), (\omega_i \cdot n), d\omega_i$$
The dot product is the cosine of the incidence angle, and it is there because irradiance is defined on the surface, not on the plane perpendicular to the incoming direction. This cosine is the same one that appears when computing solid angle from a tilted patch, and it is the source of most of the “where did the π go” confusion in shading code.
The BRDF is a ratio, and its units are inverse steradians
A bidirectional reflectance distribution function is defined as the outgoing radiance in one direction divided by the incoming irradiance from another:
$$f_r(\omega_i, \omega_o) = \frac{dL_o(\omega_o)}{dE_i(\omega_i)} = \frac{dL_o(\omega_o)}{L_i(\omega_i), (\omega_i \cdot n), d\omega_i}$$
The numerator is a radiance and the denominator is an irradiance, so the ratio carries units of sr⁻¹. It is a distribution in the formal sense: it describes how incident power is spread over outgoing directions, and it only becomes a reflectance after integration.
For a Lambertian surface the integration is easy. If outgoing radiance is uniform and the reflected fraction of incident power is ρ, then L_o = ρ E / π, and therefore f_r = ρ / π. With ρ = 1, the perfectly white diffuse surface, the BRDF value is 1/π ≈ 0.318, not 1. Code that multiplies a base color by a light’s irradiance and forgets this constant produces a surface roughly three times too bright, which is close enough to look plausible and wrong enough to fail any comparison against a reference.
/* Lambertian BRDF: albedo divided by pi, so the cosine-weighted integral is albedo. */
typedef struct { double r, g, b; } rgb;
static rgb lambert_brdf(rgb albedo) {
const double inv_pi = 0.3183098861837907;
return (rgb){ albedo.r * inv_pi, albedo.g * inv_pi, albedo.b * inv_pi };
}
/* Outgoing radiance for incident radiance Li arriving at angle theta_i. */
static rgb lambert_response(rgb albedo, rgb Li, double cos_theta_i) {
rgb f = lambert_brdf(albedo);
double e = cos_theta_i; /* Li * cos, per unit solid angle */
return (rgb){ f.r * Li.r * e, f.g * Li.g * e, f.b * Li.b * e };
}
The same structure holds for every other model in this cluster. A microfacet lobe evaluates to a distribution value with units sr⁻¹, and a Fresnel term multiplies it as a dimensionless factor. The Fresnel reflectance for dielectrics and conductors article is entirely about that dimensionless factor; the microfacet distributions article is about the shape of the sr⁻¹ part.
Directional albedo as the energy budget
Integrating a BRDF against the cosine over the hemisphere gives the directional hemispherical reflectance, sometimes called the directional albedo:
$$\rho(\omega_i) = \int_{\Omega} f_r(\omega_i, \omega_o), (\omega_o \cdot n), d\omega_o$$
For a physically valid model this integral must not exceed one for any incident direction, in every color channel separately. A model that exceeds one is not merely too bright; it creates energy that then bounces around a scene and cannot be corrected by exposure. White furnace tests, in which a surface is placed inside a uniform environment of radiance one, exist precisely to check this integral: a perfectly white non-emissive surface must render at radiance no greater than one, and for the Lambert case exactly one.
Reciprocity is the companion constraint. A BRDF must satisfy f_r(ω_i, ω_o) = f_r(ω_o, ω_i) for the surface to be physically realizable with passive materials. Reciprocity is what lets a renderer trace paths from the camera and still compute lighting that would have arrived from the light, and it is the property that makes importance sampling of either endpoint valid.
Where the conventions diverge in practice
Several conventions coexist and each shifts the constant terms.
Some formulations define the BRDF against irradiance measured on a plane perpendicular to the incoming direction, which removes the cosine from the denominator and moves it into the shading code. Others define it against irradiance on the surface, as above. Both are internally consistent; mixing them is not. Renderers that store precomputed irradiance in a texture, then multiply by a BRDF defined the second way, must apply the cosine exactly once.
A second divergence is whether the cosine is folded into the sampling density. With a cosine-weighted hemisphere the probability density for direction ω is cos θ / π, and a Monte Carlo estimator of the reflected radiance divides by that density. The cosine in the numerator of the integral and the cosine in the density cancel, which is why cosine-weighted sampling is preferred for diffuse surfaces: the estimator becomes an average of BRDF values alone. Sampling the same integral with a uniform density leaves a cos θ factor in the estimator and raises variance at grazing angles.
A third is color space. Radiometric quantities are linear in power, and any sRGB-encoded texture used as an albedo must be decoded before it is treated as ρ. Applying gamma-encoded values directly to a BRDF produces a mid-gray that is far too dark and a highlight roll-off that looks wrong next to a reference. The rendering equation does not care about encoding, but every implementation of it does.
The practical rule that resolves most of this: keep radiance and irradiance in distinct types or distinct variable names, and never multiply a BRDF by anything except an irradiance. When a shader needs an outgoing radiance, the last operation before writing it should be a multiplication by a cosine or an integral that already contains one.
References
- Geometrical Considerations and Nomenclature for Reflectance — F. E. Nicodemus, J. C. Richmond, J. J. Hsia, I. W. Ginsberg, T. Limperis, NBS Monograph 160, 1977
- Physically Based Rendering: From Theory to Implementation — Matt Pharr, Wenzel Jakob, Greg Humphreys