Web Engine Docs
Preparing documentation
Use the search bar to quickly find any topic
Preparing documentation
Use the search bar to quickly find any topic
Lighting system with directional, point, and spot lights, cascaded shadow maps, environment mapping, and light probes.
Web Engine's lighting system provides realistic illumination using a combination of direct lights, shadows, environment maps, and global illumination techniques. Built on Three.js, it supports all standard light types with advanced shadow mapping.
Parallel rays from infinite distance, like the sun
Omnidirectional light from a single point
Cone-shaped light with distance falloff
Uniform light from all directions
Sky/ground color gradient
Rectangular light source (rect area only)
Directional lights simulate the sun or moon, with parallel rays from an infinite distance. Perfect for outdoor scenes.
import * as THREE from 'three';// Create directional light (sun)const sunLight = new THREE.DirectionalLight(0xffffff, // Color (white)1.0 // Intensity);// Position (direction is from position to target)sunLight.position.set(50, 100, 50);sunLight.target.position.set(0, 0, 0);// Enable shadowssunLight.castShadow = true;// Configure shadow camera (orthographic frustum)sunLight.shadow.camera.left = -100;sunLight.shadow.camera.right = 100;sunLight.shadow.camera.top = 100;sunLight.shadow.camera.bottom = -100;sunLight.shadow.camera.near = 0.5;sunLight.shadow.camera.far = 500;// Shadow map resolutionsunLight.shadow.mapSize.width = 2048;sunLight.shadow.mapSize.height = 2048;// Shadow bias to reduce artifactssunLight.shadow.bias = -0.0001;scene.add(sunLight);scene.add(sunLight.target);
Shadow Camera Size
The shadow camera bounds (left, right, top, bottom) determine the shadow map coverage. Make them large enough to cover your scene, but not too large or shadow quality will suffer.
Point lights emit light in all directions from a single point, like a light bulb. They support distance falloff and shadows.
// Create point lightconst pointLight = new THREE.PointLight(0xff6600, // Orange color1.0, // Intensity100, // Distance (0 = infinite)2.0 // Decay factor (physically correct = 2));pointLight.position.set(10, 5, 0);// Enable shadows (uses cubemap)pointLight.castShadow = true;pointLight.shadow.mapSize.width = 512;pointLight.shadow.mapSize.height = 512;pointLight.shadow.camera.near = 0.5;pointLight.shadow.camera.far = 100;scene.add(pointLight);// Optional: Add visual helperconst helper = new THREE.PointLightHelper(pointLight, 0.5);scene.add(helper);
Point Light Shadows
Point light shadows require rendering the scene 6 times (one for each cubemap face), making them expensive. Use sparingly or disable shadows for distant point lights.
Spot lights emit a cone of light, like a flashlight or stage light. They support angle, penumbra, and distance falloff.
// Create spot lightconst spotLight = new THREE.SpotLight(0xffffff, // Color1.0, // Intensity100, // DistanceMath.PI / 4, // Angle (45 degrees)0.5, // Penumbra (soft edge)2.0 // Decay);spotLight.position.set(0, 10, 0);spotLight.target.position.set(0, 0, 0);// Enable shadowsspotLight.castShadow = true;spotLight.shadow.mapSize.width = 1024;spotLight.shadow.mapSize.height = 1024;spotLight.shadow.camera.near = 1;spotLight.shadow.camera.far = 100;spotLight.shadow.camera.fov = 45;scene.add(spotLight);scene.add(spotLight.target);
Ambient lights provide uniform illumination from all directions, while hemisphere lights create a sky/ground color gradient.
// Ambient light (uniform)const ambientLight = new THREE.AmbientLight(0x404040, // Dark gray0.5 // Intensity);scene.add(ambientLight);// Hemisphere light (sky/ground gradient)const hemisphereLight = new THREE.HemisphereLight(0x87ceeb, // Sky color (light blue)0x543210, // Ground color (brown)0.6 // Intensity);hemisphereLight.position.set(0, 50, 0);scene.add(hemisphereLight);
Web Engine uses shadow mapping to render realistic shadows. Configure shadow properties for quality and performance:
| Property | Effect | Recommended |
|---|---|---|
| mapSize | Shadow resolution | 1024-2048 for directional, 512 for point/spot |
| bias | Reduce shadow acne | -0.0001 to -0.001 |
| normalBias | Reduce peter panning | 0 to 0.05 |
| radius | Blur amount (PCF) | 1-3 for soft shadows |
| camera.near/far | Shadow depth range | Match scene bounds |
// Enable shadows on rendererrenderer.shadowMap.enabled = true;renderer.shadowMap.type = THREE.PCFSoftShadowMap; // Soft shadows// Mark objects to cast/receive shadowsmesh.castShadow = true;mesh.receiveShadow = true;// Configure light shadowslight.castShadow = true;light.shadow.bias = -0.0001;light.shadow.normalBias = 0.02;light.shadow.radius = 2;light.shadow.mapSize.set(2048, 2048);
| Type | Quality | Performance | Use Case |
|---|---|---|---|
| BasicShadowMap | Low (hard edges) | Fast | Mobile/low-end |
| PCFShadowMap | Medium (soft) | Medium | Default |
| PCFSoftShadowMap | High (very soft) | Slow | Desktop/high-end |
| VSMShadowMap | High (soft + blur) | Slow | Advanced effects |
CSM provides high-quality shadows at all distances by splitting the camera frustum into multiple cascades, each with its own shadow map:
import { Environment } from '@web-engine-dev/core/engine/ecs/components';// Enable CSM in the environmentconst envEntity = createEntity(world);addComponent(world, envEntity, Environment);// Configure CSMEnvironment.csmEnabled[envEntity] = 1; // Enable CSMEnvironment.csmIntensity[envEntity] = 1.0; // Shadow strength// Sun position (light direction)Environment.sunPosition[envEntity][0] = 50; // xEnvironment.sunPosition[envEntity][1] = 100; // yEnvironment.sunPosition[envEntity][2] = 50; // z// CSM automatically:// - Creates 3 shadow cascades// - Uses 2048x2048 shadow maps per cascade// - Updates shadow cameras each frame// - Handles cascade transitions smoothly
CSM Performance
CSM renders the scene 3 times (once per cascade), but provides excellent shadow quality at all distances. The engine uses "practical" cascade distribution for balanced near/far quality.
Environment maps provide reflections and ambient lighting from the surrounding environment:
import * as THREE from 'three';import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';// Load HDR environment mapconst rgbeLoader = new RGBELoader();rgbeLoader.load('environment.hdr', (texture) => {// Convert to cubemap for reflectionsconst pmremGenerator = new THREE.PMREMGenerator(renderer);pmremGenerator.compileEquirectangularShader();const envMap = pmremGenerator.fromEquirectangular(texture).texture;// Apply to scenescene.environment = envMap; // IBL lightingscene.background = envMap; // Skybox// Apply to materialsmaterial.envMap = envMap;material.envMapIntensity = 1.0;pmremGenerator.dispose();texture.dispose();});
Create a skybox using a cubemap or equirectangular texture:
// Cubemap skyboxconst cubeTextureLoader = new THREE.CubeTextureLoader();const skybox = cubeTextureLoader.load(['px.jpg', 'nx.jpg', // +x, -x'py.jpg', 'ny.jpg', // +y, -y'pz.jpg', 'nz.jpg', // +z, -z]);scene.background = skybox;// Equirectangular skyboxconst textureLoader = new THREE.TextureLoader();const equirect = textureLoader.load('sky.jpg');equirect.mapping = THREE.EquirectangularReflectionMapping;scene.background = equirect;
Light probes capture lighting information at specific points for image-based lighting:
import { LightProbeGenerator } from 'three/examples/jsm/lights/LightProbeGenerator.js';// Create light probe from cubemapconst cubeCamera = new THREE.CubeCamera(0.1, 100, 256);cubeCamera.position.set(0, 5, 0);scene.add(cubeCamera);// Update cubemapcubeCamera.update(renderer, scene);// Generate light probeconst lightProbe = LightProbeGenerator.fromCubeRenderTarget(renderer,cubeCamera.renderTarget);scene.add(lightProbe);// Influence objects near the probe positionlightProbe.intensity = 1.0;
Achieve realistic indirect lighting using environment maps and light probes:
Use HDR environment maps for realistic ambient lighting:
// HDR environment for IBLscene.environment = hdrEnvironmentMap;// Materials automatically use environment for:// - Ambient lighting (indirect diffuse)// - Reflections (indirect specular)// Control intensity per materialmaterial.envMapIntensity = 1.0; // Full strengthmaterial.envMapIntensity = 0.5; // Half strength
Bake AO maps or use SSAO post-processing for contact shadows:
// Baked AO mapmaterial.aoMap = aoTexture;material.aoMapIntensity = 1.0;// Requires second UV channelgeometry.setAttribute('uv2', geometry.attributes.uv);// Or use SSAO post-processing (see Post-Processing docs)const ssaoPass = new SSAOPass(scene, camera);composer.addPass(ssaoPass);
| Technique | Cost | Notes |
|---|---|---|
| Directional Light | Low | One light per scene recommended |
| Point Light | Medium | Avoid many overlapping point lights |
| Spot Light | Medium | Similar cost to point lights |
| Point Light Shadows | High | 6 shadow maps per light |
| CSM Shadows | Medium | 3 shadow maps total |
| Environment Map | Low | One-time setup, no per-frame cost |
Light Count Limits
Three.js limits the number of lights per material (default: 16 total, 4 shadows). Exceeding these limits can cause lights to be ignored. Use baked lighting or light probes for static illumination.