Overview
Threadbox provides multiple lighting options including default lights, realistic sun simulation based on time and location, and dynamic building shadows that follow the sun’s position.
Default Lighting
Basic three-point lighting for your scene:
const tb = new Threebox ( map , gl , {
defaultLights: true
});
This creates:
Ambient Light : Soft overall illumination
Directional Light : Main key light
Directional Light (back) : Fill/rim light
Manual Default Lights
const tb = new Threebox ( map , gl );
// Add default lights after creation
tb . defaultLights ();
// Access lights
console . log ( tb . lights . ambientLight );
console . log ( tb . lights . dirLight );
console . log ( tb . lights . dirLightBack );
Real Sunlight
Basic Sun Simulation
Realistic sun position based on date, time, and location:
const tb = new Threebox ( map , gl , {
realSunlight: true ,
realSunlightHelper: true // Show light direction helper
});
This automatically:
Calculates sun position using map center coordinates
Uses current date/time
Updates lighting to match sun altitude and azimuth
Creates hemisphere light for sky illumination
Sun Position Calculation
Threadbox uses the SunCalc library to compute accurate sun positions:
// Get sun position for specific time and location
const date = new Date ( '2024-06-21T12:00:00' );
const coords = [ - 122.4194 , 37.7749 ]; // San Francisco
const sunPos = tb . getSunPosition ( date , coords );
console . log ( 'Altitude:' , sunPos . altitude ); // Angle above horizon (radians)
console . log ( 'Azimuth:' , sunPos . azimuth ); // Compass direction (radians)
Update Sun Position
Dynamically update sunlight:
// Update to specific time
const newDate = new Date ( '2024-12-21T15:30:00' );
const newCoords = [ - 73.9352 , 40.7306 ]; // New York
tb . setSunlight ( newDate , newCoords );
Sun Times
Get sunrise, sunset, and other sun events:
const sunTimes = tb . getSunTimes ( new Date (), [ - 122.4194 , 37.7749 ]);
console . log ( 'Sunrise:' , sunTimes . sunrise );
console . log ( 'Sunset:' , sunTimes . sunset );
console . log ( 'Solar Noon:' , sunTimes . solarNoon );
console . log ( 'Golden Hour:' , sunTimes . goldenHour );
console . log ( 'Dusk:' , sunTimes . dusk );
console . log ( 'Night:' , sunTimes . night );
Sun times include: sunrise, sunriseEnd, goldenHourEnd, solarNoon, goldenHour, sunsetStart, sunset, dusk, nauticalDusk, night, nadir, nightEnd, nauticalDawn, dawn
Custom Lighting
Adding Custom Lights
const tb = new Threebox ( map , gl );
// Point light
const pointLight = new THREE . PointLight ( 0xffffff , 1.0 , 100 );
pointLight . position . set ( 0 , 0 , 50 );
tb . scene . add ( pointLight );
// Spot light
const spotLight = new THREE . SpotLight ( 0xffffff , 1.0 );
spotLight . position . set ( 0 , 0 , 100 );
spotLight . castShadow = true ;
tb . scene . add ( spotLight );
// Access and modify default lights
if ( tb . lights . ambientLight ) {
tb . lights . ambientLight . intensity = 0.5 ;
}
if ( tb . lights . dirLight ) {
tb . lights . dirLight . color . setHex ( 0xffeecc ); // Warm light
tb . lights . dirLight . intensity = 1.2 ;
}
Light Helper
Visualize light direction:
const tb = new Threebox ( map , gl , {
realSunlight: true ,
realSunlightHelper: true
});
// Update helper position
tb . updateLightHelper ();
// Access helper
if ( tb . lights . dirLightHelper ) {
tb . lights . dirLightHelper . visible = true ;
}
Shadows
Object Shadows
Enable shadows for 3D models:
tb . loadObj ({
obj: '/models/building.glb' ,
type: 'gltf' ,
scale: 1 ,
units: 'meters'
}, ( model ) => {
model . setCoords ([ - 122.4194 , 37.7749 , 0 ]);
// Enable shadow casting
model . castShadow = true ;
// Enable shadow receiving
model . receiveShadow = true ;
tb . add ( model );
});
Shadow Properties
Cast Shadows
Receive Shadows
Both
// Object casts shadows onto other objects
model . castShadow = true ;
// Automatically adds shadow plane
if ( model . shadowPlane ) {
console . log ( 'Shadow plane created' );
}
// Enable shadow rendering
tb . renderer . shadowMap . enabled = true ;
tb . renderer . shadowMap . type = THREE . PCFSoftShadowMap ; // Soft shadows
// Configure directional light for shadows
if ( tb . lights . dirLight ) {
tb . lights . dirLight . castShadow = true ;
tb . lights . dirLight . shadow . mapSize . width = 2048 ;
tb . lights . dirLight . shadow . mapSize . height = 2048 ;
tb . lights . dirLight . shadow . camera . near = 0.5 ;
tb . lights . dirLight . shadow . camera . far = 500 ;
}
BuildingShadows
Realistic shadows for Mapbox fill-extrusion buildings:
Setup
const tb = new Threebox ( map , gl , {
realSunlight: true
});
// Add 3D buildings layer first
map . addLayer ({
'id' : '3d-buildings' ,
'source' : 'composite' ,
'source-layer' : 'building' ,
'filter' : [ '==' , 'extrude' , 'true' ],
'type' : 'fill-extrusion' ,
'paint' : {
'fill-extrusion-color' : '#aaa' ,
'fill-extrusion-height' : [ 'get' , 'height' ],
'fill-extrusion-base' : [ 'get' , 'min_height' ],
'fill-extrusion-opacity' : 0.6
}
});
// Add building shadows layer
const BuildingShadows = require ( './objects/effects/BuildingShadows' );
const shadowLayer = new BuildingShadows ({
layerId: 'building-shadows' ,
buildingsLayerId: '3d-buildings' ,
minAltitude: 0.10 // Minimum sun altitude to show shadows
}, tb );
map . addLayer ( shadowLayer , '3d-buildings' );
BuildingShadows Options
Option Type Default Description layerIdstringRequired ID for the shadow layer buildingsLayerIdstringRequired ID of the buildings layer minAltitudenumber0.10Minimum sun altitude (radians) to show shadows
How It Works
BuildingShadows uses WebGL shaders to:
Read sun position from Threebox (tb.getSunPosition)
Project building geometry onto the ground plane
Offset projection based on sun azimuth and altitude
Render as semi-transparent black layer
Dynamic Sun Updates
// Update shadows when sun position changes
function updateSunPosition () {
const now = new Date ();
const center = map . getCenter ();
tb . setSunlight ( now , [ center . lng , center . lat ]);
// Shadows automatically update via tb.getSunPosition
map . triggerRepaint ();
}
// Update every minute
setInterval ( updateSunPosition , 60000 );
Ground Layer Updates
Update terrain/satellite layer brightness based on sun:
const tb = new Threebox ( map , gl , {
realSunlight: true ,
terrain: true
});
// Automatically updates ground layer brightness
// based on sun altitude
// Manual update
const sunPos = tb . getSunPosition ( new Date (), [ lng , lat ]);
tb . updateSunGround ( sunPos );
Complete Lighting Example
map . on ( 'load' , () => {
const tb = new Threebox ( map , gl , {
realSunlight: true ,
realSunlightHelper: false ,
terrain: true
});
// Enable shadows in renderer
tb . renderer . shadowMap . enabled = true ;
tb . renderer . shadowMap . type = THREE . PCFSoftShadowMap ;
// Configure directional light shadows
if ( tb . lights . dirLight ) {
tb . lights . dirLight . castShadow = true ;
tb . lights . dirLight . shadow . mapSize . width = 2048 ;
tb . lights . dirLight . shadow . mapSize . height = 2048 ;
}
// Add 3D buildings
map . addLayer ({
'id' : '3d-buildings' ,
'source' : 'composite' ,
'source-layer' : 'building' ,
'filter' : [ '==' , 'extrude' , 'true' ],
'type' : 'fill-extrusion' ,
'paint' : {
'fill-extrusion-color' : '#ccc' ,
'fill-extrusion-height' : [ 'get' , 'height' ],
'fill-extrusion-base' : [ 'get' , 'min_height' ],
'fill-extrusion-opacity' : 0.8
}
});
// Add building shadows
const BuildingShadows = require ( './BuildingShadows' );
const shadows = new BuildingShadows ({
layerId: 'building-shadows' ,
buildingsLayerId: '3d-buildings' ,
minAltitude: 0.05
}, tb );
map . addLayer ( shadows , '3d-buildings' );
// Add custom 3D layer
map . addLayer ({
id: 'custom-layer' ,
type: 'custom' ,
renderingMode: '3d' ,
onAdd : function ( map , gl ) {
// Load model with shadows
tb . loadObj ({
obj: '/models/monument.glb' ,
type: 'gltf' ,
scale: 2 ,
units: 'meters' ,
rotation: { x: 90 , y: 0 , z: 0 }
}, ( model ) => {
model . setCoords ([ - 122.4194 , 37.7749 , 0 ]);
model . castShadow = true ;
model . receiveShadow = true ;
tb . add ( model );
});
},
render : function ( gl , matrix ) {
tb . update ();
}
});
// Time controls
function setTime ( hour ) {
const date = new Date ();
date . setHours ( hour );
date . setMinutes ( 0 );
const center = map . getCenter ();
tb . setSunlight ( date , [ center . lng , center . lat ]);
console . log ( 'Sun position updated for' , hour + ':00' );
}
// Add UI controls
document . getElementById ( 'time-slider' ). addEventListener ( 'input' , ( e ) => {
setTime ( parseInt ( e . target . value ));
});
});
Shadow Map Size Use 1024x1024 or 2048x2048 for shadow maps. Higher = better quality but slower.
Selective Shadows Only enable castShadow for important objects, not all objects.
Update Frequency Don’t update sun position every frame. Use intervals (1-5 minutes).
Shadow Distance Limit shadow camera far distance to reduce calculations.
See Also