Skip to content

Commit

Permalink
Add explanation of UsdLux quantities and behaviour
Browse files Browse the repository at this point in the history
Adds explanation of expected behviour to UsdLux docs.
  • Loading branch information
anderslanglands committed Oct 25, 2023
1 parent 53fcb31 commit 6281acb
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 11 deletions.
2 changes: 1 addition & 1 deletion pxr/usd/usdLux/distantLight.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class UsdLuxDistantLight : public UsdLuxNonboundableLightBase
// --------------------------------------------------------------------- //
// ANGLE
// --------------------------------------------------------------------- //
/// Angular size of the light in degrees.
/// Angular diameter of the light in degrees.
/// As an example, the Sun is approximately 0.53 degrees as seen from Earth.
/// Higher values broaden the light and therefore soften shadow edges.
///
Expand Down
78 changes: 73 additions & 5 deletions pxr/usd/usdLux/lightAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,38 @@ class SdfAssetPath;
/// regardless of whether LightAPI is included as a built-in API of the prim
/// type (e.g. RectLight or DistantLight) or is applied directly to a Gprim
/// that should be treated as a light.
///
/// <b>Quantities and Units</b>
///
/// Most renderers consuming OpenUSD today are RGB renderers, rather than spectral.
/// Units in RGB renderers are tricky to define as each of the red, green and blue
/// channels transported by the renderer represents the convolution of a spectral
/// exposure distribution, e.g. CIE Illuminant D65, with a sensor response function, e.g.
/// CIE 1931 x_bar. Thus the main quantity in an RGB renderer is neither radiance nor
/// luminance, but "integrated radiance" or "tristimulus weight".
///
/// The emision of a default light with \c intensity 1 and \c color [1, 1, 1] is an
/// Illuminant D spectral power distribution with chromaticity matching the rendering
/// colour space white point, normalized such that a ray normally incident upon the
/// sensor with EV0 exposure settings will generate a pixel value of [1, 1, 1] in the
/// rendering colour space.
///
/// Given the above definition, that means that the luminance of said default light
/// will be 1 \a nit and its emission spectral radiance distribution is easily
/// computed by appropriate normalization.
///
/// For brevity, the term \a emission will be used in the documentation to mean
/// "emitted spectral radiance" or "emitted integrated radiance/tristimulus weight",
/// as appropriate.
///
/// Note that some colour spaces, most notably ACES, define their white points by
/// chromaticity coordinates that do not exactly line up to any value of a standard illuminant.
/// In these cases, a spectral renderer should choose the closest Illuminant D spectrum
/// for the lights' emission (the \a rendering \a illuminant) and perform chromatic
/// adaptation to transform the rendered image to the rendering colour space.
/// The method of "uplifting" an RGB colour to a spectral distribution is unspecified
/// other than that it should round-trip under the rendering illuminant to the limits
/// of numerical accuracy.
///
/// <b>Linking</b>
///
Expand Down Expand Up @@ -284,7 +316,13 @@ class UsdLuxLightAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
// INTENSITY
// --------------------------------------------------------------------- //
/// Scales the power of the light linearly.
/// Scales the brightness of the light linearly.
///
/// Lights' emission is in units of spectral radiance normalized such that
/// a directly visible light normally incident upon the sensor plane will
/// generate a pixel value of [1, 1, 1] in an RGB renderer, and thus have a
/// luminance of 1 nit. A light with `intensity` 2 would therefore have a
/// luminance of 2 nits.
///
/// | ||
/// | -- | -- |
Expand All @@ -306,10 +344,16 @@ class UsdLuxLightAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
// EXPOSURE
// --------------------------------------------------------------------- //
/// Scales the power of the light exponentially as a power
/// Scales the brightness of the light exponentially as a power
/// of 2 (similar to an F-stop control over exposure). The result
/// is multiplied against the intensity.
///
/// Lights' emission is in units of spectral radiance normalized such that
/// a directly visible light normally incident upon the sensor plane will
/// generate a pixel value of [1, 1, 1] in an RGB renderer, and thus have a
/// luminance of 1 nit. A light with `intensity` 1 and `exposure` 2 would
/// therefore have a luminance of 4 nits.
///
/// | ||
/// | -- | -- |
/// | Declaration | `float inputs:exposure = 0` |
Expand Down Expand Up @@ -376,10 +420,22 @@ class UsdLuxLightAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
// NORMALIZE
// --------------------------------------------------------------------- //
/// Normalizes power by the surface area of the light.
/// Normalizes brightness by the surface area of the light.
/// This makes it easier to independently adjust the power and shape
/// of the light, by causing the power to not vary with the area or
/// of the light, by causing the brightness to not vary with the area or
/// angular size of the light.
///
/// For an area light, this is calculated by dividing the emission
/// by the surface area (in world space) of the shape of the light, including
/// any scaling applied to the light by its transform stack.
///
/// For a distant light, this is calculated by dividing the proportion of the
/// visible hemisphere subtended by the light, that is by `sin(theta)*sin(theta)*M_PI`,
/// where `theta` is half the value of the distant light's `angle` attribute.
/// If `angle` is zero, this attribute has no effect.
///
/// For a dome light, this attribute is ignored.
///
///
/// | ||
/// | -- | -- |
Expand All @@ -401,7 +457,12 @@ class UsdLuxLightAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
// COLOR
// --------------------------------------------------------------------- //
/// The color of emitted light, in energy-linear terms.
/// The color of emitted light, in the rendering color space.
///
/// This color is just multiplied with the emission. In the case of a spectral
/// renderer, this color should be uplifted such that it round-trips to within
/// the limit of numerical accuracy under the rendering illuminant.
///
///
/// | ||
/// | -- | -- |
Expand Down Expand Up @@ -453,6 +514,13 @@ class UsdLuxLightAPI : public UsdAPISchemaBase
/// computed result multiplies against the color attribute.
/// See UsdLuxBlackbodyTemperatureAsRgb().
///
/// This is always calculated as an RGB color using a D65 white points, regardless
/// of the rendering color space, normalized such that the default value of
/// 6500 will always result in white, and then should be transformed to the
/// rendering color space.
/// Spectral renderers should do the same and then uplift the resulting
/// color after multiplying with the `color` attribute.
///
/// | ||
/// | -- | -- |
/// | Declaration | `float inputs:colorTemperature = 6500` |
Expand Down
36 changes: 36 additions & 0 deletions pxr/usd/usdLux/overview.dox
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,34 @@ constraints, such as to attach lights to moving geometry. This is
consistent with USD's policy of storing the computed result of rigging,
not the rigging itself.

