☰
Three.js入门指南:从零构建3D网页场景
2026/10/15 12:52:13 网站建设 项目流程

1. 初探3D世界的魅力

第一次接触three.js时,我被它构建的3D世界深深震撼。作为一个前端开发者,过去我们只能在2D平面上绘制图形,而three.js让我们能够在浏览器中创建和展示3D内容,这简直像是打开了新世界的大门。three.js是一个基于WebGL的JavaScript 3D库,它封装了WebGL的复杂API,让开发者能够更轻松地创建3D场景。

提示:three.js不是唯一的WebGL库,但它是最流行、文档最完善的一个,特别适合初学者入门3D开发。

在开始之前,我们需要了解几个核心概念:场景(Scene)、相机(Camera)和渲染器(Renderer)。这三个元素构成了three.js应用的基础框架。场景是所有3D对象的容器,相机决定了我们观看场景的视角,而渲染器则负责将场景和相机结合起来,最终呈现在网页上。

2. 搭建基础three.js环境

2.1 项目初始化

首先创建一个基本的HTML文件,引入three.js库。最简单的方式是通过CDN引入:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My first three.js app</title> <style> body { margin: 0; } canvas { display: block; } </style> </head> <body> <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script> <script src="js/main.js"></script> </body> </html>

2.2 创建基础场景

在main.js中,我们开始构建第一个3D场景:

// 创建场景 const scene = new THREE.Scene(); // 创建相机(透视相机) const camera = new THREE.PerspectiveCamera( 75, // 视野角度 window.innerWidth / window.innerHeight, // 宽高比 0.1, // 近截面 1000 // 远截面 ); // 创建渲染器 const renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement);

2.3 添加3D对象

现在场景还是空的,让我们添加一个立方体:

// 创建立方体几何体 const geometry = new THREE.BoxGeometry(1, 1, 1); // 创建材质(绿色基础材质) const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); // 创建网格对象(几何体+材质) const cube = new THREE.Mesh(geometry, material); // 将立方体添加到场景中 scene.add(cube); // 调整相机位置(否则我们会在立方体内部) camera.position.z = 5;

2.4 渲染场景

最后,我们需要创建一个动画循环来持续渲染场景:

function animate() { requestAnimationFrame(animate); // 旋转立方体 cube.rotation.x += 0.01; cube.rotation.y += 0.01; renderer.render(scene, camera); } animate();

3. 深入理解three.js核心概念

3.1 场景图结构

three.js使用场景图(Scene Graph)结构来组织3D对象。场景是一个树形结构,可以包含多个对象,这些对象又可以包含子对象。这种结构使得我们可以轻松地创建复杂的3D场景。

// 创建组 const group = new THREE.Group(); scene.add(group); // 向组中添加多个对象 const cube1 = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0xff0000 }) ); cube1.position.x = -2; const cube2 = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0x00ff00 }) ); const cube3 = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshBasicMaterial({ color: 0x0000ff }) ); cube3.position.x = 2; group.add(cube1, cube2, cube3); // 旋转整个组 group.rotation.y = Math.PI / 4;

3.2 相机类型与选择

three.js提供了几种不同的相机类型,最常用的是透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)。

透视相机模拟人眼看到的景象,远处的物体看起来更小:

const camera = new THREE.PerspectiveCamera( 45, // 视野角度(FOV) window.innerWidth / window.innerHeight, // 宽高比 1, // 近截面 1000 // 远截面 );

正交相机则保持物体大小不变,无论距离远近:

const aspect = window.innerWidth / window.innerHeight; const camera = new THREE.OrthographicCamera( -5 * aspect, // 左 5 * aspect, // 右 5, // 上 -5, // 下 1, // 近 1000 // 远 );

3.3 材质与光照

three.js提供了多种材质类型,从简单的MeshBasicMaterial(不受光照影响)到复杂的PBR材质(基于物理的渲染)。要看到光照效果,我们需要使用受光照影响的材质,如MeshPhongMaterial或MeshStandardMaterial。

// 添加光源 const light = new THREE.DirectionalLight(0xffffff, 1); light.position.set(1, 1, 1); scene.add(light); // 使用受光照影响的材质 const material = new THREE.MeshPhongMaterial({ color: 0x00ff00, shininess: 100 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube);

4. 高级特性与性能优化

4.1 纹理与贴图

为3D对象添加纹理可以大幅提升真实感。three.js支持多种纹理类型,包括基础颜色贴图、法线贴图、粗糙度贴图等。

// 加载纹理 const textureLoader = new THREE.TextureLoader(); const texture = textureLoader.load('textures/brick.jpg'); // 使用纹理材质 const material = new THREE.MeshStandardMaterial({ map: texture, // 颜色贴图 roughness: 0.8, metalness: 0.2 }); const cube = new THREE.Mesh(geometry, material); scene.add(cube);

4.2 3D模型加载

three.js支持加载多种3D模型格式,如glTF、OBJ、FBX等。glTF是官方推荐的格式,因为它专为Web设计,文件小且加载快。

import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'; const loader = new GLTFLoader(); loader.load( 'models/scene.gltf', function (gltf) { scene.add(gltf.scene); }, undefined, function (error) { console.error('加载模型出错:', error); } );

4.3 性能优化技巧

随着场景复杂度增加,性能优化变得尤为重要:

  1. 几何体合并:使用BufferGeometry和合并几何体减少绘制调用
  2. 细节层次(LOD):根据距离显示不同细节级别的模型
  3. 视锥体剔除:只渲染相机视野内的物体
  4. 使用实例化渲染:大量相同物体时使用InstancedMesh
  5. 合理使用阴影:阴影计算很耗性能,只对必要物体启用
// 实例化渲染示例 const geometry = new THREE.BoxGeometry(1, 1, 1); const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); const count = 1000; const mesh = new THREE.InstancedMesh(geometry, material, count); const matrix = new THREE.Matrix4(); for (let i = 0; i < count; i++) { matrix.setPosition( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 ); mesh.setMatrixAt(i, matrix); } scene.add(mesh);

5. 常见问题与解决方案

5.1 场景不显示或黑屏

  1. 检查相机位置是否合适(可能在物体内部)
  2. 确认物体是否添加到场景中
  3. 检查渲染循环是否正常运行
  4. 确认材质是否需要光源(MeshBasicMaterial不需要光)

5.2 性能问题

  1. 使用Chrome开发者工具的Performance面板分析性能瓶颈
  2. 减少实时阴影的使用
  3. 降低几何体复杂度或使用LOD
  4. 避免在动画循环中创建新对象

5.3 纹理加载问题

  1. 确保纹理路径正确
  2. 检查服务器是否允许跨域请求(本地文件可能需要启动本地服务器)
  3. 对于大纹理,考虑压缩或使用更小的分辨率

5.4 响应式设计

当窗口大小变化时,需要更新相机和渲染器:

window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });

6. 实战项目:创建一个3D产品展示

让我们把这些知识应用到一个实际项目中:创建一个可交互的3D产品展示。

6.1 场景设置

// 初始化场景、相机和渲染器 const scene = new THREE.Scene(); scene.background = new THREE.Color(0xf0f0f0); const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 2, 5); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; document.body.appendChild(renderer.domElement);

6.2 添加光照

// 环境光 const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); // 平行光(带阴影) const directionalLight = new THREE.DirectionalLight(0xffffff, 1); directionalLight.position.set(5, 10, 7); directionalLight.castShadow = true; directionalLight.shadow.mapSize.width = 2048; directionalLight.shadow.mapSize.height = 2048; scene.add(directionalLight);

6.3 加载产品模型

const loader = new GLTFLoader(); let product; loader.load( 'models/product.gltf', function (gltf) { product = gltf.scene; product.traverse(function (node) { if (node.isMesh) { node.castShadow = true; node.receiveShadow = true; } }); scene.add(product); }, undefined, function (error) { console.error('加载模型出错:', error); } );

6.4 添加交互控制

// 轨道控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; // 鼠标悬停高亮效果 const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); window.addEventListener('mousemove', (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, true); if (intersects.length > 0) { // 高亮处理 } });

6.5 动画循环

function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } animate();

7. 进阶学习路径

掌握了three.js基础后,你可以继续深入学习以下方向:

  1. 着色器编程:学习GLSL编写自定义着色器
  2. 物理引擎:集成Cannon.js或Ammo.js实现物理效果
  3. 后期处理:使用EffectComposer添加各种后期效果
  4. VR/AR:探索WebXR API创建虚拟/增强现实体验
  5. 性能优化:深入WebGL底层原理进行高级优化

three.js的官方文档是很好的学习资源,同时GitHub上有大量优秀的开源项目可以参考。在实际项目中,建议从简单功能开始,逐步增加复杂度,这样更容易定位和解决问题。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询