{T}

Three.js 简介与安装

Three.js 简介

Three.js 是一个基于 WebGL 的 JavaScript 3D 库,由 Ricardo Cabello(Mr.doob)于 2010 年创建并开源。它将 WebGL 的底层 API 封装成更易使用的高级接口,让开发者能够在网页上轻松创建和展示 3D 内容。

什么是 WebGL?

WebGL(Web Graphics Library)是一种在浏览器中无需插件即可渲染 3D 图形的 JavaScript API。它基于 OpenGL ES 2.0,允许在 HTML5 <canvas> 元素中使用 GPU 加速渲染。

WebGL 的优势:

  • 硬件加速:直接使用 GPU 进行图形渲染,性能强劲
  • 跨平台:支持所有现代浏览器,无需安装插件
  • 开放标准:由 Khronos Group 维护,是一个开放的标准

WebGL 的挑战:

  • 学习曲线陡峭:需要了解图形学、着色器编程等专业知识
  • 代码量大:即使是简单的场景也需要大量样板代码
  • 调试困难:底层 API 错误处理复杂

Three.js 的出现就是为了解决这些问题。

Three.js 的优势

1. 降低学习门槛

javascript
// WebGL 原生代码(简化版)
const canvas = document.getElementById('canvas')
const gl = canvas.getContext('webgl')

// 编写顶点着色器
const vertexShaderSource = `
  attribute vec4 a_position;
  void main() {
    gl_Position = a_position;
  }
`

// 编写片元着色器
const fragmentShaderSource = `
  precision mediump float;
  void main() {
    gl_FragColor = vec4(1, 0, 0.5, 1);
  }
`

// 创建着色器程序...(需要几十行代码)
javascript
// Three.js 代码
const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height)
const renderer = new THREE.WebGLRenderer()
renderer.render(scene, camera)

2. 丰富的功能

  • 几何体:内置多种几何体(立方体、球体、圆柱体等)
  • 材质:多种材质类型(基础材质、PBR 材质、着色器材质等)
  • 光照:支持多种光源类型和实时阴影
  • 动画:关键帧动画、骨骼动画、变形动画
  • 模型加载:支持 GLTF、OBJ、FBX 等格式
  • 后处理:景深、辉光、抗锯齿等后期效果
  • 交互:射线拾取、控制器等

3. 活跃的社区

  • GitHub Stars:超过 90k+
  • 贡献者:1000+ 开发者
  • 文档完善:官方文档、示例丰富
  • 社区活跃:论坛、Discord、Stack Overflow 都有活跃讨论

Three.js 能做什么?

电商产品展示

  • 3D 产品旋转展示
  • 产品配置器(颜色、材质选择)
  • 虚拟试穿、试戴
  • 360° 全景展示

游戏开发

  • 休闲网页游戏
  • 3D 小游戏
  • 游戏场景与角色展示
  • 游戏原型开发

数据可视化

  • 3D 图表(柱状图、饼图等)
  • 地理信息系统(GIS)
  • 科学数据可视化
  • 实时数据监控

建筑与设计

  • 建筑模型展示
  • 室内设计预览
  • VR 看房
  • 城市规划展示

教育培训

  • 3D 教学模型
  • 虚拟实验室
  • 交互式学习内容
  • 医学解剖模型

艺术与创意

  • 数字艺术作品
  • 交互式装置
  • 创意网站
  • 音乐可视化

Three.js 架构

核心组件

Three.js 的核心架构包含以下主要组件:

code
Scene(场景)
  ├── Object3D(3D 对象)
  │   ├── Mesh(网格)= Geometry + Material
  │   ├── Light(光源)
  │   ├── Camera(相机)
  │   └── Group(组)
  └── ...

1. Scene(场景)

场景是所有 3D 对象的容器,类似于现实世界的"舞台"。

javascript
const scene = new THREE.Scene()
scene.background = new THREE.Color(0xffffff) // 设置背景色

2. Camera(相机)

相机决定了观察者看场景的视角。Three.js 提供多种相机类型:

