从零开始:使用Three.js构建WebGL 3D场景的完整指南

一、Three.js技术选型与基础环境搭建

Three.js作为主流的WebGL JavaScript库,通过封装底层图形API简化了3D开发流程。项目初始化建议采用模块化方案,可通过npm/pnpm安装最新稳定版本:

  1. pnpm add three

在Vue/React等现代框架中,建议将3D容器与业务逻辑分离。以下是一个典型的Vue单文件组件结构:

  1. <template>
  2. <div class="three-container">
  3. <canvas ref="canvasRef"></canvas>
  4. </div>
  5. </template>
  6. <script setup>
  7. import { onMounted, ref } from 'vue'
  8. import * as THREE from 'three'
  9. const canvasRef = ref(null)
  10. // 后续初始化代码将挂载在此
  11. </script>
  12. <style scoped>
  13. .three-container {
  14. position: fixed;
  15. top: 0;
  16. left: 0;
  17. width: 100vw;
  18. height: 100vh;
  19. overflow: hidden;
  20. }
  21. canvas {
  22. display: block;
  23. }
  24. </style>

这种结构确保了3D渲染区域全屏覆盖,同时避免页面布局冲突。

二、核心场景对象初始化

1. 场景系统构建

场景(Scene)是3D对象的容器,支持动态添加/移除元素。初始化时应考虑:

  1. const scene = new THREE.Scene()
  2. // 背景设置支持纯色和纹理两种方式
  3. scene.background = new THREE.Color(0xf0f0f0) // 纯色背景
  4. // 或使用纹理加载器
  5. const textureLoader = new THREE.TextureLoader()
  6. textureLoader.load('path/to/texture.jpg', (texture) => {
  7. texture.mapping = THREE.EquirectangularReflectionMapping
  8. scene.background = texture
  9. scene.environment = texture // 同时设置环境贴图
  10. })

2. 坐标系可视化

辅助工具对于调试至关重要,AxesHelper能直观显示三维坐标系:

  1. const axesHelper = new THREE.AxesHelper(1000) // 参数为坐标轴长度
  2. scene.add(axesHelper)

建议开发阶段保持显示,生产环境可通过条件判断移除。

三、光照系统设计

合理的光照配置能显著提升3D场景的真实感,推荐组合使用:

1. 平行光(DirectionalLight)

模拟太阳光等远距离光源:

  1. const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
  2. directionalLight.position.set(100, 60, 50)
  3. // 可添加阴影配置
  4. directionalLight.castShadow = true
  5. directionalLight.shadow.mapSize.width = 2048
  6. directionalLight.shadow.mapSize.height = 2048
  7. scene.add(directionalLight)

2. 环境光(AmbientLight)

补充场景基础亮度,避免纯阴影区域:

  1. const ambientLight = new THREE.AmbientLight(0xffffff, 0.4)
  2. scene.add(ambientLight)

3. 进阶方案

对于复杂场景,可组合使用点光源(PointLight)、聚光灯(SpotLight)和半球光(HemisphereLight),但需注意性能开销。

四、相机系统配置

相机决定了观察者的视角,常用透视相机配置示例:

  1. const camera = new THREE.PerspectiveCamera(
  2. 45, // 视野角度
  3. window.innerWidth / window.innerHeight, // 宽高比
  4. 1, // 近裁剪面
  5. 500 // 远裁剪面
  6. )
  7. camera.position.set(200, 180, 0)
  8. camera.lookAt(0, 0, 0) // 指向场景中心

响应式设计需监听窗口变化:

  1. window.addEventListener('resize', () => {
  2. camera.aspect = window.innerWidth / window.innerHeight
  3. camera.updateProjectionMatrix()
  4. renderer.setSize(window.innerWidth, window.innerHeight)
  5. })

五、WebGL渲染器优化

渲染器是最终图像输出的核心组件,关键配置项包括:

  1. const renderer = new THREE.WebGLRenderer({
  2. antialias: true, // 抗锯齿
  3. alpha: true, // 允许透明背景
  4. powerPreference: "high-performance" // 性能优先
  5. })
  6. renderer.setPixelRatio(window.devicePixelRatio) // 高DPI适配
  7. renderer.shadowMap.enabled = true // 启用阴影
  8. renderer.setSize(window.innerWidth, window.innerHeight)
  9. document.body.appendChild(renderer.domElement)

对于移动端,建议添加性能检测:

  1. if (!WebGL.isWebGLAvailable()) {
  2. const warning = WebGL.getWebGLErrorMessage()
  3. document.body.appendChild(warning)
  4. }

六、动画循环与交互控制

1. 基础动画循环

使用requestAnimationFrame实现流畅动画:

  1. function animate() {
  2. requestAnimationFrame(animate)
  3. // 更新场景对象状态
  4. renderer.render(scene, camera)
  5. }
  6. animate()

2. 轨道控制器集成

引入OrbitControls实现鼠标交互:

  1. import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
  2. const controls = new OrbitControls(camera, renderer.domElement)
  3. controls.enableDamping = true // 启用阻尼效果
  4. controls.dampingFactor = 0.05

需在动画循环中更新控制器:

  1. function animate() {
  2. requestAnimationFrame(animate)
  3. controls.update() // 必须调用
  4. renderer.render(scene, camera)
  5. }

七、性能优化实践

  1. 对象池技术:复用几何体和材质,避免频繁创建销毁
  2. 层级管理:使用THREE.Group组织相关对象
  3. LOD策略:根据距离切换不同精度模型
  4. WebGL状态管理:减少不必要的状态变更
  5. 工作线程:复杂计算可移至Web Worker

八、完整初始化流程示例

  1. // 初始化函数
  2. function initThreeScene() {
  3. // 1. 创建场景
  4. const scene = new THREE.Scene()
  5. scene.background = new THREE.Color(0x87CEEB)
  6. // 2. 添加辅助工具
  7. const axesHelper = new THREE.AxesHelper(100)
  8. scene.add(axesHelper)
  9. // 3. 配置光源
  10. const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
  11. directionalLight.position.set(100, 100, 50)
  12. scene.add(directionalLight)
  13. scene.add(new THREE.AmbientLight(0x404040))
  14. // 4. 设置相机
  15. const camera = new THREE.PerspectiveCamera(
  16. 45,
  17. window.innerWidth / window.innerHeight,
  18. 0.1,
  19. 1000
  20. )
  21. camera.position.set(5, 5, 5)
  22. camera.lookAt(0, 0, 0)
  23. // 5. 初始化渲染器
  24. const renderer = new THREE.WebGLRenderer({ antialias: true })
  25. renderer.setSize(window.innerWidth, window.innerHeight)
  26. renderer.setAnimationLoop(animate)
  27. document.body.appendChild(renderer.domElement)
  28. // 6. 添加控制器
  29. const controls = new OrbitControls(camera, renderer.domElement)
  30. controls.target.set(0, 0, 0)
  31. function animate() {
  32. controls.update()
  33. renderer.render(scene, camera)
  34. }
  35. return { scene, camera, renderer }
  36. }

通过以上系统化的实践指南,开发者能够构建出性能优良、交互流畅的WebGL 3D场景。后续可进一步探索模型加载、着色器编程、物理引擎集成等高级主题。