Skip to content

Shadows

Sky Pro renders cloud coverage into a top-down shadow map. Standard and custom materials can sample this map for animated cloud shadows.

This guide covers standard materials, custom TSL materials, and performance settings.

Quick Setup

For MeshStandardNodeMaterial and other materials using Three.js lighting, assign the cloud shadow node to the sun's DirectionalLight. Receiving meshes only need receiveShadow = true:

typescript
import * as THREE from "three/webgpu";
import { positionWorld } from "three/tsl";

const sunLight = new THREE.DirectionalLight(0xffffff, sky.sun.intensity.value);
sunLight.castShadow = true;
sunLight.shadow.mapSize.set(64, 64); // the depth-compare map goes unused, keep it tiny
sunLight.shadow.shadowNode = sky.cloudShadow(positionWorld);
scene.add(sunLight, sunLight.target);

terrainMesh.receiveShadow = true;

Each frame, point the light from the sun toward the receiving geometry:

typescript
const sunDir = sky.sun.direction.value; // unit vector toward the sun
sunLight.target.position.set(camera.position.x, 0, camera.position.z);
sunLight.position.set(
  camera.position.x + sunDir.x * 5000,
  sunDir.y * 5000,
  camera.position.z + sunDir.z * 5000,
);

Custom Materials

In a TSL colorNode, multiply sky.cloudShadow(worldPos) into direct light only. Do not apply it to ambient or sky lighting.

typescript
import { positionWorld } from "three/tsl";

const direct = albedo.mul(sunColor).mul(sky.cloudShadow(positionWorld));
const lit = direct.add(albedo.mul(ambientColor));

To reduce shadow strength for one material without changing the global intensity, mix the result toward 1.0:

typescript
const cloudShade = sky.cloudShadow(positionWorld);
const shadowFactor = mix(float(1.0), cloudShade, float(0.6)); // 60% as dark as the global bake

Tuning

Use sky.pipeline.cloudShadow to configure the shadow map:

SettingDefaultDescription
setResolution(n) / .resolutiontier-driven, 128–1024Square shadow-map size. Higher values sharpen cloud edges and increase rendering cost. See Quality Levels.
extent.value4000Half-width of the world-XZ footprint in meters — 4000 covers an 8 km box centered on the camera. Raising it trades texel density for reach at a fixed resolution.
intensity.value1.0Global shadow strength: 0 = no darkening, 1 = full.
mipLevel.valuetier-driven, 1–3Cloud-field mip level. Higher values produce softer shadows at lower cost.
lightSteps.value8March step count through the shell per texel. Raise it if thin, low cloud layers show banded shadow edges.
bakeInterval1Re-bake every Nth frame instead of every frame. Cloud shadows lag behind fast-moving weather by up to bakeInterval frames.
enabledtracks sky.clouds.enabledfalse skips the bake; every receiver reads full sun.
typescript
sky.pipeline.cloudShadow.extent.value = 8000;
sky.pipeline.cloudShadow.intensity.value = 0.9;
sky.pipeline.cloudShadow.setResolution(1024);

Moon Shadows

When TimeOfDay is active, the shadow map follows the moon after sunset. Assign the same shadow.shadowNode to a separate moon DirectionalLight if the scene uses one.

Limitations

  • Cloud-cast only. No shadows between scene objects — that's Three's own shadow-mapping, run separately.
  • Flat top-down lookup, not a true directional shadow map — least accurate at very low sun/moon elevation.
  • Finite footprint. Shadows and god-ray shafts fade to nothing past extent; a receiver far outside the box reads full sun.
  • Shared with god rays. The same texture supplies ground shadows and light shafts, so extent, intensity, and resolution affect both.

See Also

Commercial License - All Rights Reserved.