{T}

光源类型

Three.js 提供了多种光源类型来模拟不同的光照效果。正确选择和配置光源是实现真实感渲染的关键。

概述

光源决定了场景中的光照效果,影响物体的明暗、阴影和整体氛围。Three.js 提供了环境光、点光源、平行光、聚光灯等多种光源类型。

光源类型架构

code
THREE.Light (基类)
├── AmbientLight         环境光 - 均匀照明
├── HemisphereLight      半球光 - 天空/地面环境光
├── DirectionalLight     平行光 - 太阳光
├── PointLight           点光源 - 灯泡
├── SpotLight            聚光灯 - 手电筒/舞台灯
├── RectAreaLight        矩形区域光 - 窗户/屏幕
└── LightProbe           光照探针 - 烘焙光照

光源特性对比

光源类型方向性阴影衰减性能消耗典型用途
AmbientLight极低基础照明
HemisphereLight上下户外环境光
DirectionalLight平行太阳光
PointLight全向灯泡、火光
SpotLight锥形手电筒、舞台灯
RectAreaLight矩形窗户、广告牌

光源基类

所有光源都继承自 THREE.Light 基类:

javascript
import * as THREE from 'three';

// 光源基类构造函数
const light = new THREE.Light(color, intensity);

// 基类属性
light.color      // 光源颜色(THREE.Color)
light.intensity  // 光源强度
light.type       // 光源类型字符串

// 方法
light.color.set(0xff0000);  // 设置颜色
light.intensity = 2;        // 设置强度

Light 基类属性

属性类型默认值说明
colorColor0xffffff光源颜色
intensitynumber1光源强度
typestring-光源类型(只读)

环境光(AmbientLight)

环境光均匀地照亮场景中的所有物体,没有方向,不能产生阴影。

javascript
// 创建环境光
const ambientLight = new THREE.AmbientLight(
  0x404040,  // 颜色(深灰色)
  1          // 强度
);

scene.add(ambientLight);

// 调整强度
ambientLight.intensity = 0.5;

// 设置颜色
ambientLight.color.set(0xffffff);

构造参数

参数类型默认值说明
colorColor0xffffff光源颜色
intensitynumber1光源强度

特点

  • 无方向性,均匀照亮所有物体
  • 不产生阴影
  • 性能消耗极低
  • 强度不能太高,否则画面发白

适用场景

javascript
// 夜间场景 - 微弱蓝灰色环境光
const nightAmbient = new THREE.AmbientLight(0x1a1a2e, 0.3);

// 白天场景 - 中等强度白色环境光
const dayAmbient = new THREE.AmbientLight(0xffffff, 0.5);

// 室内场景 - 暖色调环境光
const indoorAmbient = new THREE.AmbientLight(0xffffee, 0.4);

// 地下场景 - 深色调环境光
const undergroundAmbient = new THREE.AmbientLight(0x222233, 0.2);

平行光(DirectionalLight)

平行光模拟太阳光,光线是平行的,常用于模拟远距离光源。

javascript
// 创建平行光
const directionalLight = new THREE.DirectionalLight(
  0xffffff,  // 颜色
  1          // 强度
);

// 设置位置(光线方向 = 从位置指向目标点)
directionalLight.position.set(5, 10, 5);

// 设置目标点(默认为原点)
directionalLight.target.position.set(0, 0, 0);
scene.add(directionalLight.target);  // 必须将目标添加到场景

scene.add(directionalLight);

构造参数

参数类型默认值说明
colorColor0xffffff光源颜色
intensitynumber1光源强度

DirectionalLight 特有属性

属性类型默认值说明
positionVector3(0,1,0)光源位置
targetObject3D-光照目标点
castShadowbooleanfalse是否投射阴影
shadowDirectionalLightShadow-阴影配置

阴影配置

javascript
// 启用阴影
directionalLight.castShadow = true;

// 阴影贴图尺寸
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;

// 阴影相机(正交相机)范围
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.camera.left = -10;
directionalLight.shadow.camera.right = 10;
directionalLight.shadow.camera.top = 10;
directionalLight.shadow.camera.bottom = -10;