相机类型对比

相机类型说明应用场景
PerspectiveCamera透视相机,模拟人眼视角大多数3D场景
OrthographicCamera正交相机,无透视效果CAD、2.5D游戏
CubeCamera立方体相机,6个方向环境映射、反射
StereoCamera立体相机,双视角VR/AR应用

PerspectiveCamera 参数详解

javascript
const camera = new THREE.PerspectiveCamera(
  75, // fov: 视野角度(Field of View),0-180度
  window.innerWidth / window.innerHeight, // aspect: 宽高比
  0.1, // near: 近裁剪面,距离相机多近开始渲染
  1000 // far: 远裁剪面,距离相机多远停止渲染
)
camera.position.set(0, 0, 5) // 设置相机位置

// 参数说明:
// - fov: 值越大,视野越广(类似广角镜头);值越小,视野越窄(类似长焦镜头)
// - aspect: 必须与画布宽高比一致,否则图像会变形
// - near/far: 不在此范围内的对象不会被渲染,合理设置可优化性能

OrthographicCamera 正交相机

javascript
const aspect = window.innerWidth / window.innerHeight
const frustumSize = 5 // 视锥体大小

const camera = new THREE.OrthographicCamera(
  frustumSize * aspect / -2,  // left
  frustumSize * aspect / 2,   // right
  frustumSize / 2,            // top
  frustumSize / -2,           // bottom
  0.1,                        // near
  1000                        // far
)

相机常用方法

方法说明示例
lookAt(x, y, z)设置相机朝向camera.lookAt(0, 0, 0)
updateProjectionMatrix()更新投影矩阵camera.updateProjectionMatrix()
getWorldDirection()获取相机方向camera.getWorldDirection()
updateWorldMatrix()更新世界矩阵camera.updateWorldMatrix()

3. Renderer(渲染器)

渲染器负责将场景绘制到屏幕上。Three.js 提供多种渲染器,WebGLRenderer 是最常用的。

渲染器类型对比

渲染器说明性能兼容性
WebGLRendererWebGL 渲染器现代浏览器
WebGL1RendererWebGL 1.0 渲染器兼容性更好
WebGPURendererWebGPU 渲染器最高新特性,有限支持

WebGLRenderer 配置参数详解

javascript
const renderer = new THREE.WebGLRenderer({
  // 基础配置
  canvas: undefined,           // 指定 canvas 元素,默认自动创建
  context: undefined,          // 指定 WebGL 上下文
  alpha: false,               // 是否支持透明背景
  premultipliedAlpha: true,   // 是否预乘 alpha 值
  antialias: false,           // 是否开启抗锯齿
  stencil: true,              // 是否使用模板缓冲区
  
  // 性能配置
  powerPreference: 'default', // GPU 电源管理: 'default' | 'high-performance' | 'low-power'
  precision: 'highp',         // 着色器精度: 'highp' | 'mediump' | 'lowp'
  
  // 高级配置
  logarithmicDepthBuffer: false, // 对数深度缓冲区(大场景优化)
  preserveDrawingBuffer: false,  // 保留绘图缓冲区(截图需要)
  
  // 后处理相关
  depth: true,                // 深度缓冲区
  failIfMajorPerformanceCaveat: false // 性能警告检测
})

// 常用配置方法
renderer.setSize(width, height)                    // 设置渲染尺寸
renderer.setPixelRatio(window.devicePixelRatio)   // 设置像素比(高清屏适配)
renderer.setClearColor(0x000000, 1)               // 设置背景色
renderer.setClearAlpha(0)                         // 设置背景透明度
renderer.setScissor(x, y, width, height)          // 设置裁剪区域
renderer.setViewport(x, y, width, height)         // 设置视口

// 阴影配置
renderer.shadowMap.enabled = true                 // 开启阴影
renderer.shadowMap.type = THREE.PCFSoftShadowMap // 阴影类型

