3D/threejs 入门
专业名词
Geometry:几何体,描述物体的形状
Material:材质,描述物体的外观
Mesh:网格,几何体和材质的组合
Scene:场景,包含所有要渲染的物体
Camera:相机,用于观察场景
Renderer:渲染器,将场景渲染到屏幕上
Light:光源,用于照亮场景
Animation:动画,用于给物体添加动画
Group:组,用于将多个物体组合在一起,可以设置组的整体属性
Texture:纹理,用于给物体添加纹理
Shader:着色器,用于给物体添加着色
uv: 纹理坐标,用于描述纹理在物体上的位置
步骤
- 创建
Geometry
和Material
,加入到Mesh
中 - 创建
Light
光源 - 创建
Scene
场景,将Mesh
和Light
加入到Scene
中 - 创建
Camera
相机 - 创建
Renderer
渲染器,将Scene
和Camera
渲染到屏幕上 - 创建
OrbitControls
控制相机(传入Camera
和Renderer
),用于控制相机的位置和角度
JavaScript module 技巧
- import link 导入
- importmap 导入 importmap - MDN
1 | <!-- 通过链接导入 --> |
可视化控制
可以通过 dat-gui
/ lil-gui
来可视化控制参数,从而实现交互式效果。
dat-gui
已经不再维护了, star 7.6k
lil-gui
内置在 three.js
中, star 1.3k
lil-gui doc
lil-gui github
dat-gui github
视锥体和相机
通过创建 CameraHelper
来实现模拟相机视锥体,可视化相机角度,并通过 GUI 来实时控制 PerspectiveCamera
的 fov
、 aspect
、near
、far
参数。
fov
: 可视角度,离物体的远近,默认 50
aspect
: 宽高比,通常是浏览器窗口的宽高比 window.innerWidth / window.innerHeight
,默认 1
near
: 近截面,通常是 0.1
,默认 0.1
far
: 远截面,通常是 1000
,默认 1000
几何体
3D 物体都是有顶点构成的三角形网格模型,所有几何体都是由一堆三角形构成的。
如我们正常看到的三角形,是会有 3 个顶点;正方形则是由两个三角形构成的,有 6 个顶点。
可以通过 BufferGeometry
创建自定义集合体;
比如这里我们创建一个正方形,有 6 个顶点,每个顶点有 3 个坐标,所以需要 18 个数字。1
2
3
4
5
6
7
8
9
10
11
12const vertices = new Float32Array([
0, 0, 0,
100, 0, 0,
0, 100, 0,
0, 100, 0,
100, 0, 0,
100, 100, 0
]);
const attributes = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attributes;
有可以看出其实有一些数据是重复的 Three.js
提供了优化顶点存储的方案:存储一份不重复的顶点数据,然后存储一份顶点索引就可以了。1
2
3
4
5
6
7
8
9
10
11
12
13
14const vertices = new Float32Array([
0, 0, 0,
100, 0, 0,
0, 100, 0,
// 0, 100, 0,
// 100, 0, 0,
100, 100, 0
]);
const attributes = new THREE.BufferAttribute(vertices, 3);
geometry.attributes.position = attributes;
const indices = new Uint16Array([0, 1, 2, 2, 1, 3]);
geometry.index = new THREE.BufferAttribute(indices, 1);
噪声
噪声函数可以生成随机值,用于生成随机形状。
SimplexNoise 是 three.js
中的一种噪声函数,用于生成随机值。
uv
UV 坐标是纹理坐标,用于描述纹理在物体上的位置。
texture.offset 可以让纹理贴图偏移一段距离,相当于改变了 uv 坐标,所以修改 texture.offset 的动画也叫做 uv 动画。
还可以结合 texture.wrapT、textrue.wrapS 来实现纹理的重复。1
2
3
4
5
6
7
8const loader = new THREE.TextureLoader();
const texture = loader.load('./texture.png');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.offset.x = 0.5; // 水平偏移
texture.offset.y = 0.5; // 垂直偏移
texture.repeat.x = 2; // 水平重复
texture.repeat.y = 2; // 垂直重复