学习Three.js--光源Light+轨道控制器OrbitControls
前置核心说明
Three.js 的 3D 世界默认处于全黑状态 ,想要让「受光照影响的材质」显示出真实的光影效果,必须手动添加光源;而轨道控制器(OrbitControls)是 Three.js 官方提供的核心交互插件,能让你通过鼠标/触摸自由操控相机视角,是 3D 场景交互的标配。
核心规则
材质与光照的对应关系
材质类型
是否受光照影响
核心特点
MeshBasicMaterial
不受
纯色/纹理显示,无需光源,仅用于调试/简单UI
MeshLambertMaterial
受
漫反射光照,无高光,哑光质感
MeshPhongMaterial
受
高光光照,模拟光泽质感
MeshStandardMaterial
受
PBR物理光照,真实质感(推荐首选)
MeshPhysicalMaterial
受
高级PBR光照,极致写实
光源通用规则 :
所有光源均继承自 THREE.Light,共用「颜色、强度」核心属性;
光源创建后必须通过 scene.add(光源) 添加到场景才会生效;
除环境光外,其他光源(点/聚光/平行光)需设置 position 或 target 确定光照方向/位置。
一、Three.js 核心光源详解(参数+用法+效果)
1. 环境光 | AmbientLight(打底光,必加)
核心概念
AmbientLight 是全局均匀照明光源 ,无方向、无阴影、无衰减,作用是「给场景所有物体打基础亮度」,消除纯黑区域,但不会产生明暗对比和立体感,必须配合其他光源(如平行光)使用 。
创建语法 & 完整参数
javascript
复制代码
// 语法:new THREE.AmbientLight(颜色, 光照强度)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight); // 必须添加到场景才生效
参数名
类型
默认值
核心说明
color
Number/String/THREE.Color
0xffffff
光源颜色(支持16进制/字符串/Color对象)
intensity
Number
1
光照强度(0=无光,1=标准强度,建议0.2~0.8)
核心特点 & 效果
无位置属性(全局生效),无法设置 position;
效果:所有物体被均匀照亮,无明暗差异,单独使用会让物体像"平面贴纸",无立体感;
适用场景:作为「打底光」,配合主光源(平行光/聚光灯)使用,避免物体阴影区域纯黑。
2. 平行光 | DirectionalLight(主光源首选)
核心概念
DirectionalLight 模拟太阳光 ,光线平行发射,无衰减(距离不影响亮度),有明确的照射方向,能产生自然的明暗对比和阴影,是 3D 场景「主光源」的最优选择。
创建语法 & 完整参数
javascript
复制代码
// 语法:new THREE.DirectionalLight(颜色, 光照强度)
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
// 核心:设置光源位置(决定光照方向),默认在原点(0,0,0)
dirLight.position.set(5, 5, 5); // 光源在(5,5,5),朝向场景原点照射
// 可选:设置光照目标(默认朝向原点,可指定物体)
dirLight.target = cubeMesh; // 光照朝向立方体
// 可选:开启阴影投射(实现物体阴影效果)
dirLight.castShadow = true;
scene.add(dirLight);
参数名
类型
默认值
核心说明
color
Number/String/THREE.Color
0xffffff
光源颜色
intensity
Number
1
光照强度(建议0.8~1.2)
核心属性
属性名
说明
示例
position
光源位置(THREE.Vector3),决定光照方向
dirLight.position.set(5,5,5)
target
光照目标点/物体(默认原点)
dirLight.target = mesh
castShadow
是否投射阴影(默认false)
dirLight.castShadow = true
shadow
阴影配置对象(如阴影分辨率)
dirLight.shadow.mapSize.set(2048,2048)
效果 & 适用场景
效果:光线平行,物体朝向光源的面亮,背向面暗,立体感极强;
适用:场景主光源(模拟太阳光)、户外场景、全局照明。
3. 点光源 | PointLight(模拟灯泡/火把)
核心概念
PointLight 模拟灯泡、蜡烛、火把 ,从一个点向「所有方向」发射光线,有衰减(距离越远,光线越暗),能产生真实的距离明暗变化。
创建语法 & 完整参数
javascript
复制代码
// 语法:new THREE.PointLight(颜色, 强度, 光照距离, 衰减指数)
const pointLight = new THREE.PointLight(0xffaa00, 1.5, 10, 2);
// 核心:设置光源位置(默认原点)
pointLight.position.set(2, 2, 2);
// 可选:开启阴影投射
pointLight.castShadow = true;
scene.add(pointLight);
参数名
类型
默认值
核心说明
color
Number/String/THREE.Color
0xffffff
光源颜色
intensity
Number
1
光照强度
distance
Number
0
光照最大距离(0=无限远),超过该距离无光照
decay
Number
1
衰减指数(物理正确值为2,值越大衰减越快)
核心效果
效果:光源中心最亮,向四周逐渐变暗,距离越远越暗;
适用:灯泡、火把、台灯、局部点照明场景。
4. 聚光灯光源 | SpotLight(模拟手电筒/射灯)
核心概念
SpotLight 模拟手电筒、舞台射灯、汽车大灯 ,从一个点向「指定方向」发射「锥形光线」,有角度、有衰减,边缘可模糊,阴影效果精准。
创建语法 & 完整参数
javascript
复制代码
// 语法:new THREE.SpotLight(颜色, 强度, 距离, 锥形角度, 边缘模糊度, 衰减指数)
const spotLight = new THREE.SpotLight(0xffffff, 2, 15, Math.PI/6, 0.2, 2);
// 核心:设置光源位置+目标点
spotLight.position.set(0, 8, 0); // 光源在顶部
spotLight.target = cubeMesh; // 照射立方体
// 可选:开启阴影
spotLight.castShadow = true;
scene.add(spotLight);
参数名
类型
默认值
核心说明
color
Number/String/THREE.Color
0xffffff
光源颜色
intensity
Number
1
光照强度
distance
Number
0
光照最大距离
angle
Number(弧度)
Math.PI/3
锥形光照角度(越小,光束越集中)
penumbra
Number(0~1)
0
光线边缘模糊度(值越大,边缘越柔)
decay
Number
1
衰减指数
核心效果 & 适用场景
效果:锥形光照区域,中心亮、边缘渐暗,光束范围可控;
适用:手电筒、舞台射灯、汽车大灯、局部精准照明。
二、轨道控制器 OrbitControls(交互核心)
2.1 核心说明
OrbitControls 是 Three.js 官方提供的相机交互插件 ,无需手动编写鼠标/触摸事件,即可实现相机视角的「旋转、缩放、平移」,是 3D 场景交互的标配,支持鼠标和移动端触摸。
2.2 交互效果(固定规则,无需配置)
操作方式
交互效果
鼠标左键拖拽
相机围绕目标点旋转(场景整体旋转)
鼠标滚轮滚动
相机靠近/远离目标点(场景缩放)
鼠标右键拖拽
相机平移(场景整体平移)
移动端单指拖拽
旋转视角
移动端双指缩放
场景缩放
2.3 引入方式(两种场景,全覆盖)
方式1:CDN 引入(新手/快速测试,推荐)
直接在 HTML 中引入,无需安装依赖:
html
复制代码
<!-- 先引入Three.js核心库,再引入OrbitControls -->
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js'
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/controls/OrbitControls.js"
</script>
方式2:NPM 引入(工程化项目,Vue/React/Vite)
bash
复制代码
# 安装Three.js(已包含OrbitControls)
npm install three --save
javascript
复制代码
// 模块化导入
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
2.4 完整使用语法 & 核心参数
基础使用(最简版)
javascript
复制代码
// 语法:new OrbitControls(要控制的相机, 监听的DOM元素)
const controls = new OrbitControls(camera, renderer.domElement);
// 核心:开启阻尼效果(视角移动更顺滑,有惯性,体验更佳)
controls.enableDamping = true;
// 阻尼系数(越小,惯性越强,越顺滑)
controls.dampingFactor = 0.05;
// 动画循环(必须!enableDamping=true时,需实时更新控制器)
function animate() {
requestAnimationFrame(animate);
controls.update(); // 关键:更新控制器状态
renderer.render(scene, camera);
}
animate();
核心配置参数(高频使用)
参数名
类型
默认值
核心说明
enableDamping
Boolean
false
是否开启阻尼(顺滑惯性),推荐设为true
dampingFactor
Number
0.05
阻尼系数(0.01~0.1,越小越顺滑)
enableRotate
Boolean
true
是否允许旋转视角
rotateSpeed
Number
1.0
旋转速度(值越大,旋转越快)
enableZoom
Boolean
true
是否允许缩放视角
zoomSpeed
Number
1.0
缩放速度
enablePan
Boolean
true
是否允许平移视角
panSpeed
Number
1.0
平移速度
minDistance
Number
0
相机最小缩放距离(防止缩太近)
maxDistance
Number
Infinity
相机最大缩放距离(防止缩太远)
minPolarAngle
Number(弧度)
0
垂直旋转最小角度(防止视角翻到场景下方)
maxPolarAngle
Number(弧度)
Math.PI
垂直旋转最大角度
核心方法
方法名
说明
示例
update()
更新控制器状态(阻尼生效必备)
controls.update()
reset()
重置相机视角到初始状态
controls.reset()
dispose()
销毁控制器(释放内存)
controls.dispose()
2.5 关键注意事项(避坑必看)
阻尼效果必须加动画循环 :enableDamping = true 时,必须在 requestAnimationFrame 中调用 controls.update(),否则阻尼无效,视角卡顿;
无需监听change事件 :早期教程会监听 controls.addEventListener('change', () => renderer.render(...)),但动画循环本身会实时渲染,无需额外监听,反而会增加性能开销;
DOM元素绑定 :第二个参数必须传 renderer.domElement(渲染器的canvas画布),否则控制器无法监听鼠标事件;
视角限制 :通过 minDistance/maxDistance 限制缩放范围,避免用户缩放过度导致看不到场景。
三、完整示例代码(光源+OrbitControls 综合使用)
html
复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Three.js 光源+轨道控制器</title>
<style>body { margin: 0; overflow: hidden; }</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js'
import { OrbitControls } from "https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/controls/OrbitControls.js"
// 1. 创建三大核心
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; // 开启全局阴影支持
document.body.appendChild(renderer.domElement);
// 2. 创建几何体+材质+网格(PBR材质,受光照影响)
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00,
roughness: 0.5, // 粗糙度
metalness: 0.2 // 金属度
});
const cube = new THREE.Mesh(geometry, material);
cube.castShadow = true; // 立方体投射阴影
cube.receiveShadow = true; // 立方体接收阴影
scene.add(cube);
// 3. 创建地面(接收阴影)
const groundGeo = new THREE.PlaneGeometry(10, 10);
const groundMat = new THREE.MeshStandardMaterial({ color: 0xcccccc });
const ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2; // 旋转为地面
ground.position.y = -3;
ground.receiveShadow = true; // 地面接收阴影
scene.add(ground);
// 4. 添加光源(环境光+平行光+点光源)
// 4.1 环境光(打底)
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 4.2 平行光(主光源,模拟太阳)
const dirLight = new THREE.DirectionalLight(0xffffff, 1.2);
dirLight.position.set(5, 8, 5);
dirLight.castShadow = true;
dirLight.shadow.mapSize.set(2048, 2048); // 提高阴影分辨率
scene.add(dirLight);
// 4.3 点光源(模拟灯泡)
const pointLight = new THREE.PointLight(0xffaa00, 1.5, 10, 2);
pointLight.position.set(3, 2, 3);
pointLight.castShadow = true;
scene.add(pointLight);
// 5. 设置相机位置
camera.position.z = 8;
// 6. 创建轨道控制器(核心交互)
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 阻尼顺滑
controls.dampingFactor = 0.05;
controls.minDistance = 3; // 最小缩放距离
controls.maxDistance = 20; // 最大缩放距离
// 7. 动画循环
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01; // 立方体旋转
cube.rotation.y += 0.01;
controls.update(); // 更新控制器(阻尼生效)
renderer.render(scene, camera);
}
animate();
// 8. 窗口适配
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
</script>
</body>
</html>
示例效果
场景中有绿色立方体和灰色地面,立方体缓慢旋转;
平行光模拟太阳光,立方体产生自然阴影;
点光源模拟灯泡,立方体靠近光源的区域更亮;
鼠标操作:左键旋转视角、滚轮缩放、右键平移,视角移动顺滑有惯性;
窗口缩放时,场景自动适配尺寸。
核心总结
光源使用原则 :
受光照材质必须加光源,「环境光(打底)+ 主光源(平行光/聚光灯)」是最优组合;
平行光是场景主光源首选,点光源/聚光灯用于局部照明;
开启阴影需同时设置「光源.castShadow + 物体.castShadow/receiveShadow + 渲染器.shadowMap.enabled」。
OrbitControls 核心 :
阻尼效果(enableDamping=true)是提升交互体验的关键,必须在动画循环中调用 controls.update();
通过 min/maxDistance 限制缩放范围,避免视角失控;
无需监听 change 事件,动画循环实时渲染即可。
性能优化 :
光源阴影分辨率不宜过高(如2048足够),否则影响性能;
非必要场景关闭阴影,减少计算开销。