浏览器里的 3D 是怎么来的
网页里的三维画面,底层靠 WebGL 让显卡直接画三角形。但 WebGL 原生 API 非常底层,要自己管理缓冲区、着色器,上手成本很高。Three.js 把这些复杂度封装成了面向对象的接口,你不用碰着色器就能在网页里搭出旋转的立方体、可交互的三维模型、数据大屏的立体图表。
这篇不讲图形学理论,而是用最小可运行的代码,把 Three.js 的核心概念串一遍:场景里放什么、相机从哪看、怎么让画面动起来、怎么让用户拖拽旋转。
- 场景相机渲染器Three.js 三大基石。
- 几何体加材质决定物体的形状与外观。
- 灯光决定明暗与阴影。
- 渲染循环每一帧重绘,让画面动起来。
三个基石:场景、相机、渲染器
一个最小的 Three.js 程序必须有三样东西:Scene(场景)是所有物体的容器,Camera(相机)决定从哪个角度看,Renderer(渲染器)负责把画面画到 canvas 上。先把这三样建好,再往场景里加物体。
import * as THREE from 'three';
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75, innerWidth / innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
几何体与材质:搭出第一个物体
一个物体 = Geometry(几何体,决定形状) + Material(材质,决定颜色与光泽),两者组合成 Mesh(网格)后加进场景。比如一个发光的蓝色立方体,就是 BoxGeometry 配一个能被灯光照亮的材质。
const geo = new THREE.BoxGeometry(1, 1, 1);
const mat = new THREE.MeshStandardMaterial({ color: 0x3b82f6 });
const cube = new THREE.Mesh(geo, mat);
scene.add(cube);
灯光与阴影
用了 MeshStandardMaterial 这种真实感材质,就必须有灯光,否则物体是黑的。最常用的是环境光(照亮全局)加一盏平行光或点光(制造明暗)。想让物体投下阴影,还要在渲染器、灯光、物体上分别开启阴影开关,Three.js 会自动算出投影。
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const light = new THREE.PointLight(0xffffff, 1);
light.position.set(3, 3, 3);
scene.add(light);
动画循环与交互控制
3D 画面是靠每一帧都重新画一遍动起来的。用 requestAnimationFrame 做渲染循环,在每帧里改一点物体的位置或旋转,再渲染。想让用户用鼠标拖拽旋转视角,直接引入 OrbitControls 控制器一行接上即可。
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
性能与落地建议
3D 渲染很吃显卡,落地时要注意:几何体数量别太多,大量重复物体用实例化(InstancedMesh);纹理按尺寸压缩,别直接丢 4K 图;窗口缩放时同步更新相机宽高比和渲染尺寸;移动端适当降低分辨率和阴影质量。把数据可视化做成 3D 时,别为炫技而 3D,只有能帮用户理解空间关系时才值得上。
实战清单
落地清单:
- 先建好场景、相机、渲染器三大基石。
- 物体用几何体加材质组合,别只贴纯色。
- 真实感材质一定要配灯光,必要时开阴影。
- 用 requestAnimationFrame 渲染循环驱动动画。
- 需要拖拽旋转就上 OrbitControls。
- 关注性能,移动端降分辨率,重复物体用实例化。
Three.js 的价值,是让前端也能做出有空间感的可视化与交互体验。把场景、相机、渲染器这三个基石吃透,再配合几何体、材质、灯光和渲染循环,第一个会转、能拖拽的三维世界很快就能跑起来。