2.2光照属性 Three.js 光照属性详解与实践 2.2 光照属性详解 Three.js 提供了多种光照类型,每种光照类型都有其独特的属性,用于控制光照的颜色、强度、距离、衰减等。下面我们将逐一介绍这些属性。 2.2.1 通用光照属性 所有光照类型都继承了一些通用的属性: (Color):光照的颜色。默认为白色 (0xffffff)。可以使用 对象来设置颜色,例如: (Number):光照的强度。默认为 1。较高的值会使光照更亮。 (String):光照的名称。这对于在场景中识别和管理光照非常有用。 (Boolean):是否投射阴影。默认为 。只有 、 和 支持投射阴影。 (LightShadow):光照的阴影属性。只有当 为 时,此属性才有效。它包含控制阴影质量、分辨率和范围的属性。
Three.js 提供了多种光照类型,每种光照类型都有其独特的属性,用于控制光照的颜色、强度、距离、衰减等。下面我们将逐一介绍这些属性。
所有光照类型都继承了一些通用的属性:
color (Color):光照的颜色。默认为白色 (0xffffff)。可以使用 THREE.Color 对象来设置颜色,例如:
const light = new THREE.AmbientLight(0xff0000); // 红色环境光
intensity (Number):光照的强度。默认为 1。较高的值会使光照更亮。
light.intensity = 0.5; // 将光照强度设置为一半
name (String):光照的名称。这对于在场景中识别和管理光照非常有用。
light.name = "My Red Ambient Light";
castShadow (Boolean):是否投射阴影。默认为 false。只有 DirectionalLight、PointLight 和 SpotLight 支持投射阴影。
light.castShadow = true; // 允许光照投射阴影
shadow (LightShadow):光照的阴影属性。只有当 castShadow 为 true 时,此属性才有效。它包含控制阴影质量、分辨率和范围的属性。我们将在后续章节详细讨论阴影属性。
light.shadow.mapSize.width = 512; // 阴影贴图宽度 light.shadow.mapSize.height = 512; // 阴影贴图高度 light.shadow.camera.near = 0.5; // 阴影相机近平面 light.shadow.camera.far = 500; // 阴影相机远平面
环境光是一种均匀的光照,它会照亮场景中的所有物体,而不会产生阴影。它通常用于模拟场景中的间接光照。
AmbientLight 没有特定的属性,它只继承了通用光照属性,如 color 和 intensity。const ambientLight = new THREE.AmbientLight(0x404040); // 柔和的灰色环境光 scene.add(ambientLight);
方向光模拟来自无限远的光源,例如太阳。它会沿着特定方向照射场景中的所有物体。
position (Vector3):光的照射方向。虽然 DirectionalLight 有一个 position 属性,但它实际上定义了光的方向,而不是光的位置。光的方向是从 position 指向场景原点 (0, 0, 0) 的向量。
target (Object3D):光照的目标。光的方向是从光的位置指向目标的向量。 默认情况下,目标是场景原点。你可以通过设置 target.position 来更改目标位置。
shadow.camera.left, shadow.camera.right, shadow.camera.top, shadow.camera.bottom (Number):用于定义阴影相机的视锥体的边界。调整这些值可以控制阴影的覆盖范围和精度。
shadow.camera.near, shadow.camera.far (Number):阴影相机的近平面和远平面。这些值决定了阴影相机的深度范围。
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(1, 1, 1); // 从 (1, 1, 1) 指向原点 directionalLight.target.position.set(0, 0, 0); // 目标是原点 directionalLight.castShadow = true; 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 = -5; directionalLight.shadow.camera.right = 5; directionalLight.shadow.camera.top = 5; directionalLight.shadow.camera.bottom = -5; scene.add(directionalLight); scene.add(directionalLight.target); // 必须将 target 添加到场景中
点光源从一个点向所有方向发射光线,类似于灯泡。
distance (Number):光照的最大距离。超过此距离,光照强度将变为 0。默认为 0 (无限远)。
decay (Number):光照的衰减量。默认为 2。衰减值越高,光照衰减越快。Three.js 使用物理上更精确的平方反比衰减模型。
const pointLight = new THREE.PointLight(0xff0000, 1, 100); // 红色点光源 pointLight.position.set(0, 5, 0); pointLight.distance = 50; pointLight.decay = 2; pointLight.castShadow = true; pointLight.shadow.mapSize.width = 512; pointLight.shadow.mapSize.height = 512; pointLight.shadow.camera.near = 0.5; pointLight.shadow.camera.far = 50; scene.add(pointLight);
聚光灯从一个点向一个锥形区域发射光线,类似于手电筒。
target (Object3D):聚光灯的目标。光的方向是从光的位置指向目标的向量。 默认情况下,目标是场景原点。
distance (Number):光照的最大距离。超过此距离,光照强度将变为 0。默认为 0 (无限远)。
angle (Number):光锥的张角,以弧度表示。默认为 Math.PI / 3。
penumbra (Number):光锥边缘的模糊程度。值在 0 到 1 之间。默认为 0。
decay (Number):光照的衰减量。默认为 2。
shadow.camera.near, shadow.camera.far (Number):阴影相机的近平面和远平面。
const spotLight = new THREE.SpotLight(0xffffff, 1); spotLight.position.set(0, 10, 0); spotLight.target.position.set(0, 0, 0); spotLight.angle = Math.PI / 6; spotLight.penumbra = 0.2; spotLight.distance = 50; spotLight.decay = 2; spotLight.castShadow = true; spotLight.shadow.mapSize.width = 1024; spotLight.shadow.mapSize.height = 1024; spotLight.shadow.camera.near = 0.5; spotLight.shadow.camera.far = 50; scene.add(spotLight); scene.add(spotLight.target);
半球光是一种模拟天空光照的光源。它从上方照射的光线颜色和从下方照射的光线颜色不同。
skyColor (Color):从上方照射的光线的颜色。默认为白色 (0xffffff)。
groundColor (Color):从下方照射的光线的颜色。默认为白色 (0xffffff)。
intensity (Number):光照的强度。默认为 1。
const hemisphereLight = new THREE.HemisphereLight(0xaaaaaa, 0x444444, 1); hemisphereLight.position.set(0, 10, 0); scene.add(hemisphereLight);
区域光是一种模拟矩形区域光源的光源,例如荧光灯管或窗口。注意:RectAreaLight 需要 RectAreaLightUniformsLib 才能正常工作,并且只能与 MeshStandardMaterial 或 MeshPhysicalMaterial 一起使用。
width (Number):光的宽度。默认为 1。
height (Number):光的高度。默认为 1。
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 );
阴影是光照的重要组成部分,它能增加场景的真实感。只有 DirectionalLight、PointLight 和 SpotLight 支持投射阴影。
shadow.mapSize.width, shadow.mapSize.height (Number):阴影贴图的宽度和高度。较高的值会产生更清晰的阴影,但会消耗更多的资源。常用的值有 512, 1024, 2048。
shadow.camera.near, shadow.camera.far (Number):阴影相机的近平面和远平面。这些值决定了阴影相机的深度范围。
shadow.bias (Number):一个小的偏移量,用于解决阴影自遮挡问题。默认为 0。
shadow.normalBias (Number):沿着物体法线的偏移量,用于解决阴影自遮挡问题。默认为 0。
shadow.radius (Number):用于模糊阴影边缘的半径。仅在使用 PCFSoftShadowMap 时有效。默认为 1。
Three.js 提供了几种不同的阴影类型:
THREE.BasicShadowMap: 最简单的阴影贴图,性能最高,但质量最差。
THREE.PCFShadowMap: 使用 Percentage Closer Filtering (PCF) 来平滑阴影边缘。
THREE.PCFSoftShadowMap: 使用 PCF 的更柔和的版本,产生更平滑的阴影,但性能略低。
THREE.VSMShadowMap: 使用 Variance Shadow Maps (VSM),可以产生非常柔和的阴影,但可能会出现光渗漏问题。
可以通过设置渲染器的 shadowMap.type 属性来选择阴影类型:
renderer.shadowMap.enabled = true; renderer.shadowMap.type = THREE.PCFSoftShadowMap;
以下是一个完整的代码示例,演示如何调整各种光照属性:
import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'; import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js'; import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js'; // 初始化场景、相机和渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true }); 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); // 设置相机位置 camera.position.z = 5; // 创建一个立方体 const geometry = new THREE.BoxGeometry(); const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); cube.castShadow = true; cube.receiveShadow = true; scene.add(cube); // 创建一个地面 const planeGeometry = new THREE.PlaneGeometry(10, 10); const planeMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff }); const plane = new THREE.Mesh(planeGeometry, planeMaterial); plane.rotation.x = -Math.PI / 2; plane.receiveShadow = true; scene.add(plane); // 添加环境光 const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); // 添加方向光 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 = 500; scene.add(directionalLight); // 添加点光源 const pointLight = new THREE.PointLight(0xff0000, 1, 10); pointLight.position.set(0, 2, 0); pointLight.castShadow = true; pointLight.shadow.mapSize.width = 512; pointLight.shadow.mapSize.height = 512; pointLight.shadow.camera.near = 0.5; pointLight.shadow.camera.far = 10; scene.add(pointLight); // 添加聚光灯 const spotLight = new THREE.SpotLight(0xffffff, 1); spotLight.position.set(0, 5, 0); spotLight.target.position.set(0, 0, 0); spotLight.castShadow = true; spotLight.shadow.mapSize.width = 1024; spotLight.shadow.mapSize.height = 1024; spotLight.shadow.camera.near = 0.5; spotLight.shadow.camera.far = 20; scene.add(spotLight); scene.add(spotLight.target); //添加半球光 const hemisphereLight = new THREE.HemisphereLight(0xaaaaaa, 0x444444, 1); hemisphereLight.position.set(0, 5, 0); scene.add(hemisphereLight); // 添加区域光 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 ); // 动画循环 function animate() { requestAnimationFrame(animate); // 旋转立方体 cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); controls.update(); } animate();
以下是一个使用 mermaid 语法绘制的光照属性关系图:
理解和掌握 Three.js 中的光照属性对于创建逼真的场景至关重要。通过调整颜色、强度、距离、衰减等属性,你可以创造出各种各样的光照效果,从而提升你的 Three.js 应用的视觉体验。 此外,合理使用阴影也能增加场景的深度和真实感。记住,光照和阴影是相辅相成的,需要仔细调整才能达到最佳效果。 通过本文的学习,你应该能够熟练地运用 Three.js 中的各种光照类型,并根据需要调整其属性,从而创造出令人惊叹的 3D 场景。