3D/threejs 入门
3D 相关课程/文章
- course: threejs-journey
- book: discoverthreejs
- book: zxg_神说要有光 threejs 小册子
- article: 3d-modeling-basics-for-developers
- doc: 官方入门文档
- All 109 Examples from my book on Three.js for Three.js version r63
专业名词
- Geometry:几何体,描述物体的形状
- Material:材质,描述物体的外观
- Mesh:网格,几何体和材质的组合
- Scene:场景,包含所有要渲染的物体
- Camera:相机,用于观察场景
- Renderer:渲染器,将场景渲染到屏幕上
- Light:光源,用于照亮场景
- Animation:动画,用于给物体添加动画
- Group:组,用于将多个物体组合在一起,可以设置组的整体属性
- Texture:纹理,用于给物体添加纹理
- Shader:着色器,用于给物体添加着色
- uv: 纹理坐标,用于描述纹理在物体上的位置
JavaScript module 技巧
- import link 导入
- importmap 导入 importmap - MDN
1 | <!-- 通过链接导入 --> |
步骤
- 创建
Geometry
和Material
,加入到Mesh
中 - 创建
Light
光源 - 创建
Scene
场景,将Mesh
和Light
加入到Scene
中 - 创建
Camera
相机 - 创建
Renderer
渲染器,将Scene
和Camera
渲染到屏幕上 - 创建
OrbitControls
控制相机(传入Camera
和Renderer
),用于控制相机的位置和角度
可视化控制
可以通过 dat-gui
/ lil-gui
来可视化控制参数,从而实现交互式效果。
dat-gui
已经不再维护了, star 7.6k
lil-gui
内置在 three.js
中, star 1.3k
- dat.GUI
- lil-gui
- control-panel
- ControlKit
- Uil
- Tweakpane
- Guify
- Oui
视锥体和相机
通过创建 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; // 垂直重复
动画
使用相同的时间间隔来更新动画,可以保证动画的流畅性。
方法一:1
2
3
4
5
6
7
8
9
10
11
12
13let time = Date.now()
const tick = () => {
const currentTime = Date.now()
const deltaTime = currentTime - time
time = currentTime
mesh.rotation.y += 0.001 * deltaTime
renderer.render(scene, camera)
window.requestAnimationFrame(tick)
}
tick()
方法二:1
2
3
4
5
6
7
8
9
10const clock = new THREE.Clock()
const tick = () => {
const elapsedTime = clock.getElapsedTime()
mesh.rotation.y = 0.001 * elapsedTime
renderer.render(scene, camera)
window.requestAnimationFrame(tick)
}
tick()
动画库
- gsap
- tween.js
find texture website
- poliigon.com
- 3dtextures.me
- arroway-textures.ch
Font
@react-three/fiber 中可以直接使用 Text
组件来生成文字模型,还可配置对应字体
- 转换字体网站
- https://transfonter.org/
- https://www.fontsquirrel.com/tools/webfont-generator
- Google Fonts 字体
- Google Font Helper