Game.Rendering.LightUtils
Assembly: Game
Namespace: Game.Rendering
Type: public static class LightUtils
Base: System.Object (static utility class)
Summary:
Utility helper for converting between different photometric and radiometric light units used by the game (Lumen, Candela, Lux, Ev100, Nits/luminance) for punctual (point/spot/frustum), area (rectangle/tube) and line lights. Provides formulas for solid-angle based conversions, area luminance conversions, and helpers to convert with a distance or spot geometry. Several routines rely on ColorUtils.s_LightMeterCalibrationConstant for EV <-> luminance conversions.
Fields
-
private static float s_LuminanceToEvFactor
Calculated factor used when converting luminance (candela) to Ev (EV100). It equals Log2(100 / ColorUtils.s_LightMeterCalibrationConstant). Used to offset the base-2 log when computing EV100 from luminance. -
private static float s_EvToLuminanceFactor
The negative of s_LuminanceToEvFactor (i.e. -Log2(100 / ColorUtils.s_LightMeterCalibrationConstant)). Used when converting EV100 back to a luminance (candela).
Properties
- This class exposes only static methods and contains no public instance or get/set properties.
Constructors
- This is a static utility class — there are no public constructors or instance constructors.
Methods
-
public static float ConvertSpotLightLumenToCandela(float intensity, float angle, bool exact)
Converts a spot light's luminous flux (lumen) to luminous intensity (candela).
Parameters: intensity (lumens), angle (spot cone angle, expected in radians when calling this method directly), exact (if false a simplified approximation is used).
Behavior: If exact == false returns intensity / π. If exact == true returns intensity / (2 * (1 - cos(angle/2)) * π) — i.e. lumen divided by the spot cone solid angle. -
public static float ConvertFrustrumLightLumenToCandela(float intensity, float angleA, float angleB)
Converts frustum/pyramid-shaped spot lumen to candela using solid angle = 4 * asin(sin(angleA/2) * sin(angleB/2)). Angles are in radians. -
public static float ConvertPunctualLightLumenToCandela(LightType lightType, float lumen, float initialIntensity, bool enableSpotReflector)
Dispatch helper that returns candela for a punctual light. For Spot with enableSpotReflector = true it returns initialIntensity (the editor already provides a candela-like value); otherwise falls back to point light formula. -
public static float ConvertPointLightLumenToCandela(float intensity)
Converts spherical point light lumen -> candela by dividing by total solid angle of a sphere: intensity / (4π). -
public static float ConvertPunctualLightLumenToLux(LightType lightType, float lumen, float initialIntensity, bool enableSpotReflector, float distance)
Converts punctual light lumen -> lux at a given distance. Internally converts lumen->candela then candela->lux. Distance is in meters; lux = candela / distance^2. -
public static float ConvertCandelaToLux(float candela, float distance)
Converts luminous intensity (candela) to illuminance (lux) at a distance: lux = candela / (distance^2). -
public static float ConvertPunctualLightLumenToEv(LightType lightType, float lumen, float initialIntensity, bool enableSpotReflector)
Converts lumen to EV100 for a punctual light. Internally converts to candela then to EV using log2. -
public static float ConvertCandelaToEv(float candela)
Converts candela (treated as luminance here) to EV100 via ConvertLuminanceToEv. -
public static float ConvertLuminanceToEv(float luminance)
Converts luminance (candela units used as the luminance value) to EV100: EV = log2(luminance) + s_LuminanceToEvFactor. Uses base-2 logarithm. -
public static float ConvertPunctualLightCandelaToLumen(LightType lightType, SpotLightShape spotLightShape, float candela, bool enableSpotReflector, float spotAngle, float aspectRatio)
Converts a punctual light's candela back to lumen. For Spot + enableSpotReflector it branches by spot shape: - Cone: calls ConvertSpotLightCandelaToLumen, expects spotAngle in radians (the method that calls this converts degrees->radians).
- Pyramid: calculates axis angles from aspect ratio then uses frustum conversion.
-
Default: uses point light formula.
-
public static float ConvertSpotLightCandelaToLumen(float intensity, float angle, bool exact)
Inverse of ConvertSpotLightLumenToCandela. If exact==false multiplies by π. If exact==true multiplies by solid angle: intensity * (2 * (1 - cos(angle/2)) * π). Angle expects radians. -
public static float ConvertFrustrumLightCandelaToLumen(float intensity, float angleA, float angleB)
Inverse of frustum candela->lumen: intensity * (4 * asin(sin(angleA/2) * sin(angleB/2))). Angles in radians. -
public static float ConvertPointLightCandelaToLumen(float intensity)
Inverse of point light: intensity * (4π). -
public static void CalculateAnglesForPyramid(float aspectRatio, float spotAngle, out float angleA, out float angleB)
Given a pyramid spotAngle (in radians) and aspect ratio, calculates the two opening angles for the pyramid frustum. If aspectRatio < 1 it inverts it (so the wider side is handled). angleA is the provided spotAngle; angleB is computed from tan relationships. -
public static float ConvertPunctualLightLuxToLumen(LightType lightType, SpotLightShape spotLightShape, float lux, bool enableSpotReflector, float spotAngle, float aspectRatio, float distance)
Converts illuminance (lux) at distance back to lumen by converting lux->candela (lux * d^2) then candela->lumen using ConvertPunctualLightCandelaToLumen. -
public static float ConvertLuxToCandela(float lux, float distance)
Converts lux to candela: candela = lux * distance^2. -
public static float ConvertLuxToEv(float lux, float distance)
Converts lux at distance to EV100 by converting to candela then to EV via ConvertLuminanceToEv. -
public static float ConvertPunctualLightEvToLumen(LightType lightType, SpotLightShape spotLightShape, float ev, bool enableSpotReflector, float spotAngle, float aspectRatio)
Converts EV100 to lumen for punctual lights: ev -> candela -> lumen (taking into account spot shape/reflector). -
public static float ConvertEvToCandela(float ev)
Converts EV100 to luminance/candela via ConvertEvToLuminance. -
public static float ConvertEvToLuminance(float ev)
Converts EV100 to luminance: luminance = 2^(ev + s_EvToLuminanceFactor). -
public static float ConvertEvToLux(float ev, float distance)
Converts EV100 to lux at a distance by converting EV->candela (luminance) then candela->lux. -
public static float ConvertAreaLightLumenToLuminance(AreaLightShape areaLightShape, float lumen, float width, float height = 0f)
Converts area light lumen to luminance (nits) depending on shape: - Tube -> CalculateLineLightLumenToLuminance
- Rectangle -> ConvertRectLightLumenToLuminance
-
Default -> returns lumen as-is
-
public static float ConvertRectLightLumenToLuminance(float intensity, float width, float height)
Rectangle area luminance: intensity / (width * height * π). (π factor converts to radiometric convention used in game.) -
public static float CalculateLineLightLumenToLuminance(float intensity, float lineWidth)
Tube/line light lumen -> luminance: intensity / (π * 4 * lineWidth). -
public static float ConvertAreaLightLuminanceToLumen(AreaLightShape areaLightShape, float luminance, float width, float height = 0f)
Inverse of ConvertAreaLightLumenToLuminance. Dispatches by AreaLightShape: - Tube -> CalculateLineLightLuminanceToLumen
-
Rectangle -> ConvertRectLightLuminanceToLumen
-
public static float CalculateLineLightLuminanceToLumen(float intensity, float lineWidth)
Inverse for tube: intensity * (π * 4 * lineWidth). -
public static float ConvertRectLightLuminanceToLumen(float intensity, float width, float height)
Inverse for rectangle: intensity * (width * height * π). -
public static float ConvertAreaLightEvToLumen(AreaLightShape AreaLightShape, float ev, float width, float height)
Converts EV100 for area light -> luminance -> lumen by calling ConvertEvToLuminance then ConvertAreaLightLuminanceToLumen. -
public static float ConvertAreaLightLumenToEv(AreaLightShape AreaLightShape, float lumen, float width, float height)
Converts area lumen -> luminance -> EV100 via ConvertAreaLightLumenToLuminance then ConvertLuminanceToEv. -
public static float ConvertLightIntensity(LightUnit oldLightUnit, LightUnit newLightUnit, LightEffect editor, float intensity)
High-level helper used by the editor to convert an editor-supplied intensity value between LightUnit enums (Lumen, Candela, Lux, Ev100, Nits). Uses LightEffect editor fields (m_Type, m_EnableSpotReflector, m_SpotShape, m_SpotAngle, m_AspectRatio, m_LuxAtDistance, m_AreaShape, m_ShapeWidth, m_ShapeHeight) to perform context-aware conversions depending on whether the light is punctual or area. Returns the converted intensity.
Notes: - Angles: low-level methods ConvertSpotLight... and frustum methods expect angles in radians. The editor-level conversion (ConvertPunctualLightCandelaToLumen) converts spotAngle from degrees to radians before calling the low-level routines. So when calling low-level spot/frustum methods directly, pass radians. - Distances: distances are in world units (meters). Lux/candela conversions assume inverse-square law: lux = candela / distance^2. - EV conversions: depend on ColorUtils.s_LightMeterCalibrationConstant. Changing that calibration constant will shift EV <-> luminance mappings. - Units: - Lumen: total luminous flux (lm) - Candela: luminous intensity (cd) - Lux: illuminance at a surface (lx) - Nits / luminance: cd/m^2 - Ev / EV100: photographic exposure value normalized to ISO 100
Usage Example
// Convert a 1200 lumen point light to candela and lux at 2 meters:
float lumens = 1200f;
float candela = LightUtils.ConvertPointLightLumenToCandela(lumens); // lumens / (4*pi)
float luxAt2m = LightUtils.ConvertCandelaToLux(candela, 2f); // candela / (2^2)
// Convert a spot defined in the editor from lumen -> candela (editor uses degrees for spotAngle)
LightEffect editor = /* existing LightEffect with m_Type = LightType.Spot */;
float lumenValue = 800f;
float candelaFromEditor = LightUtils.ConvertPunctualLightLumenToCandela(editor.m_Type, lumenValue, lumenValue, editor.m_EnableSpotReflector);
If you want, I can also provide a short cheat-sheet table summarizing the main formulas (point/spot/frustum/area and EV conversions).