jk's notes
  • 手册

手册

1. 安装 (installation)

1.1 项目结构

一个 Three.js 项目至少需要一个 html 文件, 用于展示页面骨架; 一个 js 文件, 用于编写 three.js 代码. 下面是一个参考, 不是必须, 但作为文档, 可以统一使用.

实际上使用 vite 的空模板就可以. 而且官网也是基于 vite, 模块化的编码, 以及 TypeScript 有利于使用与学习 three.js.

需要注意一下, 文档中 将 页面的 body 标签的 margin 样式设置为 0, 这是为了更好的全屏显示.

按照文档有几个必要的文件:

  • index.html
  • main.js
  • public/ 这个文件夹常被称为静态资源文件夹, 一些纹理, 模型, 音视频数据会放在这里.

下面是构建/运行, 可以使用 CDN, 也可以使用包管理工具.

1.2 使用 npm 与构建工具

开发

  1. 首先安装 node 环境.

  2. 安装 three.js, vite. 使用 vite 可以使用 ES Module 模式来导入模块.

    npm i three
    npm i vite -D
    
  3. 执行 npx vite 来运行开发环境

  4. 通过浏览器访问.

生产

使用 vite build 来构建, 会生成 dist 文件夹, 来存放生成的代码.

1.3 使用 CDN (简)

开发

使用 import map

<script type="importmap">
  {
    "imports": {
      "three": "https://cdn.jsdelivr.net/npm/three@<version>/build/three.module.js",
      "three/addons/": "https://cdn.jsdelivr.net/npm/three@<version>/examples/jsm/"
    }
  }
</script>

注意修改版本, 可用版本参考: https://www.npmjs.com/package/three?activeTab=versions

安装 serve, 然后运行 npx serve ..

可用的 http 服务的 node 包有很多可以替代.

生产 (略)

不需要构建编译.

1.4 扩展 (Addon)

threejs 提供了一些开箱即用的组件. 这些组件在 addons/ 目录中. 它不需要单独安装, 但需要导入.

以 OrbitControlls 与 GLTFLoader 为例:

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';

const controls = new OrbitControls( camera, renderer.domElement );
const loader = new GLTFLoader();

对于一些第三方的组件就需要单独安装了.

2. 创建场景 (scene)

要展示内容需要三个对象: 场景 (scene), 相机 (camera), 以及渲染器 (renderer). 然后才可以在相机中渲染出场景.

基本步骤:

  1. 实例化场景对象.
  2. 实例化相机对象.
  3. 实例化渲染引擎.
  4. 将渲染引擎生成的 domElement 添加到页面中.
  5. 创建需要的对象 (几何体等). 并将几何体添加到场景中.
  6. 创建动画函数 (在其中调用 renderer.render 方法进行渲染), 然后在 renderer 中加载动画函数.
import * as THREE from 'three'

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)

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera)
})

document.body.appendChild(renderer.domElement)

创建几何体

  1. 创建几何体 (geometry)
  2. 创建材质 (material)
  3. 利用几何体与材质创建网格 (mesh)
  4. 将网格添加到场景中
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( { color: 0x00f0f0 } );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
camera.position.z = 5

然后修改动画函数

renderer.setAnimationLoop(() => {
  cube.rotation.x += 0.02;
  cube.rotation.y += 0.015;
  cube.rotation.z += 0.01;
  renderer.render(scene, camera)
})

说明

  1. 首先是相机, threejs 支持很多相机, 这里使用的是透视相机 (PerspectiveCamera). 其中第一个参数是视角, 采用角度制作为单位. 第二个参数是宽高比 (aspect ratio). 然后是近处与远处的极限值, 超出这个范围的对象不会被渲染 (考虑到渲染性能).
  2. 然后是渲染对象, 该对象需要设置 size, 以确保渲染的尺寸. 如果需要保持尺寸, 在低分辨率下渲染, 第三个参数可以传入 false.
  3. 要创建一个几何体, 首先需要一个 Geometry 对象, 它定义了几何体的形状. 需要为几何体添加材质颜色, 需要 Material 对象. 最后需要使用网格 (Mesh) 将其支撑起来.
  4. 如果要显示, 则需要使用渲染对象, 调用渲染方法, 将场景与相机渲染出来.
  5. 最后是动画, 使用 setAnimationLoop 方法, 其内部是 requestAnimationFrame 的实现, 比起 setInterval, 该方式会在必要时阻塞动画, 以提升性能与将其电池消耗.