// 色彩管理
renderer.outputColorSpace = THREE.SRGBColorSpace  // 输出色彩空间
renderer.toneMapping = THREE.ACESFilmicToneMapping // 色调映射
renderer.toneMappingExposure = 1.0                // 曝光度

document.body.appendChild(renderer.domElement)

常用方法

方法说明示例
render(scene, camera)渲染场景renderer.render(scene, camera)
clear()清除缓冲区renderer.clear()
dispose()释放资源renderer.dispose()
forceContextLoss()强制丢失上下文renderer.forceContextLoss()

4. Mesh(网格)

网格是场景中可见的 3D 对象,由几何体和材质组成。

javascript
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 })
const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)

5. Light(光源)

光源为场景提供照明,影响材质的渲染效果。

javascript
const light = new THREE.DirectionalLight(0xffffff, 1)
light.position.set(5, 5, 5)
scene.add(light)

渲染流程

Three.js 的渲染流程遵循以下步骤:

code
初始化阶段:
1. 创建场景
2. 创建相机
3. 创建渲染器
4. 创建几何体和材质
5. 创建网格并添加到场景
6. 创建光源

渲染循环:
1. 更新场景中的对象(位置、旋转等)
2. 渲染器调用 render() 方法
3. 将 3D 场景投影到 2D 画布
4. 显示在屏幕上

核心功能模块

Three.js 提供了丰富的功能模块,以下是最常用的核心模块概览:

几何体模块(Geometries)

几何体类型说明主要参数
BoxGeometry立方体width, height, depth
SphereGeometry球体radius, widthSegments, heightSegments
CylinderGeometry圆柱体radiusTop, radiusBottom, height
PlaneGeometry平面width, height
TorusGeometry圆环radius, tube, radialSegments
ConeGeometry圆锥radius, height, radialSegments
javascript
// 创建不同几何体示例
const box = new THREE.BoxGeometry(1, 1, 1)
const sphere = new THREE.SphereGeometry(0.5, 32, 32)
const cylinder = new THREE.CylinderGeometry(0.5, 0.5, 2, 32)

材质模块(Materials)

材质类型说明是否受光照影响
MeshBasicMaterial基础材质,不受光照影响
MeshStandardMaterialPBR 标准材质
MeshPhongMaterialPhong 光照材质
MeshLambertMaterialLambert 光照材质
MeshNormalMaterial法线材质(调试用)
ShaderMaterial自定义着色器材质可选
javascript
// 材质创建示例
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
const standardMaterial = new THREE.MeshStandardMaterial({
  color: 0x00ff00,
  metalness: 0.5,    // 金属度 (0-1)
  roughness: 0.5     // 粗糙度 (0-1)
})

光源模块(Lights)

光源类型说明性能消耗
AmbientLight环境光,均匀照亮场景
DirectionalLight平行光,模拟太阳光
PointLight点光源,向所有方向发散
SpotLight聚光灯,锥形光束
HemisphereLight半球光,天空和地面两种颜色
javascript
// 光源创建示例
const ambientLight = new THREE.AmbientLight(0x404040, 0.5)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
directionalLight.position.set(5, 5, 5)
directionalLight.castShadow = true // 开启阴影

加载器模块(Loaders)

Three.js 提供了多种资源加载器:

加载器支持格式说明
GLTFLoader.gltf, .glb推荐,支持动画、材质、骨骼
OBJLoader.obj通用3D格式
FBXLoader.fbx支持动画
STLLoader.stl3D打印格式
TextureLoaderjpg, png, gif纹理图片加载
javascript
// 加载模型示例
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

const loader = new GLTFLoader()
loader.load(
  'model.glb',
  (gltf) => {
    scene.add(gltf.scene)
  },
  (progress) => {
    console.log('Loading:', (progress.loaded / progress.total * 100) + '%')
  },
  (error) => {
    console.error('Error:', error)
  }
)

控制器模块(Controls)

