Three.js 速查表
本文档提供 Three.js 常用 API 和代码片段的快速参考。
初始化
基础设置
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
// 相机
const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000);
camera.position.set(0, 5, 10);
// 渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// 渲染循环
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
controls.update();
renderer.render(scene, camera);
}
animate();
响应窗口变化
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
场景
// 创建场景
const scene = new THREE.Scene();
// 背景色
scene.background = new THREE.Color(0x000000);
// 背景透明
scene.background = null;
// 雾效 - 线性
scene.fog = new THREE.Fog(color, near, far);
// 雾效 - 指数
scene.fog = new THREE.FogExp2(color, density);
// 环境贴图
scene.environment = texture;
// 添加对象
scene.add(object);
// 移除对象
scene.remove(object);
// 遍历场景
scene.traverse((obj) => { });
// 按名称查找
scene.getObjectByName('name');
相机
透视相机
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
// fov: 视野角度(度)
// aspect: 宽高比
// near: 近裁剪面
// far: 远裁剪面
camera.position.set(x, y, z);
camera.lookAt(x, y, z);
camera.lookAt(target.position);
正交相机
const camera = new THREE.OrthographicCamera(left, right, top, bottom, near, far);
相机方法
camera.position.set(x, y, z);
camera.lookAt(target);
camera.updateProjectionMatrix();
几何体
内置几何体
// 立方体
new THREE.BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments);
// 球体
new THREE.SphereGeometry(radius, widthSegments, heightSegments);
// 圆柱体
new THREE.CylinderGeometry(radiusTop, radiusBottom, height, radialSegments);
// 圆锥体
new THREE.ConeGeometry(radius, height, radialSegments);
// 平面
new THREE.PlaneGeometry(width, height, widthSegments, heightSegments);
// 圆环
new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments);
// 圆环结
new THREE.TorusKnotGeometry(radius, tube, tubularSegments, radialSegments);
// 圆形
new THREE.CircleGeometry(radius, segments);
// 圆环
new THREE.RingGeometry(innerRadius, outerRadius, segments);
BufferGeometry
const geometry = new THREE.BufferGeometry();
// 设置顶点位置
const positions = new Float32Array([x1, y1, z1, x2, y2, z2, ...]);
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
// 设置法线
geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3));
// 设置 UV
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
// 设置顶点颜色
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
// 计算包围盒
geometry.computeBoundingBox();
geometry.computeBoundingSphere();
几何体变换
geometry.translate(x, y, z);
geometry.rotateX(angle);
geometry.rotateY(angle);
geometry.rotateZ(angle);
geometry.scale(x, y, z);
geometry.center();
材质
基础材质
// 基础材质(不受光照影响)
new THREE.MeshBasicMaterial({
color: 0x00ff00,
wireframe: false,
transparent: false,
opacity: 1,
side: THREE.FrontSide // FrontSide | BackSide | DoubleSide
});
// 法线材质(调试用)
new THREE.MeshNormalMaterial();
受光照材质
// Lambert 材质(漫反射)
new THREE.MeshLambertMaterial({
color: 0x00ff00,
emissive: 0x000000
});
// Phong 材质(高光)
new THREE.MeshPhongMaterial({
color: 0x00ff00,
specular: 0xffffff,
shininess: 30
});
// 标准材质(PBR)
new THREE.MeshStandardMaterial({
color: 0x00ff00,
metalness: 0.5,
roughness: 0.5,
emissive: 0x000000,
envMapIntensity: 1
});
// 物理材质(高级 PBR)
new THREE.MeshPhysicalMaterial({
color: 0x00ff00,
metalness: 0,
roughness: 0.5,
clearcoat: 1,
clearcoatRoughness: 0,
transmission: 0,
thickness: 0.5,
ior: 1.5
});
特殊材质
// 卡通材质
new THREE.MeshToonMaterial({ color: 0x00ff00 });
// 点材质
new THREE.PointsMaterial({
color: 0x00ff00,
size: 0.1,
sizeAttenuation: true
});
// 精灵材质
new THREE.SpriteMaterial({
color: 0x00ff00,
transparent: true
});
// 着色器材质
new THREE.ShaderMaterial({
uniforms: { uTime: { value: 0 } },
vertexShader: '...',
fragmentShader: '...'
});
纹理贴图
const material = new THREE.MeshStandardMaterial({
map: diffuseTexture, // 漫反射贴图
normalMap: normalTexture, // 法线贴图
roughnessMap: roughnessTexture, // 粗糙度贴图
metalnessMap: metalnessTexture, // 金属度贴图
aoMap: aoTexture, // 环境光遮蔽贴图
emissiveMap: emissiveTexture, // 自发光贴图
alphaMap: alphaTexture // 透明度贴图
});
纹理
const loader = new THREE.TextureLoader();
const texture = loader.load('texture.jpg');
// 重复模式
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(x, y);
// 过滤
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;
// 各向异性过滤
texture.anisotropy = renderer.capabilities.getMaxAnisotropy();
// 偏移和旋转
texture.offset.set(x, y);
texture.rotation = angle;
texture.center.set(0.5, 0.5);
// 编码
texture.colorSpace = THREE.SRGBColorSpace;
网格
const mesh = new THREE.Mesh(geometry, material);
// 变换
mesh.position.set(x, y, z);
mesh.rotation.set(rx, ry, rz);
mesh.scale.set(sx, sy, sz);
// 欧拉角旋转顺序
mesh.rotation.order = 'XYZ';
// 四元数旋转
mesh.quaternion.setFromAxisAngle(axis, angle);
// 阴影
mesh.castShadow = true;
mesh.receiveShadow = true;
// 可见性
mesh.visible = true;
// 渲染顺序
mesh.renderOrder = 0;
// 用户数据
mesh.userData.customProperty = value;
光源
// 环境光
const ambient = new THREE.AmbientLight(color, intensity);
// 半球光
const hemi = new THREE.HemisphereLight(skyColor, groundColor, intensity);
// 方向光
const dir = new THREE.DirectionalLight(color, intensity);
dir.position.set(x, y, z);
dir.castShadow = true;
dir.shadow.mapSize.set(2048, 2048);
dir.shadow.camera.near = 0.5;
dir.shadow.camera.far = 50;
// 点光源
const point = new THREE.PointLight(color, intensity, distance, decay);
point.position.set(x, y, z);
point.castShadow = true;
// 聚光灯
const spot = new THREE.SpotLight(color, intensity, distance, angle, penumbra);
spot.position.set(x, y, z);
spot.target.position.set(x, y, z);
spot.castShadow = true;
// 矩形区域光
const rect = new THREE.RectAreaLight(color, intensity, width, height);
阴影
// 启用阴影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 光源投射阴影
light.castShadow = true;
light.shadow.mapSize.set(2048, 2048);
// 方向光阴影范围
light.shadow.camera.left = -10;
light.shadow.camera.right = 10;
light.shadow.camera.top = 10;
light.shadow.camera.bottom = -10;
light.shadow.camera.near = 0.5;
light.shadow.camera.far = 50;
// 阴影偏移
light.shadow.bias = -0.0001;
// 物体投射/接收阴影
mesh.castShadow = true;
mesh.receiveShadow = true;
动画
基础动画
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
const elapsed = clock.getElapsedTime();
// 更新物体
mesh.rotation.y += delta;
renderer.render(scene, camera);
}
关键帧动画
const mixer = new THREE.AnimationMixer(object);
const positionKF = new THREE.VectorKeyframeTrack(
'.position',
[0, 1, 2],
[0, 0, 0, 2, 2, 0, 0, 0, 0]
);
const clip = new THREE.AnimationClip('action', duration, [positionKF]);
const action = mixer.clipAction(clip);
action.play();
// 更新混合器
mixer.update(delta);
动画控制
action.play();
action.pause();
action.stop();
action.reset();
action.timeScale = 1;
action.loop = THREE.LoopRepeat;
action.repetitions = Infinity;
action.weight = 1;
交互
射线检测
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
// 鼠标位置转归一化坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 设置射线
raycaster.setFromCamera(mouse, camera);
// 检测相交
const intersects = raycaster.intersectObjects(objects);
const intersects = raycaster.intersectObjects(objects, true); // 递归检测
// 相交结果
intersects[0].object; // 相交物体
intersects[0].point; // 相交点
intersects[0].distance; // 距离
intersects[0].face; // 相交面
intersects[0].uv; // UV 坐标
控制器
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
const controls = new OrbitControls(camera, domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.autoRotate = true;
controls.autoRotateSpeed = 2;
controls.minDistance = 2;
controls.maxDistance = 20;
controls.minPolarAngle = 0;
controls.maxPolarAngle = Math.PI / 2;
controls.enablePan = true;
controls.enableZoom = true;
// 更新
controls.update();
加载器
// GLTF 模型
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
new GLTFLoader().load('model.glb', (gltf) => {
scene.add(gltf.scene);
});
// 纹理
new THREE.TextureLoader().load('texture.jpg', (texture) => {});
// HDR 环境贴图
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
new RGBELoader().load('env.hdr', (texture) => {});
// OBJ 模型
import { OBJLoader } from 'three/addons/loaders/OBJLoader.js';
// FBX 模型
import { FBXLoader } from 'three/addons/loaders/FBXLoader.js';
// 字体
import { FontLoader } from 'three/addons/loaders/FontLoader.js';
后期处理
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bloomPass = new UnrealBloomPass(size, strength, radius, threshold);
composer.addPass(bloomPass);
// 渲染
composer.render();
数学工具
// 向量
const v = new THREE.Vector3(x, y, z);
v.set(x, y, z);
v.add(v2);
v.sub(v2);
v.multiplyScalar(s);
v.normalize();
v.length();
v.distanceTo(v2);
v.clone();
// 颜色
const c = new THREE.Color(0xff0000);
c.setHex(0xff0000);
c.setRGB(r, g, b);
c.setHSL(h, s, l);
c.lerp(c2, t);
// 欧拉角
const e = new THREE.Euler(x, y, z, 'XYZ');
// 四元数
const q = new THREE.Quaternion();
q.setFromAxisAngle(axis, angle);
q.setFromEuler(euler);
// 矩阵
const m = new THREE.Matrix4();
m.compose(position, quaternion, scale);
m.decompose(position, quaternion, scale);
// 射线
const ray = new THREE.Ray(origin, direction);
ray.intersectSphere(sphere, target);
ray.intersectPlane(plane, target);
// 平面
const plane = new THREE.Plane(normal, constant);
// 包围盒
const box = new THREE.Box3();
box.setFromObject(object);
box.containsPoint(point);
box.intersectsBox(box2);
常用常量
// 渲染面
THREE.FrontSide
THREE.BackSide
THREE.DoubleSide
// 混合模式
THREE.NormalBlending
THREE.AdditiveBlending
THREE.SubtractiveBlending
THREE.MultiplyBlending
// 纹理包裹
THREE.ClampToEdgeWrapping
THREE.RepeatWrapping
THREE.MirroredRepeatWrapping
// 过滤
THREE.NearestFilter
THREE.LinearFilter
THREE.NearestMipmapNearestFilter
THREE.NearestMipmapLinearFilter
THREE.LinearMipmapNearestFilter
THREE.LinearMipmapLinearFilter
// 阴影类型
THREE.BasicShadowMap
THREE.PCFShadowMap
THREE.PCFSoftShadowMap
// 颜色空间
THREE.SRGBColorSpace
THREE.LinearSRGBColorSpace
// 动画循环
THREE.LoopOnce
THREE.LoopRepeat
THREE.LoopPingPong
性能优化
// 实例化渲染
const mesh = new THREE.InstancedMesh(geometry, material, count);
mesh.setMatrixAt(index, matrix);
mesh.instanceMatrix.needsUpdate = true;
// 合并几何体
import { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';
const merged = mergeGeometries([geo1, geo2]);
// 限制像素比
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
// 按需渲染
let needsRender = true;
controls.addEventListener('change', () => needsRender = true);
function animate() {
requestAnimationFrame(animate);
if (needsRender) {
renderer.render(scene, camera);
needsRender = false;
}
}
// 释放资源
geometry.dispose();
material.dispose();
texture.dispose();