\subsection usdLux_quantities Quantities and Units

Most renderers consuming OpenUSD today are RGB renderers, rather than spectral.
Units in RGB renderers are tricky to define as each of the red, green and blue
channels transported by the renderer represents the convolution of a spectral
exposure distribution, e.g. CIE Illuminant D65, with a sensor response function, e.g.
CIE 1931 x_bar. Thus the main quantity in an RGB renderer is neither radiance nor
luminance, but "integrated radiance" or "tristimulus weight".

The emision of a default light with \c intensity 1 and \c color [1, 1, 1] is an
Illuminant D spectral power distribution with chromaticity matching the rendering
colour space white point, normalized such that a ray normally incident upon the
sensor with EV0 exposure settings will generate a pixel value of [1, 1, 1] in the
rendering colour space.

Given the above definition, that means that the luminance of said default light
will be 1 \a nit and its emission spectral radiance distribution is easily computed by appropriate
normalization.

Note that some colour spaces, most notably ACES, define their white points by
chromaticity coordinates that do not exactly line up to any value of a standard illuminant.
In these cases, a spectral renderer should choose the closest Illuminant D spectrum
for the lights' emission (the \a rendering \a illuminant) and perform chromatic
adaptation to transform the rendered image to the rendering colour space.
The method of "uplifting" an RGB colour to a spectral distribution is unspecified
other than that it should round-trip under the rendering illuminant to the limits
of numerical accuracy.

\subsection usdLux_Behavior Properties & Behavior