// 阴影质量参数
directionalLight.shadow.bias = -0.0001;  // 阴影偏移
directionalLight.shadow.radius = 1;      // 软阴影半径

阴影相机调试

javascript
// 可视化阴影相机范围
const helper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(helper);

特点

  • 光线平行,模拟太阳光
  • 光照强度不随距离衰减
  • 可以产生阴影
  • 使用正交相机计算阴影

点光源(PointLight)

点光源从一个点向所有方向发射光线,类似于灯泡。

javascript
// 创建点光源
const pointLight = new THREE.PointLight(
  0xffffff,  // 颜色
  1,         // 强度
  100,       // 距离(影响范围,0 表示无限制)
  2          // 衰减系数
);

// 设置位置
pointLight.position.set(0, 5, 0);

scene.add(pointLight);

// 可视化光源位置
const pointLightHelper = new THREE.PointLightHelper(pointLight, 1);
scene.add(pointLightHelper);

构造参数

参数类型默认值说明
colorColor0xffffff光源颜色
intensitynumber1光源强度
distancenumber0最大距离(0=无限)
decaynumber2衰减系数

PointLight 特有属性

属性类型默认值说明
positionVector3(0,0,0)光源位置
distancenumber0光照距离(0=无限)
decaynumber2衰减系数
castShadowbooleanfalse是否投射阴影
shadowPointLightShadow-阴影配置

衰减计算

javascript
// 光照强度衰减公式
// 光照 = color * intensity / (decay * distance²)

// 衰减系数说明
pointLight.decay = 0;  // 无衰减(不推荐)
pointLight.decay = 1;  // 线性衰减
pointLight.decay = 2;  // 二次衰减(默认,最接近真实物理)

// 距离限制
pointLight.distance = 100;  // 超过 100 单位后光照为 0
pointLight.distance = 0;    // 无限距离

特点

  • 向所有方向发射
  • 强度随距离衰减
  • 可以产生阴影(使用立方体贴图,消耗较大)
  • 适合局部照明、灯泡、火光

聚光灯(SpotLight)

聚光灯从一点沿锥形方向发射光线,类似于手电筒。

javascript
// 创建聚光灯
const spotLight = new THREE.SpotLight(
  0xffffff,  // 颜色
  1,         // 强度
  100,       // 距离
  Math.PI / 6,  // 角度(弧度)
  0.1,       // 半影衰减
  2          // 衰减系数
);

// 设置位置和目标
spotLight.position.set(0, 10, 0);
spotLight.target.position.set(0, 0, 0);

scene.add(spotLight);
scene.add(spotLight.target);

// 可视化聚光灯
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
scene.add(spotLightHelper);

构造参数

参数类型默认值说明
colorColor0xffffff光源颜色
intensitynumber1光源强度
distancenumber0光照距离
anglenumberπ/3锥形角度(弧度)
penumbranumber0半影衰减(0-1)
decaynumber2衰减系数

SpotLight 特有属性

属性类型默认值说明
positionVector3(0,0,0)光源位置
targetObject3D-光照目标
anglenumberπ/3锥形角度
penumbranumber0边缘柔和度
distancenumber0光照距离
decaynumber2衰减系数
castShadowbooleanfalse是否投射阴影

聚光灯参数详解

javascript
// 聚光灯角度(锥形张开角度)
spotLight.angle = Math.PI / 6;  // 30 度
spotLight.angle = Math.PI / 4;  // 45 度

// 半影衰减(边缘柔和度,0-1)
spotLight.penumbra = 0;    // 硬边缘
spotLight.penumbra = 0.5;  // 中等柔和
spotLight.penumbra = 1;    // 完全柔和

// 聚焦(影响阴影质量)
spotLight.shadow.focus = 1;  // 聚焦程度(0-1)

特点

  • 锥形光束
  • 可调整角度和边缘柔和度
  • 可以产生阴影
  • 适合舞台灯光、手电筒效果

半球光(HemisphereLight)

半球光模拟天空和地面的环境光,提供自然的户外光照。

javascript
// 创建半球光
const hemisphereLight = new THREE.HemisphereLight(
  0xffffbb,  // 天空颜色(淡黄色)
  0x080820,  // 地面颜色(深蓝色)
  1          // 强度
);

