光照 (Lights) 与阴影 (Shadows) Three.js 光照 (Lights) 与阴影 (Shadows) 光照是 Three.js 场景中至关重要的组成部分,它赋予了场景深度、真实感和氛围。阴影则进一步增强了这种真实感,使物体能够相互遮挡光线,从而创建更具沉浸感的视觉体验。 光照类型 (Light Types) Three.js 提供了多种不同类型的光照,每种光照都有其独特的特性和用途。 AmbientLight (环境光): 环境光是一种均匀照射场景中所有物体的光。它没有方向,不会产生阴影。通常用作场景中的基础照明,以确保即使在没有其他光源的情况下,物体也能被看到。 DirectionalLight (平行光): 平行光模拟来自无限远的光源,例如太阳。
光照是 Three.js 场景中至关重要的组成部分,它赋予了场景深度、真实感和氛围。阴影则进一步增强了这种真实感,使物体能够相互遮挡光线,从而创建更具沉浸感的视觉体验。
Three.js 提供了多种不同类型的光照,每种光照都有其独特的特性和用途。
AmbientLight (环境光):
环境光是一种均匀照射场景中所有物体的光。它没有方向,不会产生阴影。通常用作场景中的基础照明,以确保即使在没有其他光源的情况下,物体也能被看到。
const ambientLight = new THREE.AmbientLight(0x404040); // soft white light scene.add(ambientLight);
DirectionalLight (平行光):
平行光模拟来自无限远的光源,例如太阳。它具有特定的方向,所有光线都沿该方向平行传播。平行光可以产生阴影。
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(1, 1, 1); directionalLight.castShadow = true; // 启用阴影投射 scene.add(directionalLight);
PointLight (点光源):
点光源从一个点向所有方向发射光线。类似于灯泡。点光源可以产生阴影。
const pointLight = new THREE.PointLight(0xffffff, 1, 100); // color, intensity, distance pointLight.position.set(0, 5, 0); pointLight.castShadow = true; scene.add(pointLight);
SpotLight (聚光灯):
聚光灯从一个点向一个锥形区域发射光线。类似于手电筒或舞台灯光。聚光灯可以产生阴影。
const spotLight = new THREE.SpotLight(0xffffff, 1); spotLight.position.set(5, 5, 5); spotLight.target.position.set(0, 0, 0); spotLight.angle = Math.PI / 6; spotLight.penumbra = 0.2; spotLight.decay = 2; spotLight.distance = 200; spotLight.castShadow = true; scene.add(spotLight); scene.add(spotLight.target); // 聚光灯需要一个目标
HemisphereLight (半球光):
半球光模拟户外环境光,它从天空和地面两个方向发射不同颜色的光。它没有方向,不会产生阴影。
const hemisphereLight = new THREE.HemisphereLight(0xffffff, 0x080820, 1); // skyColor, groundColor, intensity scene.add(hemisphereLight);
RectAreaLight (矩形区域光):
矩形区域光从一个矩形区域发射光线。这种光照类型可以创建更柔和、更逼真的阴影,但计算成本较高。 需要RectAreaLightUniformsLib
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js'; RectAreaLightUniformsLib.init(); const rectLight = new THREE.RectAreaLight( 0xffffff, 5, 4, 10 ); rectLight.position.set( 5, 5, 0 ); rectLight.lookAt( 0, 0, 0 ); scene.add( rectLight ) const rectLightHelper = new RectAreaLightHelper( rectLight ); rectLight.add( rectLightHelper );
要在 Three.js 中启用阴影,需要执行以下步骤:
启用渲染器的阴影:
renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 可选的阴影类型
启用光源的阴影投射:
directionalLight.castShadow = true;
启用物体的阴影接收和投射:
mesh.receiveShadow = true; // 接收阴影 mesh.castShadow = true; // 投射阴影
调整阴影贴图参数 (可选):
可以调整光源的 shadow 属性来优化阴影质量和性能。
directionalLight.shadow.mapSize.width = 1024; directionalLight.shadow.mapSize.height = 1024; directionalLight.shadow.camera.near = 0.5; directionalLight.shadow.camera.far = 500; directionalLight.shadow.camera.left = -10; directionalLight.shadow.camera.right = 10; directionalLight.shadow.camera.top = 10; directionalLight.shadow.camera.bottom = -10;
以下是一个简单的 Three.js 场景,展示了如何使用平行光和阴影:
import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; // 创建场景 const scene = new THREE.Scene(); // 创建相机 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 5, 10); // 创建渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; // 启用阴影 renderer.shadowMap.type = THREE.PCFSoftShadowMap; document.body.appendChild(renderer.domElement); // 创建轨道控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; // 创建平行光 const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(1, 1, 1); directionalLight.castShadow = true; // 启用阴影投射 directionalLight.shadow.mapSize.width = 1024; directionalLight.shadow.mapSize.height = 1024; directionalLight.shadow.camera.near = 0.5; directionalLight.shadow.camera.far = 50; scene.add(directionalLight); // 创建环境光 const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); // 创建平面 const planeGeometry = new THREE.PlaneGeometry(10, 10); const planeMaterial = new THREE.MeshStandardMaterial({ color: 0x808080 }); const plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.rotation.x = -Math.PI / 2; plane.receiveShadow = true; // 接收阴影 scene.add(plane); // 创建立方体 const cubeGeometry = new THREE.BoxGeometry(1, 1, 1); const cubeMaterial = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(cubeGeometry, cubeMaterial); cube.position.set(0, 0.5, 0); cube.castShadow = true; // 投射阴影 scene.add(cube); // 动画循环 function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } animate(); // 窗口大小调整 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });
阴影计算可能会对性能产生影响,尤其是在复杂的场景中。以下是一些优化阴影的方法:
使用适当的阴影贴图大小: 较小的阴影贴图可以提高性能,但会降低阴影质量。
调整阴影相机参数: 优化阴影相机的 near, far, left, right, top, bottom 属性,使其紧密贴合场景中的阴影区域。
使用 ShadowMapViewer: ShadowMapViewer 可以帮助你可视化阴影贴图,从而更容易地调整阴影相机参数。
使用阴影类型: THREE.PCFSoftShadowMap 提供更柔和的阴影,但计算成本更高。THREE.BasicShadowMap 性能最高,但阴影质量较低。
避免不必要的阴影投射: 只让需要投射阴影的物体投射阴影。
阴影不显示: 确保渲染器的阴影已启用,光源的 castShadow 属性已设置为 true,并且物体的 receiveShadow 和 castShadow 属性已正确设置。
阴影质量差: 尝试增加阴影贴图的大小,或调整阴影相机参数。
性能问题: 尝试降低阴影贴图的大小,或使用性能更高的阴影类型。
光照和阴影是 Three.js 中创建逼真场景的关键。通过理解不同类型的光照以及如何启用和优化阴影,可以创建更具吸引力和沉浸感的 3D 体验。 记住,良好的光照和阴影设计可以显著提升你 Three.js 项目的视觉效果。