name: threejs description: Three.js 3D图形库 - 场景设置、几何体、材质、照明、纹理、动画、加载器、着色器、后处理、交互。适用于构建3D网页体验、创建WebGL可视化、处理GLTF模型、实现自定义着色器或向网页应用添加交互式3D元素。 version: 1.0.0 license: MIT
Three.js 技能
概述
构建3D网页体验的全面知识库,提供准确的API参考、最佳实践和可运行代码示例,覆盖所有主要Three.js领域。
Three.js 版本: r160+ (2024年1月)
快速参考
核心主题
本技能涵盖10个基本Three.js领域:
- 基础 - 场景设置、相机、渲染器、Object3D层级
- 几何体 - 内置形状、BufferGeometry、自定义几何体、实例化
- 材质 - PBR材质、着色器材质、材质属性
- 照明 - 光源类型、阴影、环境光照
- 纹理 - UV映射、环境贴图、渲染目标
- 动画 - 关键帧动画、骨骼动画、动画混合
- 加载器 - GLTF/GLB加载、异步模式、缓存
- 着色器 - GLSL基础、ShaderMaterial、自定义效果
- 后处理 - EffectComposer、辉光、景深、自定义通道
- 交互 - 射线投射、相机控制、鼠标/触摸输入
何时加载参考
根据当前任务加载详细参考文件:
- 基础场景设置、相机、渲染器 → 加载
references/threejs-fundamentals.md - 创建形状、自定义几何体、实例化 → 加载
references/threejs-geometry.md - 材质属性、PBR、着色器材质 → 加载
references/threejs-materials.md - 添加光源、配置阴影 → 加载
references/threejs-lighting.md - 纹理加载、UV映射、环境贴图 → 加载
references/threejs-textures.md - 动画对象、GLTF动画、混合 → 加载
references/threejs-animation.md - 加载GLTF/GLB模型、Draco压缩 → 加载
references/threejs-loaders.md - 编写GLSL着色器、自定义视觉效果 → 加载
references/threejs-shaders.md - 添加辉光、景深、屏幕效果 → 加载
references/threejs-postprocessing.md - 射线投射、鼠标拾取、相机控制 → 加载
references/threejs-interaction.md
快速入门示例
1. 基础:基础场景
import * as THREE from 'three';
// 场景、相机、渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
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 geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// 添加光源
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 5, 5);
scene.add(dirLight);
camera.position.z = 5;
// 动画循环
function animate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
// 响应式
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
2. 几何体:创建形状
// 内置几何体
const box = new THREE.BoxGeometry(1, 1, 1);
const sphere = new THREE.SphereGeometry(0.5, 32, 32);
const plane = new THREE.PlaneGeometry(10, 10);
// 自定义BufferGeometry
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-1, -1, 0, // 顶点0
1, -1, 0, // 顶点1
1, 1, 0, // 顶点2
-1, 1, 0 // 顶点3
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
// 三角形索引
const indices = new Uint16Array([0, 1, 2, 0, 2, 3]);
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
// 实例化用于多个副本
const count = 1000;
const instancedMesh = new THREE.InstancedMesh(geometry, material, count);
const dummy = new THREE.Object3D();
for (let i = 0; i < count; i++) {
dummy.position.set(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20
);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);
3. 材质:PBR材质
// 标准PBR材质
const material = new THREE.MeshStandardMaterial({
color: 0xffffff,
metalness: 0.5,
roughness: 0.5,
map: colorTexture,
normalMap: normalTexture,
roughnessMap: roughnessTexture,
metalnessMap: metalnessTexture,
envMap: environmentMap,
envMapIntensity: 1
});
// 物理材质(高级PBR)
const glassMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1, // 玻璃透明度
thickness: 0.5,
ior: 1.5, // 折射率
envMapIntensity: 1
});
// 着色器材质(自定义)
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
color: { value: new THREE.Color(0xff0000) }
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform float time;
uniform vec3 color;
varying vec2 vUv;
void main() {
gl_FragColor = vec4(color * sin(vUv.x * 10.0 + time), 1.0);
}
`
});
4. 照明:基础照明
// 环境光(均匀)
const ambient = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambient);
// 定向光(太阳)
const dirLight = new THREE.DirectionalLight(0xffffff, 1);
dirLight.position.set(5, 10, 5);
dirLight.castShadow = true;
// 阴影配置
dirLight.shadow.mapSize.width = 2048;
dirLight.shadow.mapSize.height = 2048;
dirLight.shadow.camera.left = -10;
dirLight.shadow.camera.right = 10;
dirLight.shadow.camera.top = 10;
dirLight.shadow.camera.bottom = -10;
scene.add(dirLight);
// 点光源(灯泡)
const pointLight = new THREE.PointLight(0xffffff, 1, 100);
pointLight.position.set(0, 5, 0);
scene.add(pointLight);
// 在渲染器上启用阴影
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// 在对象上启用
mesh.castShadow = true;
mesh.receiveShadow = true;
5. 纹理:加载纹理
const loader = new THREE.TextureLoader();
// 加载颜色纹理
const colorTexture = loader.load('texture.jpg');
colorTexture.colorSpace = THREE.SRGBColorSpace; // 颜色准确性重要
// 配置纹理
colorTexture.wrapS = THREE.RepeatWrapping;
colorTexture.wrapT = THREE.RepeatWrapping;
colorTexture.repeat.set(4, 4);
// HDR环境贴图
import { RGBELoader } from 'three/addons/loaders/RGBELoader.js';
const rgbeLoader = new RGBELoader();
rgbeLoader.load('environment.hdr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.environment = texture;
scene.background = texture;
});
// 立方体纹理(天空盒)
const cubeLoader = new THREE.CubeTextureLoader();
const cubeTexture = cubeLoader.load([
'px.jpg', 'nx.jpg', // +X, -X
'py.jpg', 'ny.jpg', // +Y, -Y
'pz.jpg', 'nz.jpg' // +Z, -Z
]);
scene.background = cubeTexture;
6. 动画:简单动画
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const loader = new GLTFLoader();
loader.load('model.glb', (gltf) => {
const model = gltf.scene;
scene.add(model);
// 创建动画混合器
const mixer = new THREE.AnimationMixer(model);
// 播放所有动画
gltf.animations.forEach((clip) => {
const action = mixer.clipAction(clip);
action.play();
});
// 在动画循环中更新
const clock = new THREE.Clock();
function animate() {
requestAnimationFrame(animate);
const delta = clock.getDelta();
mixer.update(delta);
renderer.render(scene, camera);
}
animate();
});
// 程序化动画
function animate() {
const time = clock.getElapsedTime();
mesh.rotation.y = time;
mesh.position.y = Math.sin(time) * 0.5;
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
7. 加载器:加载GLTF模型
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';
// 设置Draco压缩支持
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('https://www.gstatic.com/draco/versioned/decoders/1.5.6/');
const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);
// 加载模型
gltfLoader.load('model.glb', (gltf) => {
const model = gltf.scene;
// 启用阴影
model.traverse((child) => {
if (child.isMesh) {
child.castShadow = true;
child.receiveShadow = true;
}
});
// 居中并缩放
const box = new THREE.Box3().setFromObject(model);
const center = box.getCenter(new THREE.Vector3());
model.position.sub(center);
scene.add(model);
});
// 异步/Promise模式
async function loadModel(url) {
return new Promise((resolve, reject) => {
gltfLoader.load(url, resolve, undefined, reject);
});
}
const gltf = await loadModel('model.glb');
scene.add(gltf.scene);
8. 着色器:自定义着色器材质
const material = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
amplitude: { value: 0.5 }
},
vertexShader: `
uniform float time;
uniform float amplitude;
varying vec2 vUv;
void main() {
vUv = uv;
vec3 pos = position;
// 波位移
pos.z += sin(pos.x * 5.0 + time) * amplitude;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
`,
fragmentShader: `
uniform float time;
varying vec2 vUv;
void main() {
vec3 color = vec3(vUv, 0.5 + 0.5 * sin(time));
gl_FragColor = vec4(color, 1.0);
}
`
});
// 在动画循环中更新
function animate() {
material.uniforms.time.value = clock.getElapsedTime();
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
9. 后处理:添加辉光
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);
// 渲染场景通道
const renderPass = new RenderPass(scene, camera);
composer.addPass(renderPass);
// 辉光通道
const bloomPass = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
1.5, // 强度
0.4, // 半径
0.85 // 阈值
);
composer.addPass(bloomPass);
// 使用合成器代替渲染器
function animate() {
requestAnimationFrame(animate);
composer.render(); // 不是renderer.render()
}
// 处理调整大小
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
});
10. 交互:射线投射
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 相机控制
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// 射线投射设置
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onMouseClick(event) {
// 转换鼠标到标准化坐标
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// 从相机射线投射
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
const object = intersects[0].object;
console.log('点击:', object);
console.log('点:', intersects[0].point);
// 高亮选中对象
object.material.emissive.set(0x444444);
}
}
window.addEventListener('click', onMouseClick);
// 在动画循环中更新控制
function animate() {
requestAnimationFrame(animate);
controls.update(); // 如果enableDamping为真则必需
renderer.render(scene, camera);
}
常见模式
适当处置
// 处置几何体、材质、纹理
geometry.dispose();
material.dispose();
texture.dispose();
// 从场景中移除
scene.remove(mesh);
// 处置渲染器
renderer.dispose();
响应式渲染
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
性能优化
- 对重复对象使用实例化(
InstancedMesh) - 启用视锥体剔除(默认启用)
- 处置未使用资源
- 对复杂场景使用适当的LOD(层次细节)
- 通过合并几何体最小化绘制调用
- 限制活动光源(每个光源增加着色器复杂性)
- 使用纹理图集减少纹理切换
版本信息
Three.js 版本: r160+ (2024年1月)
导入格式: ES6模块(three, three/addons/*)
已验证: 2024-01