学习Three.js--光源Light+轨道控制器OrbitControls

学习Three.js--光源Light+轨道控制器OrbitControls

前置核心说明

Three.js 的 3D 世界默认处于全黑状态,想要让「受光照影响的材质」显示出真实的光影效果,必须手动添加光源;而轨道控制器(OrbitControls)是 Three.js 官方提供的核心交互插件,能让你通过鼠标/触摸自由操控相机视角,是 3D 场景交互的标配。

核心规则

  1. 材质与光照的对应关系
材质类型 是否受光照影响 核心特点
MeshBasicMaterial 不受 纯色/纹理显示,无需光源,仅用于调试/简单UI
MeshLambertMaterial 漫反射光照,无高光,哑光质感
MeshPhongMaterial 高光光照,模拟光泽质感
MeshStandardMaterial PBR物理光照,真实质感(推荐首选)
MeshPhysicalMaterial 高级PBR光照,极致写实
  1. 光源通用规则
    • 所有光源均继承自 THREE.Light,共用「颜色、强度」核心属性;
    • 光源创建后必须通过 scene.add(光源) 添加到场景才会生效;
    • 除环境光外,其他光源(点/聚光/平行光)需设置 positiontarget 确定光照方向/位置。

一、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 关键注意事项(避坑必看)

  1. 阻尼效果必须加动画循环enableDamping = true 时,必须在 requestAnimationFrame 中调用 controls.update(),否则阻尼无效,视角卡顿;
  2. 无需监听change事件 :早期教程会监听 controls.addEventListener('change', () => renderer.render(...)),但动画循环本身会实时渲染,无需额外监听,反而会增加性能开销;
  3. DOM元素绑定 :第二个参数必须传 renderer.domElement(渲染器的canvas画布),否则控制器无法监听鼠标事件;
  4. 视角限制 :通过 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>

示例效果

  1. 场景中有绿色立方体和灰色地面,立方体缓慢旋转;
  2. 平行光模拟太阳光,立方体产生自然阴影;
  3. 点光源模拟灯泡,立方体靠近光源的区域更亮;
  4. 鼠标操作:左键旋转视角、滚轮缩放、右键平移,视角移动顺滑有惯性;
  5. 窗口缩放时,场景自动适配尺寸。

核心总结

  1. 光源使用原则
    • 受光照材质必须加光源,「环境光(打底)+ 主光源(平行光/聚光灯)」是最优组合;
    • 平行光是场景主光源首选,点光源/聚光灯用于局部照明;
    • 开启阴影需同时设置「光源.castShadow + 物体.castShadow/receiveShadow + 渲染器.shadowMap.enabled」。
  2. OrbitControls 核心
    • 阻尼效果(enableDamping=true)是提升交互体验的关键,必须在动画循环中调用 controls.update()
    • 通过 min/maxDistance 限制缩放范围,避免视角失控;
    • 无需监听 change 事件,动画循环实时渲染即可。
  3. 性能优化
    • 光源阴影分辨率不宜过高(如2048足够),否则影响性能;
    • 非必要场景关闭阴影,减少计算开销。
相关推荐
Amumu121382 小时前
Vue核心(二)
前端·javascript·vue.js
墨轩尘2 小时前
qiankun的简单使用
前端·vue.js·前端框架
EEEzhenliang2 小时前
CSS样式所有使用方式(书写位置)
前端·css
愚公移码3 小时前
蓝凌EKP产品:关联机制浅析
java·服务器·前端
汉堡go4 小时前
python_chapter6
前端·数据库·python
wusp19944 小时前
v-model 和 :value 的深度解析
前端·javascript·vue.js
Code知行合壹4 小时前
Vue项目中SVG图标
前端·vue.js
SJLoveIT4 小时前
【安全研发】CSRF (跨站请求伪造) 深度复盘与防御体系
前端·安全·csrf
小二·4 小时前
Python Web 开发进阶实战:数字孪生平台 —— 在 Flask + Vue 中构建实时物理世界镜像
前端·vue.js·python