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:
DirectionalLightPointLightSpotLight
Requirements for Shadows:
Enable shadows on the renderer
Enable shadow casting on lights
Enable shadow receiving on objects
Configure shadow properties
1. DirectionalLight Shadows
Simple Example:
// 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:
// 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:
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:
// 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:
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:
// 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
Shadow Map Resolution: Higher values (2048, 4096) give better quality but reduce performance
Shadow Camera Frustum: Tighten the frustum to include only necessary areas
Shadow Types:
THREE.BasicShadowMap- Fast but low qualityTHREE.PCFShadowMap- Better quality (default)THREE.PCFSoftShadowMap- Softer edges
Selective Casting: Only enable
castShadowon important objectsShadow Radius: For softer shadow edges (WebGL2 required for best results)
Combining Multiple Shadow Lights
// 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.
تعليقات
إرسال تعليق