scene.add(hemisphereLight);

// 调整颜色
hemisphereLight.color.set(0x87CEEB);        // 天空蓝
hemisphereLight.groundColor.set(0x8B4513);  // 地面棕

// 可视化
const hemisphereLightHelper = new THREE.HemisphereLightHelper(
  hemisphereLight,
  5  // 辅助球体大小
);
scene.add(hemisphereLightHelper);

构造参数

参数类型默认值说明
skyColorColor0xffffff天空颜色
groundColorColor0xffffff地面颜色
intensitynumber1光源强度

HemisphereLight 特有属性

属性类型默认值说明
colorColor0xffffff天空颜色
groundColorColor0xffffff地面颜色
positionVector3(0,100,0)位置(只影响方向)

不同时间段的半球光

javascript
// 清晨 - 暖色调天空
const morningLight = new THREE.HemisphereLight(
  0xffd4a0,  // 天空:暖橙色
  0x555555,  // 地面:灰色
  0.5
);

// 中午 - 明亮蓝天
const noonLight = new THREE.HemisphereLight(
  0x87CEEB,  // 天空:浅蓝色
  0x8B4513,  // 地面:棕色
  0.8
);

// 黄昏 - 橙红色天空
const sunsetLight = new THREE.HemisphereLight(
  0xff6b35,  // 天空:橙红色
  0x4a4a4a,  // 地面:深灰色
  0.4
);

// 夜晚 - 深蓝天空
const nightLight = new THREE.HemisphereLight(
  0x1a1a3e,  // 天空:深蓝色
  0x0a0a1a,  // 地面:深黑色
  0.2
);

特点

  • 模拟天空和地面反射光
  • 提供自然的上下明暗过渡
  • 不产生阴影
  • 适合户外场景

矩形区域光(RectAreaLight)

矩形区域光从矩形区域发射光线,产生柔和的光照效果。

javascript
import { RectAreaLightUniformsLib } from 'three/addons/lights/RectAreaLightUniformsLib.js';
import { RectAreaLightHelper } from 'three/addons/helpers/RectAreaLightHelper.js';

// 初始化(必须)
RectAreaLightUniformsLib.init();

// 创建矩形区域光
const rectLight = new THREE.RectAreaLight(
  0xffffff,  // 颜色
  5,         // 强度
  4,         // 宽度
  2          // 高度
);

// 设置位置和旋转
rectLight.position.set(0, 5, 0);
rectLight.rotation.x = -Math.PI / 2;  // 面向下

scene.add(rectLight);

// 可视化
const rectLightHelper = new RectAreaLightHelper(rectLight);
rectLight.add(rectLightHelper);

构造参数

参数类型默认值说明
colorColor0xffffff光源颜色
intensitynumber1光源强度
widthnumber10矩形宽度
heightnumber10矩形高度

RectAreaLight 特有属性

属性类型默认值说明
widthnumber10矩形宽度
heightnumber10矩形高度
intensitynumber1光源强度
注意事项
  1. 只支持 MeshStandardMaterialMeshPhysicalMaterial
  2. 不产生阴影
  3. 必须调用 RectAreaLightUniformsLib.init()
  4. 光源方向由物体朝向决定(默认朝向 +Z)

特点

  • 从矩形区域发射
  • 柔和的光照效果
  • 不产生阴影
  • 适合模拟窗户、屏幕、广告牌等面光源

光源属性详解

颜色设置

javascript
// 多种方式设置颜色
light.color.set(0xff0000);              // 十六进制
light.color.set('red');                 // 颜色名称
light.color.set('rgb(255, 0, 0)');      // RGB 字符串
light.color.set('hsl(0, 100%, 50%)');   // HSL 字符串
light.color.setRGB(1, 0, 0);            // RGB 分量
light.color.setHSL(0, 1, 0.5);          // HSL 分量

// 获取颜色
const hex = light.color.getHex();       // 十六进制
const r = light.color.r;                // 红色分量
const g = light.color.g;                // 绿色分量
const b = light.color.b;                // 蓝色分量

强度调整

javascript
// 设置强度
light.intensity = 2;