Colors specified in attributes are in energy-linear terms,
Expand All @@ -115,6 +143,14 @@ that do not measure the visible solid angle are expected to provide an
approximation, such as inverse-square falloff. Further artistic control
over attenuation can be modelled as light filters.

The behavior of all attributes is in UsdLuxLightAPI is documented on their \c Get()
methods. All attributes are expected to be supported by all light types, with
the effect of each attribute applying multiplicatively in sequence.

The example hdEmbree delegate provides a reference implementation, as well as a
series of unit tests and reference images for renderers to check their own
implementation against.

More complex behaviors are provided via a set of API classes.
These behaviors are common and well-defined but may not be supported
in all rendering environments. These API classes provide
Expand Down
43 changes: 38 additions & 5 deletions pxr/usd/usdLux/shapingAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,14 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
/// A control to shape the spread of light. Higher focus
/// values pull light towards the center and narrow the spread.
/// Implemented as an off-axis cosine power exponent.
/// TODO: clarify semantics
///
/// This is implemented as a multiplication with the dot product between the
/// light's surface normal and the emission direction, raised to the power `focus`,
/// i.e.
/// ```
/// Le = GfCompMult(Le, powf(emissionDirection * lightNormal, focus))
/// ```
///
///
/// | ||
/// | -- | -- |
Expand All @@ -196,7 +202,17 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
/// Off-axis color tint. This tints the emission in the
/// falloff region. The default tint is black.
/// TODO: clarify semantics
///
/// This is implemented as a linear interpolation between `focusTint` and
/// white, by the factor computed from the focus attribute, in other words:
///
/// ```
/// if (focus > 0.0f) {
/// const float focusFactor = powf(emissionDirection * lightNormal, focus);
/// const GfVec3f focusTintFactor = lerp(focusTint, GfVec3f(1), focusFactor);
/// Le = GfCompMult(Le, focusTintFactor);
/// }
/// ```
///
/// | ||
/// | -- | -- |
Expand All @@ -221,6 +237,12 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
/// Angular limit off the primary axis to restrict the
/// light spread.
///
/// ```
/// const float cosThetaC = cosf(light.shaping.coneAngle * M_PI / 180.0f);
/// const float cosThetaS = Lerp(cosThetaC, 1.0f, light.shaping.coneSoftness);
/// Le *= Smoothstep(cosThetaC, cosThetaS, cosThetaOZ);
/// ```
///
/// | ||
/// | -- | -- |
/// | Declaration | `float inputs:shaping:cone:angle = 90` |
Expand All @@ -242,7 +264,13 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
// SHAPING:CONE:SOFTNESS
// --------------------------------------------------------------------- //
/// Controls the cutoff softness for cone angle.
/// TODO: clarify semantics
///
/// ```
/// const float cosThetaC = cosf(light.shaping.coneAngle * M_PI / 180.0f);
/// const float cosThetaS = Lerp(cosThetaC, 1.0f, light.shaping.coneSoftness);
/// Le *= Smoothstep(cosThetaC, cosThetaS, cosThetaOZ);
/// ```
///
///
/// | ||
/// | -- | -- |
Expand All @@ -267,6 +295,8 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
/// An IES (Illumination Engineering Society) light
/// profile describing the angular distribution of light.
///
/// See hdEmbree example plugin for reference implementation
///
/// | ||
/// | -- | -- |
/// | Declaration | `asset inputs:shaping:ies:file` |
Expand All @@ -288,7 +318,8 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
// SHAPING:IES:ANGLESCALE
// --------------------------------------------------------------------- //
/// Rescales the angular distribution of the IES profile.
/// TODO: clarify semantics
///
/// See hdEmbree example plugin for reference implementation
///
/// | ||
/// | -- | -- |
Expand All @@ -312,6 +343,8 @@ class UsdLuxShapingAPI : public UsdAPISchemaBase
// --------------------------------------------------------------------- //
/// Normalizes the IES profile so that it affects the shaping
/// of the light while preserving the overall energy output.
///
/// See hdEmbree example plugin for reference implementation
///
/// | ||
/// | -- | -- |
Expand Down

0 comments on commit 6281acb

Please sign in to comment.