控制器说明主要用途
OrbitControls轨道控制器鼠标旋转、缩放、平移
FlyControls飞行控制器第一人称飞行
FirstPersonControls第一人称控制器类似FPS游戏
TrackballControls轨迹球控制器自由旋转视角
javascript
// OrbitControls 使用示例
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true      // 开启阻尼效果
controls.dampingFactor = 0.05      // 阻尼系数
controls.minDistance = 1           // 最小缩放距离
controls.maxDistance = 100         // 最大缩放距离
controls.maxPolarAngle = Math.PI / 2  // 限制垂直旋转角度

安装方式

Three.js 提供多种安装方式,你可以根据项目需求选择合适的方式。

1. NPM 安装(推荐)

适用于现代前端项目,支持模块化打包。

安装

bash
npm install three

使用

javascript
// 方式一:全局导入
import * as THREE from 'three'

const scene = new THREE.Scene()
const camera = new THREE.PerspectiveCamera(75, width / height)
const renderer = new THREE.WebGLRenderer()

// 方式二:按需导入(推荐)
import { Scene, PerspectiveCamera, WebGLRenderer } from 'three'

const scene = new Scene()
const camera = new PerspectiveCamera(75, width / height)
const renderer = new WebGLRenderer()

导入示例和插件

javascript
// 导入 OrbitControls 控制器
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

// 导入 GLTFLoader 加载器
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'

// 导入后处理效果
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'

TypeScript 支持

Three.js 自带 TypeScript 类型定义,无需额外安装。

typescript
import * as THREE from 'three'

const scene: THREE.Scene = new THREE.Scene()
const camera: THREE.PerspectiveCamera = new THREE.PerspectiveCamera(
  75,
  width / height
)

2. CDN 引入

适用于快速原型开发或简单项目。

使用最新版本

html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Three.js CDN</title>
  <style>
    body { margin: 0; }
    canvas { display: block; }
  </style>
</head>
<body>
  <script src="https://cdn.jsdelivr.net/npm/three@latest/build/three.min.js"></script>
  <script>
    const scene = new THREE.Scene()
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight)
    const renderer = new THREE.WebGLRenderer()
    
    renderer.setSize(window.innerWidth, window.innerHeight)
    document.body.appendChild(renderer.domElement)
    
    // ...其他代码
  </script>
</body>
</html>

使用特定版本

html
<!-- 指定版本号 -->
<script src="https://cdn.jsdelivr.net/npm/three@0.150.0/build/three.min.js"></script>

<!-- 或者使用 unpkg -->
<script src="https://unpkg.com/three@0.150.0/build/three.min.js"></script>

<!-- 或者使用 cdnjs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r150/three.min.js"></script>

CDN 导入模块

html
<!-- 主文件 -->
<script src="https://cdn.jsdelivr.net/npm/three@latest/build/three.min.js"></script>

<!-- OrbitControls -->
<script src="https://cdn.jsdelivr.net/npm/three@latest/examples/js/controls/OrbitControls.js"></script>

<!-- GLTFLoader -->
<script src="https://cdn.jsdelivr.net/npm/three@latest/examples/js/loaders/GLTFLoader.js"></script>

<script>
  // 使用
  const controls = new THREE.OrbitControls(camera, renderer.domElement)
  const loader = new THREE.GLTFLoader()
</script>

3. 直接下载

适用于离线开发或需要修改源码的场景。

下载方式

  1. GitHub Releases

    访问 Three.js Releases,下载最新版本的源码。

  2. 克隆仓库

    bash
    git clone https://github.com/mrdoob/three.js.git

使用本地文件

html
<script src="./path/to/three.js"></script>
<!-- 或使用压缩版 -->
<script src="./path/to/three.min.js"></script>

4. 在线编辑器

适用于学习和快速测试。

版本选择

版本命名规则

Three.js 遵循语义化版本控制:

  • 主版本号:重大更新,可能包含不兼容的 API 变更
  • 次版本号:新功能添加,向后兼容
  • 修订号:Bug 修复,向后兼容

例如:r150 表示第 150 个版本

如何选择版本?

开发环境

bash
# 使用最新稳定版
npm install three

# 使用特定版本
npm install three@0.150.0

