Magnum::Trade::LightData class

Light data.

Usage

The class exposes light parameters in a way that makes sense as a whole, allowing to reduce branching in application code — e.g., a light defined by just its range has the quadratic attenuation factor set to one, with constant and linear attenuation being zero, or spot cone angles are the full circle everything except spotlights.

Populating an instance

You can choose a constructor overload that matches the subset of input parameters and let the class set the rest implicitly. For example, a Type::Point light constructed using a range will have attenuation() implicitly set to {1.0f, 0.0f, 1.0f} and cone angles to 360.0_degf:

Trade::LightData data{Trade::LightData::Type::Point,
    0xfff3d6_srgbf, 1.0f,
    15.0f};

Or, a Type::Spot light constructed from a constant / linear / quadratic attenuation will have range() implicitly set to Constants::inf():

Trade::LightData data{Trade::LightData::Type::Spot,
    0xf3d6ff_srgbf, 10.0f,
    {0.01f, 0.5f, 2.0f},
    25.0_degf, 55.0_degf};

And a Type::Directional light that doesn't attenuate can be constructed without either, causing attenuation() to be {1.0f, 0.0f, 0.0f} and range() Constants::inf(), cancelling out the attenuation equation:

Trade::LightData data{Trade::LightData::Type::Directional,
    0xd6fff3_srgbf, 0.25f};

Attenuation calculation

To support all common lighting calculations, the class exposes parameters in a combined equation containing both constant / linear / quadratic attenuation $ \color{m-success} K_c $ / $ \color{m-success} K_l $ / $ \color{m-success} K_q $ and a range parameter $ \color{m-info} R $ over a distance $ d $ :

\[ F_{att} = \frac{\operatorname{clamp}(1 - (\frac{d}{\color{m-info} R})^4, 0, 1)^2}{{\color{m-success} K_c} + {\color{m-success} K_l} d + {\color{m-success} K_q} d^2} \]

In most cases you'll have the light data using either one or the other approach. The classic constant/linear/quadratic equation allows for most control, but because the attenuated intensity never really reaches zero, it makes light culling optimizations hard to perform. In this case the range() is set to Constants::inf():

\[ F_{att} = \lim_{{\color{m-info} R} \to \infty} \frac{{\color{m-dim} \operatorname{clamp}(}1 \mathbin{\color{m-dim}-} {\color{m-dim} (\frac{d}{R})^4, 0, 1)^2}}{{\color{m-success} K_c} + {\color{m-success} K_l} d + {\color{m-success} K_q} d^2} = \frac{1}{{\color{m-success} K_c} + {\color{m-success} K_l} d + {\color{m-success} K_q} d^2} \]

The range-based equation approaches zero when $ {\color{m-info} R} = d $ and provides a good tradeoff for performance while staying mostly physically-based. This is modelled after the glTF KHR_lights_punctual extension, which in turn is based on the UE4 implementation. In this case, attenuation() is set to {1.0f, 0.0f, 1.0f}, the constant factor is present in order to prevent the function from exploding to infinity when $ d \to \infty $ .

\[ F_{att} = \frac{\operatorname{clamp}(1 - (\frac{d}{\color{m-info} R})^4, 0, 1)^2}{{\color{m-success} K_c} + {\color{m-dim} K_l d} \mathbin{\color{m-dim} +} {\color{m-success} K_q} d^2} = \frac{\operatorname{clamp}(1 - (\frac{d}{\color{m-info} R})^4, 0, 1)^2}{1 + d^2} \]

If $ {\color{m-info} R} \to \infty $ as well, the equation reduces down to a simple inverse square:

\[ F_{att} = \lim_{{\color{m-info} R} \to \infty} \frac{{\color{m-dim} \operatorname{clamp}(} 1 \mathbin{\color{m-dim} -} {\color{m-dim} (\frac{d}{R})^4, 0, 1)^2}}{{\color{m-success} K_c} + {\color{m-dim} K_l d} \mathbin{\color{m-dim} +} {\color{m-success} K_q} d^2} = \frac{1}{1 + d^2} \]

As a special case, a Type::Directional light is defined by attenuation() set to {1.0f, 0.0f, 0.0f} and range() to Constants::inf() — thus without any attenuation:

