手册
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
与构建工具
开发
首先安装
node
环境.安装
three.js
,vite
. 使用vite
可以使用 ES Module 模式来导入模块.npm i three npm i vite -D
执行
npx vite
来运行开发环境通过浏览器访问.
生产
使用 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
). 然后才可以在相机中渲染出场景.
基本步骤:
- 实例化场景对象.
- 实例化相机对象.
- 实例化渲染引擎.
- 将渲染引擎生成的
domElement
添加到页面中. - 创建需要的对象 (几何体等). 并将几何体添加到场景中.
- 创建动画函数 (在其中调用
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)
创建几何体
- 创建几何体 (
geometry
) - 创建材质 (
material
) - 利用几何体与材质创建网格 (
mesh
) - 将网格添加到场景中
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)
})
说明
- 首先是相机,
threejs
支持很多相机, 这里使用的是透视相机 (PerspectiveCamera
). 其中第一个参数是视角, 采用角度制作为单位. 第二个参数是宽高比 (aspect ratio
). 然后是近处与远处的极限值, 超出这个范围的对象不会被渲染 (考虑到渲染性能). - 然后是渲染对象, 该对象需要设置
size
, 以确保渲染的尺寸. 如果需要保持尺寸, 在低分辨率下渲染, 第三个参数可以传入false
. - 要创建一个几何体, 首先需要一个
Geometry
对象, 它定义了几何体的形状. 需要为几何体添加材质颜色, 需要Material
对象. 最后需要使用网格 (Mesh
) 将其支撑起来. - 如果要显示, 则需要使用渲染对象, 调用渲染方法, 将场景与相机渲染出来.
- 最后是动画, 使用
setAnimationLoop
方法, 其内部是requestAnimationFrame
的实现, 比起setInterval
, 该方式会在必要时阻塞动画, 以提升性能与将其电池消耗.
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
5. 绘制文本
绘制文本的方式很多.
1. DOM + CSS
使用绝对定位 + z-index
将文本置于画布之上即可.
缺点是没有交互性, 主要以展示文字为主.
2. 使用 CSS2DRenderer
或 CSS3DRenderer
基本特征与 DOM + CSS 一样, 不同的是, 它处理文字是在代码层面, 结合动画, 可以实现满足可交互的文字.
基本原理是:
- 使用
CSSXDRender
生成一个与画布等大的层, 利用CSS
绝对定位将该层置于Canvas
上方. 需要注意样式中pointerEvents
设为none
, 让盖层不会拦截鼠标与底层的canvas
交互. - 创建
DOM
并在其中添加文件, 并设置样式. - 创建
CSSXDObject
对象, 包装DOM
对象, 并设置position
属性来进行定位. 然后将该对象添加到场景中. - 调用
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)
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);
});