# 使用最新开发版
npm install three@latest

生产环境

bash
# 锁定版本号
npm install three@0.150.0

# 或在 package.json 中锁定
{
  "dependencies": {
    "three": "0.150.0"
  }
}

版本迁移

Three.js 版本更新较快,迁移时需要注意:

  1. 查看更新日志: https://github.com/mrdoob/three.js/releases
  2. 关注废弃 API: 查看控制台的废弃警告
  3. 测试兼容性: 升级后全面测试项目

浏览器支持

支持的浏览器

Three.js 支持所有支持 WebGL 的现代浏览器:

浏览器最低版本推荐版本
Chrome9+最新版
Firefox4+最新版
Safari5.1+最新版
Edge12+最新版
Opera12+最新版

移动端支持

  • iOS Safari 8+
  • Android Chrome 60+
  • Android Firefox 60+

WebGL 支持检测

javascript
// 检测 WebGL 支持
function isWebGLAvailable() {
  try {
    const canvas = document.createElement('canvas')
    return !!(
      window.WebGLRenderingContext &&
      (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))
    )
  } catch (e) {
    return false
  }
}

if (!isWebGLAvailable()) {
  alert('您的浏览器不支持 WebGL,请升级浏览器')
}

或者使用 Three.js 提供的检测工具:

javascript
import { WEBGL } from 'three/examples/jsm/WebGL.js'

if (WEBGL.isWebGLAvailable()) {
  // WebGL 支持
} else {
  const warning = WEBGL.getWebGLErrorMessage()
  document.body.appendChild(warning)
}

项目依赖

核心依赖

Three.js 本身没有外部依赖,是一个独立的库。

开发依赖(推荐)

json
{
  "devDependencies": {
    "vite": "^4.0.0", // 构建工具
    "typescript": "^5.0.0", // TypeScript 支持
    "@types/three": "^0.150.0" // Three.js 类型定义
  }
}

可选依赖

json
{
  "dependencies": {
    // 物理引擎
    "cannon-es": "^0.20.0",
    "ammo.js": "^0.0.10",
    
    // 动画库
    "gsap": "^3.12.0",
    
    // 工具库
    "lodash": "^4.17.21"
  }
}

最佳实践

1. 使用模块化导入

javascript
// ❌ 不推荐:全局导入
import * as THREE from 'three'

// ✅ 推荐:按需导入
import { Scene, PerspectiveCamera, WebGLRenderer } from 'three'

2. 锁定版本号

json
{
  "dependencies": {
    "three": "0.150.0" // 锁定具体版本
  }
}

3. 使用构建工具

推荐使用 Vite、Webpack 等现代构建工具:

javascript
// vite.config.js
export default {
  optimizeDeps: {
    include: ['three']
  }
}

4. 按需加载插件

javascript
// ✅ 推荐:按需导入插件
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

// ❌ 不推荐:全量导入
import 'three/examples/js/controls/OrbitControls'

5. 资源释放

避免内存泄漏,及时释放不再使用的资源:

javascript
// 释放几何体
geometry.dispose()

// 释放材质
material.dispose()

// 释放纹理
texture.dispose()

// 释放渲染器
renderer.dispose()

// 从场景移除对象
scene.remove(mesh)

6. 性能优化建议

javascript
// 限制像素比,避免高清屏性能问题
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

// 使用 requestAnimationFrame 控制渲染循环
function animate() {
  requestAnimationFrame(animate)
  renderer.render(scene, camera)
}

// 合并几何体减少 draw calls
const mergedGeometry = BufferGeometryUtils.mergeGeometries(geometries)

// 使用 InstancedMesh 渲染大量相同对象
const instancedMesh = new THREE.InstancedMesh(geometry, material, count)

// 按需渲染(非动画场景)
let needsUpdate = true
function render() {
  if (needsUpdate) {
    renderer.render(scene, camera)
    needsUpdate = false
  }
}

API 接口参考

Scene(场景)