\[ F_{att} = \lim_{{\color{m-info} R} \to \infty} \frac{{\color{m-dim} \operatorname{clamp}(} 1 \mathbin{\color{m-dim} -} {\color{m-dim} (\frac{d}{R})^4, 0, 1)^2}}{{\color{m-success} K_c} \mathbin{\color{m-dim} +} {\color{m-dim} K_l d + K_q d^2}} = 1 \]

Units

To follow physically-based principles in lighting calculation, intensity is assumed to be in in candela (lm/sr) for Type::Point and Type::Spot, and in lux (lm/m2) for Type::Directional. Distance $ d $ is in meters.

Public types

enum class Type: UnsignedByte { Ambient = 1 new in Git master, Directional new in Git master, Infinite = Directional deprecated in Git master, Point, Spot }
Light type.

Constructors, destructors, conversion operators

LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, Float range, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master
Constructor.
LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, Float range, const void* importerState = nullptr) explicit noexcept new in Git master
Construct with implicit cone angles.
LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master
Construct attenuation-based light data.
LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, const void* importerState = nullptr) explicit noexcept new in Git master
Construct attenuation-based light data with implicit cone angles.
LightData(Type type, const Color3& color, Float intensity, Float range, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master
Construct range-based light data.
LightData(Type type, const Color3& color, Float intensity, Float range, const void* importerState = nullptr) explicit noexcept new in Git master
Construct range-based light data with implicit cone angles.
LightData(Type type, const Color3& color, Float intensity, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master
Construct light data with implicit attenuation.
LightData(Type type, const Color3& color, Float intensity, const void* importerState = nullptr) explicit noexcept
Construct light data with implicit attenuation and cone angles.
LightData(const LightData&) deleted
Copying is not allowed.
LightData(LightData&&) defaulted noexcept
Move constructor.

Public functions

auto operator=(const LightData&) -> LightData& deleted
Copying is not allowed.
auto operator=(LightData&&) -> LightData& defaulted noexcept
Move assignment.
auto type() const -> Type
Light type.
auto color() const -> Color3
Light color.
auto intensity() const -> Float
Light intensity.
auto attenuation() const -> Vector3 new in Git master
Constant, linear and quadratic light attenuation.
auto range() const -> Float new in Git master
Light range.
auto innerConeAngle() const -> Rad new in Git master
Inner cone angle.
auto outerConeAngle() const -> Rad new in Git master
Outer cone angle.
auto importerState() const -> const void*
Importer-specific state.

Enum documentation

enum class Magnum::Trade::LightData::Type: UnsignedByte

Light type.

Enumerators
Ambient new in Git master

Ambient light, without any position, direction or attenuation. Meant to be added to ambient color in Phong workflows, has no use in physically based workflows.

Directional new in Git master

Light at a position that is infinitely far away, emitted in a direction of negative Z axis. The rotation is inherited from absolute object transformation; scale and position don't affect the light in any way. Because the light is at infinite distance, it's not attenuated in any way.

Infinite

Directional light.

Point

Point light, emitting light in all directions. The position is inherited from absolute object transformation; scale and rotation don't affect the light in any way. Brightness attenuates depending on the range() value.

Spot

Spot light, emitting light in a cone in direction of local negative Z axis. The position and rotation is inherited from absolute object transformation; scale doesn't affect the light in any way. The angle and falloff of the cone is defined using innerConeAngle() and outerConeAngle() and brightness attenuates depending on the range() value.

Function documentation

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, Float range, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master

Constructor.

Parameters
type Light type
color Light color
intensity Light intensity
attenuation Constant, linear and quadratic light attenuation factor. Expected to be {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light.
range Light range, after which the intensity is considered to be zero. Expected to be Constants::inf() for an Type::Ambient and Type::Directional light.
innerConeAngle Inner cone angle. Expected to be greater than or equal to 0.0_degf and less than or equal to outerConeAngle for a Type::Spot light, 360.0_degf otherwise.
outerConeAngle Outer cone angle. Expected to be greater than or equal to innerConeAngle and less than or equal to 360.0_degf for a Type::Spot light, 360.0_degf otherwise.
importerState Importer-specific state

This is a combined constructor including both attenuation and range parameters. Use LightData(Type, const Color3&, Float, const Vector3&, Rad, Rad, const void*) for light data defined by just attenuation parameters and LightData(Type, const Color3&, Float, Float, Rad, Rad, const void*) for light data defined by a range alone, and LightData(Type, const Color3&, Float, Rad, Rad, const void*) for an implicit inverse square attenuation. See Attenuation calculation for more information.

For lights other than spot it may be more convenient to use LightData(Type, const Color3&, Float, const Vector3&, Float, const void*) and friends instead.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, Float range, const void* importerState = nullptr) explicit noexcept new in Git master

Construct with implicit cone angles.

Parameters
type Light type
color Light color
intensity Light intensity
attenuation Constant, linear and quadratic light attenuation factor. Expected to be {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light.
range Light range, after which the intensity is considered to be zero. Expected to be Constants::inf() for an Type::Ambient and Type::Directional light.
importerState Importer-specific state

This is a combined constructor including both attenuation and range parameters. Use LightData(Type, const Color3&, Float, const Vector3&, const void*) for light data defined by just attenuation parameters and LightData(Type, const Color3&, Float, Float, const void*) for light data defined by a range alone, and LightData(Type, const Color3&, Float, const void*) for an implicit inverse square attenuation. See Attenuation calculation for more information.

For a Type::Spot light, innerConeAngle() is implicitly set to 0.0_degf and outerConeAngle() to 90.0_degf, and both are 360.0_degf otherwise. Use LightData(Type, const Color3&, Float, const Vector3&, Float, Rad, Rad, const void*) in order to specify cone angles as well.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master

Construct attenuation-based light data.

Parameters
type Light type
color Light color
intensity Light intensity
attenuation Constant, linear and quadratic light attenuation factor. Expected to be {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light.
innerConeAngle Inner cone angle. Expected to be greater than or equal to 0.0_degf and less than or equal to outerConeAngle for a Type::Spot light, 360.0_degf otherwise.
outerConeAngle Inner cone angle. Expected to be greater than or equal to innerConeAngle and less than or equal to 360.0_degf for a Type::Spot light, 360.0_degf otherwise.
importerState Importer-specific state

The range() is implicitly set to Constants::inf(). See Attenuation calculation for more information.

For lights other than spot it may be more convenient to use LightData(Type, const Color3&, Float, const Vector3&, const void*) instead.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, const Vector3& attenuation, const void* importerState = nullptr) explicit noexcept new in Git master

Construct attenuation-based light data with implicit cone angles.

Parameters
type Light type
color Light color
intensity Light intensity
attenuation Constant, linear and quadratic light attenuation factor. Expected to be {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light.
importerState Importer-specific state

The range() is implicitly set to Constants::inf(). See Attenuation calculation for more information.

For a Type::Spot light, innerConeAngle() is implicitly set to 0.0_degf and outerConeAngle() to 90.0_degf, and both are 360.0_degf otherwise. Use LightData(Type, const Color3&, Float, const Vector3&, Rad, Rad, const void*) in order to specify cone angles as well.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, Float range, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master

Construct range-based light data.

Parameters
type Light type
color Light color
intensity Light intensity
range Light range, after which the intensity is considered to be zero. Expected to be Constants::inf() for an Type::Ambient and Type::Directional light.
innerConeAngle Inner cone angle. Expected to be greater than or equal to 0.0_degf and less than or equal to outerConeAngle for a Type::Spot light, 360.0_degf otherwise.
outerConeAngle Outer cone angle. Expected to be greater than or equal to innerConeAngle and less than or equal to 360.0_degf for a Type::Spot light, 360.0_degf otherwise.
importerState Importer-specific state

The attenuation() is implicitly set to {1.0f, 0.0f, 1.0f} for a Type::Point and Type::Spot light and to {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light. See Attenuation calculation for more information.

For lights other than spot it may be more convenient to use LightData(Type, const Color3&, Float, Float, const void*) instead.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, Float range, const void* importerState = nullptr) explicit noexcept new in Git master

Construct range-based light data with implicit cone angles.

Parameters
type Light type
color Light color
intensity Light intensity
range Light range, after which the intensity is considered to be zero. Expected to be Constants::inf() for an Type::Ambient and Type::Directional light.
importerState Importer-specific state

The attenuation() is implicitly set to {1.0f, 0.0f, 1.0f} for a Type::Point and Type::Spot light and to {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light. See Attenuation calculation for more information.

For a Type::Spot light, innerConeAngle() is implicitly set to 0.0_degf and outerConeAngle() to 90.0_degf, and both are 360.0_degf otherwise. Use LightData(Type, const Color3&, Float, Float, Rad, Rad, const void*) in order to specify cone angles as well.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, Rad innerConeAngle, Rad outerConeAngle, const void* importerState = nullptr) explicit noexcept new in Git master

Construct light data with implicit attenuation.

Parameters
type Light type
color Light color
intensity Light intensity
innerConeAngle Inner cone angle. Expected to be greater than or equal to 0.0_degf and less than or equal to outerConeAngle for a Type::Spot light, 360.0_degf otherwise.
outerConeAngle Outer cone angle. Expected to be greater than or equal to innerConeAngle and less than or equal to 360.0_degf for a Type::Spot light, 360.0_degf otherwise.
importerState Importer-specific state

The attenuation() is implicitly set to {1.0f, 0.0f, 1.0f} for a Type::Point and Type::Spot light and to {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light; range() is always Constants::inf(). See Attenuation calculation for more information.

For lights other than spot it may be more convenient to use LightData(Type, const Color3&, Float, const void*) instead.

Magnum::Trade::LightData::LightData(Type type, const Color3& color, Float intensity, const void* importerState = nullptr) explicit noexcept

Construct light data with implicit attenuation and cone angles.

Parameters
type Light type
color Light color
intensity Light intensity
importerState Importer-specific state

The attenuation() is implicitly set to {1.0f, 0.0f, 1.0f} for a Type::Point and Type::Spot light and to {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light; range() is always Constants::inf(). See Attenuation calculation for more information.

For a Type::Spot light, innerConeAngle() is implicitly set to 0.0_degf and outerConeAngle() to 90.0_degf, and both are 360.0_degf otherwise. Use LightData(Type, const Color3&, Float, Rad, Rad, const void*) in order to specify cone angles as well.

Float Magnum::Trade::LightData::intensity() const

Light intensity.

Defined in candela (lm/sr) for Type::Point and Type::Spot, and in lux (lm/m2) for Type::Directional.

Vector3 Magnum::Trade::LightData::attenuation() const new in Git master

Constant, linear and quadratic light attenuation.

Values of $ \color{m-success} K_c $ , $ \color{m-success} K_l $ and $ \color{m-success} K_q $ in the attenuation equation. Always {1.0f, 0.0f, 0.0f} for an Type::Ambient and Type::Directional light, set to {1.0f, 0.0f, 1.0f} for range-based attenuation — and if range() is Constants::inf() as well, the attenuation equation is simply $ F_{att} = \frac{1}{1 + d^2} $ .

Float Magnum::Trade::LightData::range() const new in Git master

Light range.

Value of $ \color{m-info} R $ in the attenuation equation. If set to Constants::inf(), then:

  • if attenuation() is {1.0f, 0.0f, 1.0f}, the attenuation equation is $ F_{att} = \frac{1}{1 + d^2} $ ;
  • if attenuation() is {1.0f, 0.0f, 0.0f}, the attenuation equation is $ F_{att} = 1 $ .

The latter is always the case for a Type::Directional light.

Rad Magnum::Trade::LightData::innerConeAngle() const new in Git master

Inner cone angle.

For a Type::Spot light, it's always less than outerConeAngle(). For a Type::Directional or Type::Point light it's always 360.0_degf.

Rad Magnum::Trade::LightData::outerConeAngle() const new in Git master

Outer cone angle.

For a Type::Spot light, it's always greater than outerConeAngle() and less than or equal to 90.0_degf. For a Type::Directional or Type::Point light it's always 360.0_degf.

const void* Magnum::Trade::LightData::importerState() const

Importer-specific state.

See AbstractImporter::importerState() for more information.

Debug& operator<<(Debug& debug, LightData::Type value)

Debug output operator.