Skip to content

Light Descriptor

LightDesc is a group of classes that manage lighting in a 3D scene. It provides various lighting techniques including ambient light, sunlight, and Image-Based Lighting.

Lighting only affects surfaces that have normals. A surface without normals is shaded uniformly (fully lit) and needs no light at all. Once a surface has normals, however, it renders completely black unless at least one light is present. Add a light whenever the scene contains:

  • Meshes or GLTF models that ship vertex normals
  • quantized-mesh terrain loaded with requestVertexNormals: true
  • raster-dem terrain rendered with a hillshade material

If nothing in your scene has normals, you can skip lights entirely and everything is drawn evenly lit.

navara_three provides multiple light descriptor types to address various lighting requirements:

Purpose: Ambient light for the entire scene Description: Basic ambient light that illuminates all objects evenly. Does not cast shadows. Key features:

  • Simple and lightweight
  • Uniform lighting from all directions
  • No shadows

Usage example:

import ThreeView, { Color } from "@navaramap/three";
import { AmbientLightDesc } from "@navaramap/three_default_descs";
view.registerLight("ambient", AmbientLightDesc);
view.addLight<AmbientLightDesc>({
ambient: {
color: new Color().setHex(0xffffff),
intensity: 1.0
}
});

Purpose: Image-Based Lighting (IBL) Description: Pre-computed environment lighting using spherical harmonics. Achieves realistic indirect lighting. Key features:

  • Fast computation using Spherical Harmonics
  • Uses pre-computed lighting data
  • Ideal for static environment lighting

Usage example:

import ThreeView from "@navaramap/three";
import { LightProbeDesc } from "@navaramap/three_default_descs";
view.registerLight("lightProbe", LightProbeDesc);
view.addLight<LightProbeDesc>({
lightProbe: {
sh: new THREE.SphericalHarmonics3().set(coefficients),
intensity: 0.05
}
});

Purpose: Dynamic sky lighting Description: Dynamic environment lighting that works in conjunction with atmospheric scattering simulation. Automatically updates based on the sun’s position. Key features:

  • Automatic integration with the atmosphere system
  • Follows the sun’s position
  • Automatically computes different lighting for day and night

Usage example:

import ThreeView from "@navaramap/three";
import { SkyLightProbeDesc } from "@navaramap/three_default_descs";
view.registerLight("skyLightProbe", SkyLightProbeDesc);
view.addLight<SkyLightProbeDesc>({
skyLightProbe: {
intensity: 1.0
}
});

Purpose: Sunlight and shadows Description: High-quality sunlight simulation using Cascaded Shadow Maps (CSM). Works in conjunction with atmospheric scattering. Key features:

  • High-quality Cascaded Shadow Maps
  • Dynamic color computation via atmospheric scattering
  • Detailed shadow parameter control

Usage example:

import ThreeView from "@navaramap/three";
import { SunLightDesc } from "@navaramap/three_default_descs";
view.registerLight("sun", SunLightDesc);
view.addLight<SunLightDesc>({
sun: {
intensity: 1.0,
castShadow: true,
shadowMapSize: 2048,
shadowCascadeCount: 4
}
});
Light TypeShadowsDynamic UpdateAtmosphere IntegrationPrimary UsePerformance
AmbientLightDescNoneManualNot requiredBasic ambient lightVery lightweight
LightProbeDescNoneManualNot requiredStatic IBLLightweight
SkyLightProbeDescNoneAutomaticRequiredDynamic sky lightingModerate
SunLightDescYes (CSM)AutomaticRecommendedSunlight and shadowsHeavy (with shadows)

The simplest lighting configuration:

// AmbientLightDesc must be registered
view.addLight<AmbientLightDesc>({
ambient: { intensity: 1.0 }
});

For realistic scenes, combine multiple light Descriptors. Using DefaultPlugin from three_default_plugin registers all Descriptors at once, and addDefaultPhotorealScene() makes it easy to set up a photorealistic scene.

import { DefaultPlugin } from "@navaramap/three_default_plugin";
const plugin = new DefaultPlugin();
view.addPlugin(plugin);
await view.init();
// Set up a photorealistic scene at once (includes SunLight + SkyLightProbe, etc.)
const layers = plugin.addDefaultPhotorealScene();
// Add additional ambient light as needed
view.addLight<AmbientLightDesc>({
ambient: { intensity: 0.3 }
});

For night scenes, additional light probes are effective:

// Set up a photorealistic scene with DefaultPlugin
const layers = plugin.addDefaultPhotorealScene();
// Night light probe (LightProbeDesc is registered by DefaultPlugin)
const nightLight = view.addLight<LightProbeDesc>({
lightProbe: {
sh: new THREE.SphericalHarmonics3().set(NIGHT_COEFFICIENTS),
intensity: 0.05
}
});
// Enable only at night
view.atmosphere.on("sunChanged", () => {
const isNight = view.atmosphere.isAtNight(view.camera.positionECEF);
nightLight.update({ visible: isNight });
});
  • AmbientLight: The most lightweight, can always be enabled
  • LightProbe/SkyLightProbe: Moderate, adds shader computation
  • SunLight with CSM: The heaviest, especially when using high-resolution shadow maps

The following light Descriptors integrate with the atmosphere system:

  • SkyLightProbeDesc: Uses the atmosphere’s irradiance texture (required)
  • SunLightDesc: Uses the atmosphere’s transmittance texture (recommended)

If you are not using the atmosphere system, use AmbientLightDesc and LightProbeDesc instead.