// 不同场景的推荐强度
AmbientLight:     0.3 - 0.8   // 基础照明
DirectionalLight: 0.5 - 2.0   // 主光源
PointLight:       0.5 - 3.0   // 局部照明
SpotLight:        1.0 - 3.0   // 聚光效果
HemisphereLight:  0.3 - 1.0   // 环境光
RectAreaLight:    1.0 - 10.0  // 面光源

位置和目标

javascript
// 设置位置
light.position.set(5, 10, 5);
light.position.x = 5;
light.position.y = 10;
light.position.z = 5;

// 设置目标(平行光、聚光灯)
light.target.position.set(0, 0, 0);

// 将目标添加到场景(重要!)
scene.add(light.target);

// 光线方向 = normalize(target.position - light.position)

光源使用示例

基础光照配置

javascript
import * as THREE from 'three';

// 创建场景
const scene = new THREE.Scene();

// 1. 环境光(基础照明)
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);

// 2. 平行光(主光源,模拟太阳)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10, 10, 10);
directionalLight.castShadow = true;
scene.add(directionalLight);

// 3. 点光源(补光)
const pointLight = new THREE.PointLight(0xff6600, 0.5, 50);
pointLight.position.set(-5, 5, -5);
scene.add(pointLight);

// 创建物体
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
cube.castShadow = true;
cube.receiveShadow = true;
scene.add(cube);

// 地面
const groundGeometry = new THREE.PlaneGeometry(20, 20);
const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x888888 });
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);

夜间场景

javascript
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x0a0a1a);

// 微弱环境光
const ambientLight = new THREE.AmbientLight(0x1a1a2e, 0.3);
scene.add(ambientLight);

// 月光(平行光)
const moonLight = new THREE.DirectionalLight(0x4444ff, 0.5);
moonLight.position.set(10, 20, 5);
scene.add(moonLight);

// 路灯(点光源)
const streetLights = [];
for (let i = 0; i < 5; i++) {
  const light = new THREE.PointLight(0xffaa00, 1, 20, 2);
  light.position.set(i * 10 - 20, 5, 0);
  light.castShadow = true;
  scene.add(light);
  streetLights.push(light);
}

室内场景

javascript
const scene = new THREE.Scene();

// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.3);
scene.add(ambientLight);

// 主光源(吸顶灯)
const ceilingLight = new THREE.PointLight(0xffffee, 1, 30, 2);
ceilingLight.position.set(0, 4, 0);
ceilingLight.castShadow = true;
scene.add(ceilingLight);

// 窗户光(平行光)
const windowLight = new THREE.DirectionalLight(0x87CEEB, 0.5);
windowLight.position.set(5, 3, 0);
scene.add(windowLight);

// 台灯(聚光灯)
const deskLight = new THREE.SpotLight(0xffaa55, 1, 10, Math.PI / 4, 0.5, 2);
deskLight.position.set(-3, 2, 2);
deskLight.target.position.set(-3, 0, 2);
scene.add(deskLight);
scene.add(deskLight.target);

舞台灯光

javascript
const scene = new THREE.Scene();

// 微弱环境光
const ambientLight = new THREE.AmbientLight(0x000000, 0.1);
scene.add(ambientLight);

// 主聚光灯
const mainSpot = new THREE.SpotLight(0xffffff, 2, 50, Math.PI / 6, 0.5, 1);
mainSpot.position.set(0, 15, 10);
mainSpot.target.position.set(0, 0, 0);
mainSpot.castShadow = true;
scene.add(mainSpot);

// 彩色聚光灯
const colors = [0xff0000, 0x00ff00, 0x0000ff];
const spotLights = colors.map((color, i) => {
  const spot = new THREE.SpotLight(color, 1, 30, Math.PI / 8, 0.3, 2);
  spot.position.set((i - 1) * 10, 10, 5);
  spot.target.position.set(0, 0, 0);
  scene.add(spot);
  return spot;
});

