WebGL 让浏览器可以直接调用 GPU 渲染 3D 图形,而 Three.js 则将底层的复杂性封装成优雅的 JavaScript API。本文将从零开始,带你构建第一个 3D 场景。

一、WebGL 是什么?

WebGL(Web Graphics Library)是一种 JavaScript API,用于在浏览器中渲染高性能的 2D 和 3D 图形。它基于 OpenGL ES 2.0/3.0 标准,不需要任何插件即可运行。过去五年间,WebGPU 作为下一代标准也开始崭露头角,但 WebGL 仍然是最广泛兼容的选择。

用原生 WebGL 绘制一个三角形需要编写顶点着色器、片段着色器、设置缓冲区……几十行代码只为了画一个三角形。这就是 Three.js 存在的意义——它把这些称为"样板代码"的部分彻底封装起来。

二、Three.js 核心概念

Three.js 构建 3D 场景需要四个核心元素:

  • Scene(场景):所有物体的容器,相当于 3D 世界的舞台
  • Camera(相机):观察视角,常用透视相机(PerspectiveCamera)模拟人眼
  • Renderer(渲染器):将场景通过相机渲染到屏幕,使用 WebGLRenderer
  • Mesh(网格):几何体(Geometry)加上材质(Material)组成的可见物体
import * as THREE from 'three';

// 1. 创建场景
const scene = new THREE.Scene();

// 2. 创建透视相机 (视角75°, 宽高比, 近裁面0.1, 远裁面1000)
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;

// 3. 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// 4. 创建一个旋转的立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00fff7 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 5. 添加光照
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(0, 5, 5);
scene.add(light);

// 6. 动画循环
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

三、进阶:粒子系统和着色器

Three.js 的高级功能可以让效果更加惊艳:

粒子系统(Points)

使用 PointsMaterial 可以创建数千个粒子,常用于星空、烟雾等效果。配合鼠标交互,可以产生本文网站主页那样的动态粒子网络。

自定义着色器(Shader)

通过编写自定义 GLSL 着色器,可以实现超出内置材质的视觉效果——如赛博朋克风格的故障闪烁、流光扫描线等。

// 一个简单的自定义着色器材质
const customMaterial = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0 },
    uColor: { value: new THREE.Color(0x00fff7) }
  },
  vertexShader: 
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  ,
  fragmentShader: 
    uniform vec3 uColor;
    uniform float uTime;
    varying vec2 vUv;
    void main() {
      float glow = sin(vUv.x * 20.0 + uTime) * 0.5 + 0.5;
      gl_FragColor = vec4(uColor * glow, 1.0);
    }
  
});

四、性能优化建议

  • 合并几何体:使用 BufferGeometryUtils.mergeGeometries 减少 draw call
  • 使用 LOD(细节层次):远处物体使用低精度模型
  • 纹理压缩:使用 KTX2 或 Basis 压缩格式
  • 限制帧率:非交互场景可以锁 30fps 降低功耗
  • InstancedMesh:大量相同物体使用实例化渲染

五、推荐学习资源


本文是 Xiao Ming 博客系列文章之一。下一篇将探讨零信任架构在企业中的应用。