属性/方法类型说明
backgroundColor/Texture场景背景色或背景贴图
environmentTexture环境贴图(影响材质反射)
fogFog场景雾效果
childrenArray场景中所有子对象
add(object)Method添加对象到场景
remove(object)Method从场景移除对象
traverse(callback)Method遍历场景树

Object3D(3D对象基类)

属性/方法类型说明
positionVector3对象位置 (x, y, z)
rotationEuler对象旋转(欧拉角)
scaleVector3对象缩放
visibleBoolean是否可见
castShadowBoolean是否投射阴影
receiveShadowBoolean是否接收阴影
userDataObject自定义数据
translateX/Y/Z(distance)Method沿轴移动
rotateX/Y/Z(angle)Method绕轴旋转
lookAt(target)Method朝向目标

Mesh(网格)

javascript
const mesh = new THREE.Mesh(geometry, material)

// 常用属性
mesh.position.set(0, 0, 0)      // 位置
mesh.rotation.set(0, 0, 0)      // 旋转
mesh.scale.set(1, 1, 1)         // 缩放
mesh.visible = true             // 可见性
mesh.castShadow = true          // 投射阴影
mesh.receiveShadow = true       // 接收阴影

BufferGeometry(缓冲几何体)

属性/方法说明
attributes.position顶点位置数据
attributes.normal顶点法线数据
attributes.uvUV 坐标数据
attributes.color顶点颜色数据
index索引数据
boundingBox包围盒(需调用 computeBoundingBox)
boundingSphere包围球(需调用 computeBoundingSphere)
computeVertexNormals()计算顶点法线
dispose()释放资源

Material(材质基类)

属性类型说明
colorColor材质颜色
opacityNumber透明度 (0-1)
transparentBoolean是否透明
visibleBoolean是否可见
sideConstant渲染面:FrontSide/BackSide/DoubleSide
wireframeBoolean线框模式
mapTexture颜色贴图
normalMapTexture法线贴图
aoMapTexture环境遮蔽贴图

Texture(纹理)

javascript
const texture = new THREE.TextureLoader().load('texture.jpg')

// 常用属性
texture.wrapS = THREE.RepeatWrapping    // 水平重复
texture.wrapT = THREE.RepeatWrapping    // 垂直重复
texture.repeat.set(2, 2)                 // 重复次数
texture.offset.set(0.5, 0.5)             // 偏移
texture.rotation = Math.PI / 4           // 旋转
texture.center.set(0.5, 0.5)             // 旋转中心
texture.encoding = THREE.sRGBEncoding    // 编码方式

// 纹理过滤
texture.minFilter = THREE.LinearMipmapLinearFilter  // 缩小过滤
texture.magFilter = THREE.LinearFilter              // 放大过滤

常见问题

Q1: NPM 安装和 CDN 引入有什么区别?

A:

  • NPM 安装:适合现代前端项目,支持模块化、Tree-shaking、TypeScript,打包后体积更小
  • CDN 引入:适合快速原型开发,无需构建工具,但无法按需加载

Q2: 如何选择 Three.js 版本?

A:

  • 学习阶段:使用最新版本,体验最新特性
  • 生产环境:使用稳定版本,锁定版本号
  • 长期项目:定期更新,关注更新日志

Q3: Three.js 需要什么基础?

A:

  • 必需:JavaScript 基础、HTML/CSS
  • 推荐:ES6+ 语法、模块化开发
  • 进阶:WebGL 基础、图形学概念、GLSL 着色器

Q4: 如何调试 Three.js 应用?

A:

  • 使用浏览器开发者工具
  • 安装 Three.js DevTools 扩展
  • 使用 console.log 查看对象属性
  • 使用 Stats.js 监控性能

Q5: Three.js 支持哪些 3D 模型格式?

A:

  • 推荐: GLTF/GLB(官方推荐格式)
  • 支持: OBJ、FBX、STL、Collada、3DS 等
  • 详见: 模型加载 章节

Q6: 如何解决场景黑屏问题?

A: 场景黑屏常见原因及解决方案:

javascript
// 1. 检查相机位置
console.log(camera.position)