// 动态效果
function animate() {
  requestAnimationFrame(animate);
  
  const time = Date.now() * 0.001;
  
  // 旋转彩色灯光
  spotLights.forEach((spot, i) => {
    spot.target.position.x = Math.sin(time + i * Math.PI * 2 / 3) * 5;
    spot.target.position.z = Math.cos(time + i * Math.PI * 2 / 3) * 5;
  });
  
  renderer.render(scene, camera);
}
animate();

性能优化

光源数量控制

javascript
// ❌ 不推荐:大量光源(严重影响性能)
for (let i = 0; i < 100; i++) {
  const light = new THREE.PointLight(0xffffff, 0.1);
  light.position.set(Math.random() * 10, Math.random() * 10, Math.random() * 10);
  scene.add(light);
}

// ✅ 推荐:少量光源 + 环境贴图
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);

const mainLight = new THREE.DirectionalLight(0xffffff, 1);
scene.add(mainLight);

// 使用环境贴图模拟间接光照
scene.environment = envMap;

阴影性能优化

javascript
// 根据需求设置阴影贴图尺寸
light.shadow.mapSize.width = 1024;   // 移动端:512-1024
light.shadow.mapSize.height = 1024;  // 桌面端:1024-2048

// 紧凑的阴影相机范围
light.shadow.camera.near = 1;
light.shadow.camera.far = 20;
light.shadow.camera.left = -5;
light.shadow.camera.right = 5;

// 只在需要时启用阴影
light.castShadow = true;

光源数量限制

平台推荐光源数说明
移动端≤ 3避免实时阴影
桌面端≤ 8可适当增加
高性能设备≤ 16需测试验证

常见问题解答

Q: 场景太暗或太亮怎么办?

A: 调整光源强度和环境光:

javascript
// 场景太暗
ambientLight.intensity = 0.5;  // 增加环境光
directionalLight.intensity = 1.5;  // 增加主光

// 场景太亮
ambientLight.intensity = 0.2;  // 降低环境光
directionalLight.intensity = 0.5;  // 降低主光

Q: 物体看起来很平,没有立体感?

A: 缺少方向光或光源位置不合适:

javascript
// 添加方向光创建明暗对比
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);  // 斜上方
scene.add(directionalLight);

// 降低环境光强度
ambientLight.intensity = 0.3;

Q: 如何实现真实的光照效果?

A: 使用标准材质和环境贴图:

javascript
// 使用 MeshStandardMaterial 或 MeshPhysicalMaterial
const material = new THREE.MeshStandardMaterial({
  color: 0xffffff,
  metalness: 0.5,
  roughness: 0.5
});

// 添加环境贴图
scene.environment = envMap;

Q: 点光源和聚光灯的阴影为什么很慢?

A: 这两种光源使用立方体贴图渲染阴影,消耗较大:

javascript
// 降低阴影贴图分辨率
pointLight.shadow.mapSize.width = 512;
pointLight.shadow.mapSize.height = 512;

// 或者只在必要时启用阴影
pointLight.castShadow = false;  // 默认关闭

Q: 如何模拟白天/夜晚的时间变化?

A: 动态调整光源参数:

javascript
function updateLighting(timeOfDay) {
  // timeOfDay: 0-1,0=午夜,0.5=正午
  
  // 太阳位置
  const angle = timeOfDay * Math.PI;
  sunLight.position.set(
    Math.cos(angle) * 50,
    Math.sin(angle) * 50,
    0
  );
  
  // 太阳强度
  sunLight.intensity = Math.max(0, Math.sin(angle));
  
  // 天空颜色
  const skyColor = new THREE.Color().lerpColors(
    new THREE.Color(0x1a1a2e),  // 夜晚
    new THREE.Color(0x87CEEB),  // 白天
    Math.sin(angle)
  );
  hemisphereLight.color.copy(skyColor);
}

最佳实践

  1. 合理搭配光源:环境光 + 主光源 + 补光(三点光照)
  2. 控制光源数量:移动端不超过 3 个,桌面端不超过 8 个
  3. 优化阴影:合理设置阴影贴图尺寸和相机范围
  4. 使用辅助器:开发时使用光源辅助器可视化
  5. 考虑性能:实时阴影消耗较大,静态场景可使用光照贴图
  6. 材质选择:使用 MeshStandardMaterial 以获得正确的光照响应

相关链接