Three.js Shadows & Lights: Summary with Examples

 

Three.js Shadows: Summary with Examples

Three.js provides powerful shadow capabilities that work with certain light types. Here's a comprehensive overview with simple and advanced examples.

Shadow Basics

Only these light types can cast shadows in Three.js:

  • DirectionalLight

  • PointLight

  • SpotLight

Requirements for Shadows:

  1. Enable shadows on the renderer

  2. Enable shadow casting on lights

  3. Enable shadow receiving on objects

  4. Configure shadow properties

1. DirectionalLight Shadows

Simple Example:

javascript
Copy
Download
// Setup
renderer.shadowMap.enabled = true;

const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 10, 7);
light.castShadow = true;
scene.add(light);

// Create a surface to receive shadows
const planeGeometry = new THREE.PlaneGeometry(20, 20);
const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xdddddd });
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
scene.add(plane);

// Create an object to cast shadows
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const box = new THREE.Mesh(boxGeometry, boxMaterial);
box.position.set(0, 1, 0);
box.castShadow = true;
scene.add(box);

Advanced Example:

javascript
Copy
Download
// Enhanced directional shadow with better quality
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(10, 20, 10);
dirLight.castShadow = true;

// Shadow camera setup
dirLight.shadow.camera.near = 0.5;
dirLight.shadow.camera.far = 500;
dirLight.shadow.camera.left = -20;
dirLight.shadow.camera.right = 20;
dirLight.shadow.camera.top = 20;
dirLight.shadow.camera.bottom = -20;

// Shadow map quality
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
dirLight.shadow.radius = 3; // Soft shadow edges

scene.add(dirLight);

// Shadow camera helper
const helper = new THREE.CameraHelper(dirLight.shadow.camera);
scene.add(helper);

// Complex scene with multiple shadow casters/receivers
// (Add your scene objects here that cast/receive shadows)

2. SpotLight Shadows

Simple Example:

javascript
Copy
Download
renderer.shadowMap.enabled = true;

const spotLight = new THREE.SpotLight(0xffffff, 1, 100, Math.PI/4, 0.5, 1);
spotLight.position.set(0, 15, 0);
spotLight.castShadow = true;
scene.add(spotLight);

// Target the light
spotLight.target.position.set(0, 0, 0);
scene.add(spotLight.target);

// Floor
const floor = new THREE.Mesh(
  new THREE.PlaneGeometry(20, 20),
  new THREE.MeshStandardMaterial({ color: 0xcccccc })
);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);

// Objects
const sphere = new THREE.Mesh(
  new THREE.SphereGeometry(2, 32, 32),
  new THREE.MeshStandardMaterial({ color: 0xff0000 })
);
sphere.position.set(0, 2, 0);
sphere.castShadow = true;
scene.add(sphere);

Advanced Example:

javascript
Copy
Download
// High-quality spotlight shadows with animation
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

const spotLight = new THREE.SpotLight(0xffffff, 2, 50, Math.PI/3, 0.2, 1);
spotLight.position.set(0, 20, 10);
spotLight.castShadow = true;

// Shadow quality settings
spotLight.shadow.mapSize.width = 2048;
spotLight.shadow.mapSize.height = 2048;
spotLight.shadow.camera.near = 0.5;
spotLight.shadow.camera.far = 50;
spotLight.shadow.focus = 0.8; // Focus quality

scene.add(spotLight);

// Target
spotLight.target.position.set(0, 0, 0);
scene.add(spotLight.target);

// Helper
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);

// Scene setup with multiple objects
// (Add your complex scene here)

// Animation
function animate() {
  const time = Date.now() * 0.001;
  
  // Move light in circular pattern
  spotLight.position.x = Math.sin(time) * 15;
  spotLight.position.z = Math.cos(time) * 15;
  
  // Update helper
  spotLightHelper.update();
  
  requestAnimationFrame(animate);
}
animate();

3. PointLight Shadows

Simple Example:

javascript
Copy
Download
renderer.shadowMap.enabled = true;

const pointLight = new THREE.PointLight(0xffffff, 1, 50);
pointLight.position.set(0, 10, 0);
pointLight.castShadow = true;
scene.add(pointLight);