// 2. 确保对象在视锥体内
const box = new THREE.Box3().setFromObject(mesh)
console.log(box) // 查看包围盒

// 3. 检查材质是否需要光照
// MeshStandardMaterial 和 MeshPhongMaterial 需要光源
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) // 不受光照影响

// 4. 确保调用了 render()
renderer.render(scene, camera)

// 5. 检查渲染器尺寸
console.log(renderer.getSize(new THREE.Vector2()))

Q7: 如何优化 Three.js 性能?

A:

javascript
// 1. 减少几何体面数
const geometry = new THREE.SphereGeometry(1, 16, 16) // 较少分段

// 2. 合并几何体
import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils'
const mergedGeometry = BufferGeometryUtils.mergeGeometries([geo1, geo2])

// 3. 使用 InstancedMesh
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000)

// 4. 限制像素比
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))

// 5. 关闭抗锯齿(移动端)
const renderer = new THREE.WebGLRenderer({ antialias: false })

// 6. 使用 LOD(细节层次)
const lod = new THREE.LOD()
lod.addLevel(highPolyMesh, 10)
lod.addLevel(mediumPolyMesh, 20)
lod.addLevel(lowPolyMesh, 30)

// 7. 视锥体剔除(默认开启)
// 确保对象的 frustumCulled 属性为 true
mesh.frustumCulled = true

Q8: 如何处理响应式布局?

A:

javascript
// 监听窗口大小变化
window.addEventListener('resize', () => {
  const width = window.innerWidth
  const height = window.innerHeight
  
  // 更新相机宽高比
  camera.aspect = width / height
  camera.updateProjectionMatrix()
  
  // 更新渲染器尺寸
  renderer.setSize(width, height)
})

// 使用 ResizeObserver 监听容器大小变化(推荐)
const container = document.getElementById('container')
const resizeObserver = new ResizeObserver((entries) => {
  const { width, height } = entries[0].contentRect
  camera.aspect = width / height
  camera.updateProjectionMatrix()
  renderer.setSize(width, height)
})
resizeObserver.observe(container)

Q9: 如何实现对象动画?

A:

javascript
// 方式1:直接修改属性
function animate() {
  requestAnimationFrame(animate)
  mesh.rotation.y += 0.01
  renderer.render(scene, camera)
}

// 方式2:使用三角函数
const clock = new THREE.Clock()
function animate() {
  requestAnimationFrame(animate)
  const time = clock.getElapsedTime()
  mesh.position.y = Math.sin(time) * 2
  renderer.render(scene, camera)
}

// 方式3:使用 GSAP 动画库
import gsap from 'gsap'
gsap.to(mesh.position, {
  duration: 2,
  x: 5,
  y: 3,
  ease: 'power2.inOut'
})

// 方式4:使用 Three.js 动画系统
import { AnimationMixer } from 'three'
const mixer = new AnimationMixer(model)
const action = mixer.clipAction(animationClip)
action.play()

function animate() {
  requestAnimationFrame(animate)
  mixer.update(deltaTime)
  renderer.render(scene, camera)
}

Q10: 如何实现点击选中对象?

A:

javascript
import { Raycaster, Vector2 } from 'three'

const raycaster = new Raycaster()
const mouse = new Vector2()

window.addEventListener('click', (event) => {
  // 计算鼠标归一化坐标
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
  
  // 设置射线
  raycaster.setFromCamera(mouse, camera)
  
  // 检测相交对象
  const intersects = raycaster.intersectObjects(scene.children)
  
  if (intersects.length > 0) {
    const selected = intersects[0].object
    console.log('选中对象:', selected)
    
    // 高亮显示
    selected.material.emissive.setHex(0xff0000)
  }
})

相关链接

下一步

现在你已经了解了 Three.js 的基本概念和安装方法,接下来可以:

  1. 快速入门 - 创建你的第一个 3D 场景
  2. 开发环境配置 - 配置完整的开发环境
  3. 场景系统 - 深入理解 Three.js 核心概念