Three.js3D图形开发技能 threejs

Three.js 技能库提供构建3D网页体验的全面知识,涵盖场景设置、几何体、材质、照明、纹理、动画、加载器、着色器、后处理和交互等核心领域。适用于WebGL可视化、GLTF模型处理、自定义着色器实现和交互式3D元素开发,关键词包括Three.js、WebGL、3D图形、JavaScript库、前端开发、3D建模、动画效果。

前端开发 0 次安装 0 次浏览 更新于 3/7/2026

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领域:

  1. 基础 - 场景设置、相机、渲染器、Object3D层级
  2. 几何体 - 内置形状、BufferGeometry、自定义几何体、实例化
  3. 材质 - PBR材质、着色器材质、材质属性
  4. 照明 - 光源类型、阴影、环境光照
  5. 纹理 - UV映射、环境贴图、渲染目标
  6. 动画 - 关键帧动画、骨骼动画、动画混合
  7. 加载器 - GLTF/GLB加载、异步模式、缓存
  8. 着色器 - GLSL基础、ShaderMaterial、自定义效果
  9. 后处理 - EffectComposer、辉光、景深、自定义通道
  10. 交互 - 射线投射、相机控制、鼠标/触摸输入

何时加载参考

根据当前任务加载详细参考文件:

  • 基础场景设置、相机、渲染器 → 加载 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

另请参阅