Three.js 知识点总结
Three.js 是一个基于 WebGL 的 3D 图形库,用于在浏览器中创建和显示 3D 场景。
核心概念
三大核心组件
Three.js 的核心由三个组件构成:
- Scene(场景) - 3D 世界的容器
- Camera(相机) - 定义观察者的视角
- Renderer(渲染器) - 将场景渲染到画布上
// 基本结构
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);
document.body.appendChild(renderer.domElement);
Scene(场景)
场景是所有对象的容器,用于组织和管理 3D 对象。
const scene = new THREE.Scene();
// 设置 背景色
scene.background = new THREE.Color(0x000000);
// 添加雾效果
scene.fog = new THREE.Fog(0x000000, 10, 50);
场景属性
background: 场景背景(颜色、纹理或立方体贴图)fog: 雾效果environment: 环境贴图(用于 PBR 材质)
Camera(相机)
PerspectiveCamera(透视相机)
最常用的相机类型,模拟人眼视角。
const camera = new THREE.PerspectiveCamera(
75, // FOV(视野角度)
window.innerWidth / window.innerHeight, // 宽高比
0.1, // 近裁剪面
1000 // 远裁剪面
);
camera.position.set(0, 0, 5);
camera.lookAt(0, 0, 0);
OrthographicCamera(正交相机)
正交投影,无透视变形。
const camera = new THREE.OrthographicCamera(
-1, 1, // left, right
1, -1, // top, bottom
0.1, // near
100 // far
);
相机控制
// 使用 OrbitControls 控制相机
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true; // 启用阻尼
controls.dampingFactor = 0.05;
Renderer(渲染器)
WebGLRenderer
使用 WebGL 进行硬件加速渲染。
const renderer = new THREE.WebGLRenderer({
antialias: true, // 抗锯齿
alpha: true, // 透明背景
powerPreference: "high-performance" // 性能偏好
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio); // 适配高DPI屏幕
renderer.shadowMap.enabled = true; // 启用阴影
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 阴影类型
渲染循环
function animate() {
requestAnimationFrame(animate);
// 更新控制器
controls.update();
// 渲染场景
renderer.render(scene, camera);
}
animate();
Geometry(几何体)
内置几何体
// 立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 球体
const geometry = new THREE.SphereGeometry(1, 32, 32);
// 平面
const geometry = new THREE.PlaneGeometry(1, 1);
// 圆柱体
const geometry = new THREE.CylinderGeometry(0.5, 0.5, 1, 32);
// 圆环
const geometry = new THREE.TorusGeometry(0.5, 0.2, 16, 100);
// 圆锥
const geometry = new THREE.ConeGeometry(0.5, 1, 32);
// 圆环结
const geometry = new THREE.TorusKnotGeometry(0.5, 0.2, 100, 16);
BufferGeometry
更灵活、性能更好的几何体,适合自定义形状。
const geometry = new THREE.BufferGeometry();
// 定义顶点位置
const vertices = new Float32Array([
-1.0, -1.0, 1.0,
1.0, -1.0, 1.0,
1.0, 1.0, 1.0,
-1.0, 1.0, 1.0,
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
// 定义索引
const indices = new Uint16Array([0, 1, 2, 2, 3, 0]);
geometry.setIndex(indices);
// 计算法线
geometry.computeVertexNormals();
几何体操作
// 合并几何体
const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries([geo1, geo2]);
// 中心化
geometry.center();
// 归一化
geometry.normalize();
// 计算包围盒
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
Material(材质)
基础材质
// MeshBasicMaterial - 不受光照影响
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// MeshLambertMaterial - 漫反射材质
const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 });
// MeshPhongMaterial - 高光材质
const material = new THREE.MeshPhongMaterial({
color: 0x00ff00,
shininess: 100,
specular: 0x222222
});
// MeshStandardMaterial - PBR 标准材质
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00,
metalness: 0.5,
roughness: 0.5
});
// MeshPhysicalMaterial - 物理材质(更真 实)
const material = new THREE.MeshPhysicalMaterial({
color: 0x00ff00,
metalness: 0.5,
roughness: 0.5,
clearcoat: 1.0,
clearcoatRoughness: 0.1
});
材质属性
const material = new THREE.MeshStandardMaterial({
color: 0x00ff00, // 颜色
map: texture, // 漫反射贴图
normalMap: normalTexture, // 法线贴图
roughnessMap: roughnessTexture, // 粗糙度贴图
metalnessMap: metalnessTexture, // 金属度贴图
aoMap: aoTexture, // 环境光遮蔽贴图
emissive: 0x000000, // 自发光颜色
emissiveMap: emissiveTexture, // 自发光贴图
transparent: true, // 启用透明
opacity: 0.5, // 透明度
side: THREE.DoubleSide, // 渲染面(FrontSide/BackSide/DoubleSide)
wireframe: false, // 线框模式
flatShading: false // 平面着色
});
纹理
// 加载纹理
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('path/to/texture.jpg');
// 纹理设置
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(2, 2);
texture.offset.set(0.5, 0.5);
texture.rotation = Math.PI / 4;
// 立方体贴图
const cubeTextureLoader = new THREE.CubeTextureLoader();
const envMap = cubeTextureLoader.load([
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
]);
scene.background = envMap;
material.envMap = envMap;
Mesh(网格)
网格是几何体和材质的组合。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(0, 0, 0);
mesh.rotation.set(0, Math.PI / 4, 0);
mesh.scale.set(1, 1, 1);
scene.add(mesh);
对象变换
// 位置
mesh.position.x = 1;
mesh.position.set(1, 2, 3);
// 旋转(弧度制)
mesh.rotation.x = Math.PI / 4;
mesh.rotation.set(0, Math.PI / 4, 0);
// 缩放
mesh.scale.set(2, 2, 2);
// 使用四元数旋转(避免万向锁)
mesh.quaternion.setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 4);
Light(光照)
光源类型
// 环境光 - 均匀照亮所有物体
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 方向光 - 平行光(如太阳光)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 5, 5);
directionalLight.castShadow = true;
scene.add(directionalLight);
// 点光源 - 从一点向四周发射
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 10, 0);
pointLight.castShadow = true;
scene.add(pointLight);
// 聚光灯 - 圆锥形光束
const spotLight = new THREE.SpotLight(0xffffff, 1);
spotLight.position.set(0, 10, 0);
spotLight.angle = Math.PI / 4;
spotLight.penumbra = 0.1;
spotLight.castShadow = true;
scene.add(spotLight);
// 半球光 - 模拟天空和地面
const hemisphereLight = new THREE.HemisphereLight(0xffffbb, 0x080820, 1);
scene.add(hemisphereLight);
// 矩形光 - 面光源(用于 PBR)
const rectLight = new THREE.RectAreaLight(0xffffff, 1, 10, 10);
rectLight.position.set(5, 5, 5);
scene.add(rectLight);
阴影
// 启用阴影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 光源投射阴影
light.castShadow = true;
light.shadow.mapSize.width = 2048;
light.shadow.mapSize.height = 2048;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 50;
// 物 体接收/投射阴影
mesh.castShadow = true;
mesh.receiveShadow = true;
Animation(动画)
使用 requestAnimationFrame
function animate() {
requestAnimationFrame(animate);
// 旋转动画
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
使用 GSAP 动画库
import gsap from 'gsap';
gsap.to(mesh.rotation, {
x: Math.PI * 2,
y: Math.PI * 2,
duration: 2,
repeat: -1,
ease: "none"
});
使用 Clock 控制时间
const clock = new THREE.Clock();
function animate() {
const elapsedTime = clock.getElapsedTime();
mesh.rotation.y = elapsedTime;
camera.position.x = Math.sin(elapsedTime) * 3;
camera.position.z = Math.cos(elapsedTime) * 3;
camera.lookAt(mesh.position);
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Loaders(加载器)
GLTFLoader - 加载 3D 模型
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load(
'path/to/model.gltf',
(gltf) => {
const model = gltf.scene;
scene.add(model);
},
(progress) => {
console.log('加载进度:', progress.loaded / progress.total * 100 + '%');
},
(error) => {
console.error('加载错误:', error);
}
);
TextureLoader - 加载纹理
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('path/to/texture.jpg');
CubeTextureLoader - 加载立方体贴图
const cubeTextureLoader = new THREE.CubeTextureLoader();
const envMap = cubeTextureLoader.load([
'px.jpg', 'nx.jpg',
'py.jpg', 'ny.jpg',
'pz.jpg', 'nz.jpg'
]);
FontLoader - 加载字体
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
const fontLoader = new FontLoader();
fontLoader.load('path/to/font.json', (font) => {
const textGeometry = new TextGeometry('Hello Three.js', {
font: font,
size: 0.5,
height: 0.2,
curveSegments: 12,
bevelEnabled: true,
bevelThickness: 0.03,
bevelSize: 0.02,
bevelOffset: 0,
bevelSegments: 5
});
const textMesh = new THREE.Mesh(textGeometry, material);
scene.add(textMesh);
});
性能优化
几何体合并
import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';
const geometries = [];
for (let i = 0; i < 1000; i++) {
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
geometry.translate(Math.random() * 10, Math.random() * 10, Math.random() * 10);
geometries.push(geometry);
}
const mergedGeometry = BufferGeometryUtils.mergeBufferGeometries(geometries);
const mesh = new THREE.Mesh(mergedGeometry, material);
scene.add(mesh);
实例化渲染
const geometry = new THREE.BoxGeometry(0.1, 0.1, 0.1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const mesh = new THREE.InstancedMesh(geometry, material, 1000);
const matrix = new THREE.Matrix4();
for (let i = 0; i < 1000; i++) {
matrix.setPosition(
Math.random() * 10,
Math.random() * 10,
Math.random() * 10
);
mesh.setMatrixAt(i, matrix);
}
scene.add(mesh);
LOD(细节层次)
const lod = new THREE.LOD();
// 添加不同细节级别的模型
lod.addLevel(highDetailMesh, 0);
lod.addLevel(mediumDetailMesh, 50);
lod.addLevel(lowDetailMesh, 100);
scene.add(lod);
视锥体剔除
// 自动启用,但需要正确设置几何体的包围盒
geometry.computeBoundingSphere();
减少绘制调用
- 合并几何体
- 使用实例化渲染
- 使用纹理图集