引言

三维计算机图形和二维计算机图形的不同之处在于计算机存储了几何数据的三维表示,其用于计算和绘制最终的二维图像。——《3D computer graphics》

随着 WebGL 标准的快速推进,越来越多团队尝试在浏览器上推出可交互的 3D 作品。相较于二维场景,它更能为用户带来真实和沉浸的体验。

然而 OpenGL 和 WebGL(基于 OpenGL ES) 都比较复杂,Three.js 则更适合初学者。本文将分享一些 Three.js 的基础知识,希望能让你能有所收获。

当然,分享的知识点也不会面面俱到,想更深入的学习,还得靠大家多看多实践。另外,为了控制篇幅,本文更倾向于通过案例中的代码和注释进行阐述一些细节。

若想系统学习,笔者认为看书是一个不错的选择:

Three.js开发指南(原书第2版)
Three.js开发指南(原书第2版) 购买链接>>

尽管由于 Three.js 的不断迭代,书本上的某些 API 已改变(或弃用),甚至难免还有一些错误,但这些并不影响整体的阅读。

Canvas 2D

如引言中说道,3D 图像在计算机中最终以 2D 图像呈现。因此,渲染模式只是作为一个载体。下面我们用 JavaScript(无依赖) 在 Canvas 2D 渲染一个在正视图/透视图中的立方体。

正视图中的立方体:

See the Pen 3D Orthographic View by SitePoint (@SitePoint) on CodePen.

透视图中的立方体:

See the Pen 3D Perspective View by SitePoint (@SitePoint) on CodePen.

若要将三维图形渲染在二维屏幕上,需要将三维坐标以某种方式转为二维坐标。但对于更复杂的场景,大量坐标的转换和阴影等耗性能操作无疑需要 Web 提供更高效的渲染模式。

另外,想了解上述两个案例的实现原理,可查看译文:《用 JavaScript 构建一个3D引擎》

WebGL

WebGL(Web Graphics Library)在 GPU 中运行。因此需要使用能够在 GPU 上运行的代码。这样的代码需要提供成对的方法(其中一个叫顶点着色器, 另一个叫片段着色器),并且使用一种类 C/C++ 的强类型语言 GLSL(OpenGL Shading Language)。 每一对方法组合起来称为一个 program(着色程序)。

顶点着色器的作用是计算顶点的位置。根据计算出的一系列顶点位置,WebGL 可以对点、线和三角形在内的一些图元进行光栅化处理。当对这些图元进行光栅化处理时需要使用片段着色器方法。片段着色器的作用是计算出当前绘制图元中每个像素的颜色值。

用 WebGL 绘制一个三角形:

See the Pen WebGL - Fundamentals by Jc (@JChehe) on CodePen.

查看上述案例的代码实现后,我们发现绘制一个看似简单的三角形其实并不简单,它需要我们学习更多额外的知识。

因此,对于刚入门的开发者来说,直接使用 WebGL 来绘制并拼装出几何体是不现实的。但我们可以在了解 WebGL 的基础知识后,再通过 Three.js 这类封装后的库来现实我们的需求。

Three.js

打开 Three.js 官方文档 并阅览左侧的目录,发现该文档对初学者并不友好。但相对于其他资料,它提供了最新的 API 说明,尽管有些描述并不详细(甚至需要在懂 WebGL 等其他知识的前提下,才能了解某个术语的意思)。下面提供两个 Three.js 的相关图片资料,希望它们能让你对 Three.js 有个整体的认识:

Three.js 文档的结构
Three.js 文档结构:图片来自>>

Three.js 核心对象结构和基本的渲染流程
Three.js 核心对象结构和基本的渲染流程:图片来自>>

Three.js 的基本要素

我们先通过一个简单但完整的案例来了解 Three.js 的基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 引入 Three.js 库
<script src="https://unpkg.com/three"></script>

function init () {
// 获取浏览器窗口的宽高,后续会用
var width = window.innerWidth
var height = window.innerHeight

// 创建一个场景
var scene = new THREE.Scene()

// 创建一个具有透视效果的摄像机
var camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 800)

// 设置摄像机位置,并将其朝向场景中心
camera.position.x = 10
camera.position.y = 10
camera.position.z = 30
camera.lookAt(scene.position)

// 创建一个 WebGL 渲染器,Three.js 还提供 <canvas>, <svg>, CSS3D 渲染器。
var renderer = new THREE.WebGLRenderer()

   // 设置渲染器的清除颜色(即背景色)和尺寸。
   // 若想用 body 作为背景,则可以不设置 clearColor,然后在创建渲染器时设置 alpha: true,即 new THREE.WebGLRenderer({ alpha: true })
   renderer.setClearColor(0xffffff)
renderer.setSize(width, height)

// 创建一个长宽高均为 4 个单位长度的立方体(几何体)
var cubeGeometry = new THREE.BoxGeometry(4, 4, 4)

// 创建材质(该材质不受光源影响)
var cubeMaterial = new THREE.MeshBasicMaterial({