threejs 入门到放弃过程
官网下载:https://threejs.org/左边代码下载可以直接下载整个文档、示例和源码包
在本地使用 npm i 或 pnpm i 安装运行即可
整个threejs涉及的概念列表
| 英文 | 中文 | 说明 |
|---|---|---|
| Scene | 场景 | 包含所有3D物体和灯光的容器,是Three.js的核心之一。 |
| Camera | 摄像机 | 定义视角,将3D场景投影到2D画布上,常用的是PerspectiveCamera。 |
| Renderer | 渲染器 | 负责将场景渲染到屏幕上,常用的渲染器是WebGLRenderer。 |
| Object3D | 3D对象 | 所有3D对象的基类,包括Mesh、Light等,支持位置、旋转、缩放。 |
| Mesh | 网格 | 由Geometry和Material组成的3D物体,是场景中常见的对象类型。 |
| Geometry | 几何体 | 定义物体的形状,如BoxGeometry(立方体)、SphereGeometry(球体)等。 |
| Material | 材质 | 决定物体表面外观,如MeshBasicMaterial(基础材质)、MeshPhongMaterial(Phong材质)。 |
| Light | 灯光 | 为场景提供照明,包括AmbientLight(环境光)、PointLight(点光源)、DirectionalLight(平行光)等。 |
| Animation | 动画 | 通过Tween或Morph实现物体的动态效果,如旋转、移动等。 |
| Loader | 加载器 | 用于加载外部模型和资源,如OBJLoader(加载OBJ模型)、TextureLoader(加载纹理)。 |
| Event | 事件 | 处理用户输入和交互,如鼠标移动、点击等。 |
| Particles | 粒子系统 | 用于创建大量小物体,如烟花、星云等。 |
| Post-processing | 后期处理 | 通过ShaderMaterial增强视觉效果,如模糊、色调调整等。 |
| Physics | 物理引擎 | 虽然Three.js本身不提供,但可以集成如Cannon.js等物理引擎。 |
| Shaders | 着色器 | 通过自定义GLSL代码实现复杂视觉效果,如水波纹、火焰等。 |
| WebGL | WebGL | 基于OpenGL ES 2.0的API,在浏览器中渲染3D图形。 |
| Math | 数学库 | 提供向量、矩阵、颜色等工具,如Vector3、Matrix4、Color等。 |
| Utils | 工具库 | 提供辅助函数,如几何体生成、单位转换等。 |
| SceneGraph | 场景图 | 管理对象的层次结构,方便场景管理。 |
初始化项目
使用 vite创建一个 js 的项目
pnpm create vite
Select a framework:
│ ● Vanilla
│ ○ Vue
│ ○ React
│ ○ Preact
│ ○ Lit
│ ○ Svelte
│ ○ Solid
│ ○ Qwik
│ ○ Angular
│ ○ Marko
│ ○ Others
◆ Select a variant:
│ ○ TypeScript
│ ● JavaScript
增加一个 css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
box-sizing: border-box;
}
安装 threejs
pnpm add three
创建一个正方形
在 main.js 中书写以下代码
import "./style.css";
import * as THREE from "three";
init();
function init() {
const scene = new THREE.Scene();
//创建一个透视相机
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.z = 6;
camera.position.y = 10;
camera.position.x = 8;
camera.lookAt(0, 0, 0);
scene.add(camera);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
document.body.appendChild(renderer.domElement);
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshBasicMaterial({ color: 0x00ff00 })
);
scene.add(cube);
controls.enableRotate = true;
renderer.render(scene, camera);
}
坐标辅助器
AxesHelper 类实现
// 坐标轴辅助器
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
轨道控制器
OrbitControls来实现,实际就是为相机控件,本质是改变相机的参数,如角度,透视,与模型的距离等,可以实现以下效果
- 旋转:拖动鼠标左键
- 缩放:滚动鼠标中键
- 平移:拖动鼠标右键
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
const controls = new OrbitControls(camera, renderer.domElement);
//添加阻尼
controls.enableDamping = true;
//添加阻尼系数
controls.dampingFactor = 0.25;
//是否启用缩放
controls.enableZoom = true;
//是否启用平移
controls.enablePan = true;
//是否启用旋转
controls.enableRotate = true;
controls.addEventListener("change", function () {
// 浏览器控制台查看相机位置变化
console.log("camera.position", camera.position);
});
动画渲染循环
threejs可以借助HTML5的API请求动画帧window.requestAnimationFrame实现动画渲染。
const clock = new THREE.Clock();
function animate() {
const spt = clock.getDelta() * 1000; //毫秒
requestAnimationFrame(animate);
controls.update();
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
console.log("spt", spt); //每秒帧数
}
animate();
备注说明:对于部分高刷新率的电脑硬件设备,.requestAnimationFrame每秒钟默认调用函数执行次数也是有可能超过60次的,比如你的电脑显卡、显示器等硬件能够支持144hz刷新频率,.requestAnimationFrame的每秒执行上限,也可以接近144帧率。
自适应宽度
window.onresize = function () {
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera.aspect = window.innerWidth / window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
};
光源
PointLight点光源
// 点光源
const pointLight = new THREE.PointLight(0xffffff, 0.5);
pointLight.position.set(2, 2, 2);
scene.add(pointLight);
环境光
AmbientLight环境光
// 环境光
const pointLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(pointLight);
聚光灯
SpotLight聚光灯
const spotLight = new THREE.SpotLight(0xffffff, 1.0);
spotLight.position.set(2, 2, 2);
scene.add(spotLight);
平行光
DirectionalLight 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.0);
directionalLight.position.set(2, 2, 2);
scene.add(directionalLight);
几何体和顶点
// 创建一个三角形
const geometry = new THREE.BufferGeometry();
// 创建一个三角形的顶点
const vertices = new Float32Array([
-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0,
1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0, -1.0, 0.0,
]);
// 设置顶点位置,3 个为一个 点
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
设置索引
const geometry = new THREE.BufferGeometry();
// 创建一个三角形的顶点
const vertices = new Float32Array([
-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0,
]);
// 设置顶点位置
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
// 创建一个三角形的索引
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
// 设置索引
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
增加加个材质
const geometry = new THREE.BufferGeometry();
// 创建一个三角形的顶点
const vertices = new Float32Array([
-1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0,
]);
// 设置顶点位置
geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
// 创建一个三角形的索引
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
// 设置索引
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
geometry.addGroup(0, 3, 0);
geometry.addGroup(3, 3, 1);
console.log(geometry);
// 创建一个材质
const material1 = new THREE.MeshBasicMaterial({
color: 0x00ff00,
// wireframe: true,
side: THREE.DoubleSide,
});
const material2 = new THREE.MeshBasicMaterial({
color: 0x0000ff,
// wireframe: true,
side: THREE.DoubleSide,
});
// 创建一个网格
const cube = new THREE.Mesh(geometry, [material1, material2]);
// 添加到场景中
scene.add(cube);