image-20241211161039959

3. WebGL 能力检测

涉及到兼容性, 必要时还是需要进行能力检测.

import WebGL from 'three/addons/capabilities/WebGL.js'

if (WebGL.isWebGL2Available()) {
  // 代码
} else {
  const warning = WebGL.getWebGL2ErrorMessage()
  document.body.append(warning)
}

4. 划线

这里绘制线段与环路等, 并非网格框架. 首先需要准备, 场景, 相机与渲染器.

绘制线, 就是创建线对象, 线对象也需要几何对象, 材质对象. 逻辑上与网格对象一样.

  • 这里几何对象使用 BufferGeometry, 并使用点 (向量) 数组来定义路径.
  • 材质可以使用 LineBasicMaterial 或 LineDashedMaterial 对象, 来定义颜色.
  • 最后使用 Line 对象将器包装到一起, 添加到场景中.
const points = [
  new THREE.Vector3(0, 0, 0),
  new THREE.Vector3(10, 0, 0),
  new THREE.Vector3(10, 10, 0),
  new THREE.Vector3(0, 10, 0),
]

const material = new THREE.LineBasicMaterial({ color: 0x0000ff })
const geometry = new THREE.BufferGeometry().setFromPoints(points)
const line = new THREE.Line(geometry, material)
scene.add(line)

注意设置相机的 z 轴值

camera.position.z = 20

image-20241211163134071

5. 绘制文本

绘制文本的方式很多.

1. DOM + CSS

使用绝对定位 + z-index 将文本置于画布之上即可.

缺点是没有交互性, 主要以展示文字为主.

2. 使用 CSS2DRenderer 或 CSS3DRenderer

基本特征与 DOM + CSS 一样, 不同的是, 它处理文字是在代码层面, 结合动画, 可以实现满足可交互的文字.

基本原理是:

  1. 使用 CSSXDRender 生成一个与画布等大的层, 利用 CSS 绝对定位将该层置于 Canvas 上方. 需要注意样式中 pointerEvents 设为 none, 让盖层不会拦截鼠标与底层的 canvas 交互.
  2. 创建 DOM 并在其中添加文件, 并设置样式.
  3. 创建 CSSXDObject 对象, 包装 DOM 对象, 并设置 position 属性来进行定位. 然后将该对象添加到场景中.
  4. 调用 CSSXDRenderer 的 render 方法, 在相机下渲染场景.

基本代码结构

import { CSS2DRenderer, CSS3Renderer } from 'three/addons/renderers/CSS2DRenderer.js'

const css2dRenderer = new CSS2DRenderer()
css2dRenderer.setSize(window.innerWidth, window.innerHeight)
css2dRenderer.domElement.style.position = 'absolute'
css2dRenderer.domElement.style.left = 0
css2dRenderer.domElement.style.top = 0
css2dRenderer.domElement.style.zIndex = 100

document.body.appendChild(css2dRenderer.domElement)
css2dRenderer.render(scene, camera)

创建文字 DOM

const div = document.createElement('div')
div.innerHTML = '一段描述性文字'
div.style.color = '#333'
div.style.backgroundColor = 'lightyellow'

const css2DObj = new CSS2DObject(div)
css2DObj.position.set(10, 0, 0)
scene.add(css2DObj)

image-20241211174425875

3. 使用 Texture 将文字绘制到 Canvas 中

该方式是将文字作为几何体对象直接绘制到场景中.

用法暂略

4. 使用第三方工具导出模型

用法暂略

5. 使用 Text Geometry (内置几何对象)

用法暂略

6. Bitmap Fonts (位图字体)

用法暂略

7. Troika Text

用法暂略

6. 导入 3D 模型

three.js 提供了很多模型的导入工具. 但是模型格式太多, 无法一一俱到. 推荐使用 glTF (gl 传输格式).

加载的片段是:

import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
loader.load( 'path/to/model.glb', function (gltf) {
  scene.add(gltf.scene);
}, undefined, function (error) {
  console.error(error);
});
Last Updated:
Contributors: jk