// Floor
const floor = new THREE.Mesh(
  new THREE.PlaneGeometry(20, 20),
  new THREE.MeshStandardMaterial({ color: 0xcccccc })
);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(floor);

// Object
const torus = new THREE.Mesh(
  new THREE.TorusGeometry(3, 1, 16, 100),
  new THREE.MeshStandardMaterial({ color: 0x00ff00 })
);
torus.position.set(0, 5, 0);
torus.castShadow = true;
scene.add(torus);

Advanced Example:

javascript
Copy
Download
// Animated point light shadows with multiple objects
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

const pointLight = new THREE.PointLight(0xffffff, 2, 30);
pointLight.position.set(0, 15, 0);
pointLight.castShadow = true;

// Shadow settings
pointLight.shadow.mapSize.width = 1024;
pointLight.shadow.mapSize.height = 1024;
pointLight.shadow.camera.near = 0.1;
pointLight.shadow.camera.far = 50;
pointLight.shadow.radius = 2; // Soft shadows

scene.add(pointLight);

// Helper
const sphereSize = 0.5;
const pointLightHelper = new THREE.Mesh(
  new THREE.SphereGeometry(sphereSize, 16, 8),
  new THREE.MeshBasicMaterial({ color: 0xffffff })
);
pointLightHelper.position.copy(pointLight.position);
scene.add(pointLightHelper);

// Complex scene setup
// (Add your detailed scene with multiple objects here)

// Animation
function animate() {
  const time = Date.now() * 0.001;
  
  // Animate light position
  pointLight.position.x = Math.sin(time * 1.3) * 10;
  pointLight.position.y = 10 + Math.sin(time * 0.7) * 5;
  pointLight.position.z = Math.cos(time * 0.9) * 10;
  
  // Update helper
  pointLightHelper.position.copy(pointLight.position);
  
  // Change color over time
  pointLight.color.setHSL(Math.sin(time * 0.2) * 0.5 + 0.5, 1, 0.5);
  
  requestAnimationFrame(animate);
}
animate();

Shadow Optimization Tips

  1. Shadow Map Resolution: Higher values (2048, 4096) give better quality but reduce performance

  2. Shadow Camera Frustum: Tighten the frustum to include only necessary areas

  3. Shadow Types:

    • THREE.BasicShadowMap - Fast but low quality

    • THREE.PCFShadowMap - Better quality (default)

    • THREE.PCFSoftShadowMap - Softer edges

  4. Selective Casting: Only enable castShadow on important objects

  5. Shadow Radius: For softer shadow edges (WebGL2 required for best results)

Combining Multiple Shadow Lights

javascript
Copy
Download
// Complete shadow setup with multiple lights
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

// Directional light (sun)
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
dirLight.position.set(10, 20, 10);
dirLight.castShadow = true;
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
dirLight.shadow.camera.near = 0.5;
dirLight.shadow.camera.far = 100;
dirLight.shadow.camera.left = -20;
dirLight.shadow.camera.right = 20;
dirLight.shadow.camera.top = 20;
dirLight.shadow.camera.bottom = -20;
scene.add(dirLight);

// Spotlight (key light)
const spotLight = new THREE.SpotLight(0xffffff, 0.5, 50, Math.PI/4, 0.5, 1);
spotLight.position.set(5, 15, 5);
spotLight.castShadow = true;
spotLight.shadow.mapSize.width = 1024;
spotLight.shadow.mapSize.height = 1024;
spotLight.target.position.set(0, 0, 0);
scene.add(spotLight, spotLight.target);

// Point light (fill light)
const pointLight = new THREE.PointLight(0xffffff, 0.3, 30);
pointLight.position.set(-5, 10, -5);
pointLight.castShadow = true;
pointLight.shadow.mapSize.width = 512;
pointLight.shadow.mapSize.height = 512;
scene.add(pointLight);

// Scene objects
// (Add your objects with castShadow/receiveShadow properties)

Remember that shadows can be performance-intensive, so use them judiciously and optimize settings based on your scene requirements.

تعليقات

المشاركات الشائعة من هذه المدونة

this keyword in JavaScript

Debouncing وThrottling.