threejs-webgl

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Three.js WebGL/WebGPU Development

Three.js WebGL/WebGPU开发

Overview

概述

Three.js is the industry-standard JavaScript library for creating 3D graphics in web browsers using WebGL and WebGPU. This skill provides comprehensive guidance for building performant, interactive 3D experiences including scenes, cameras, renderers, geometries, materials, lights, textures, and animations.
Three.js是行业标准的JavaScript库,用于在网页浏览器中借助WebGL和WebGPU创建3D图形。本技能为构建高性能、交互式3D体验提供全面指导,涵盖场景、相机、渲染器、几何体、材质、灯光、纹理和动画等内容。

Core Concepts

核心概念

Scene Graph Architecture

场景图架构

Three.js uses a hierarchical scene graph where all 3D objects are organized in a tree structure:
javascript
Scene
├── Camera
├── Lights
│   ├── AmbientLight
│   ├── DirectionalLight
│   └── PointLight
├── Meshes
│   ├── Mesh (Geometry + Material)
│   └── InstancedMesh
└── Groups
Three.js采用层级化的场景图结构,所有3D对象都以树状结构组织:
javascript
Scene
├── Camera
├── Lights
│   ├── AmbientLight
│   ├── DirectionalLight
│   └── PointLight
├── Meshes
│   ├── Mesh (Geometry + Material)
│   └── InstancedMesh
└── Groups

Essential Components

核心组件

Every Three.js application requires these core elements:
  1. Scene: Container for all 3D objects
  2. Camera: Defines the viewing perspective
  3. Renderer: Draws the scene to canvas (WebGL or WebGPU)
  4. Geometry: Defines the shape of objects
  5. Material: Defines the surface appearance
  6. Mesh: Combines geometry and material
每个Three.js应用都需要以下核心元素:
  1. Scene:所有3D对象的容器
  2. Camera:定义观察视角
  3. Renderer:将场景绘制到canvas上(WebGL或WebGPU)
  4. Geometry:定义对象的形状
  5. Material:定义对象的表面外观
  6. Mesh:几何体和材质的组合体

Quick Start Pattern

快速入门模板

Basic Scene Setup

基础场景搭建

javascript
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// Scene, Camera, Renderer
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x333333);

const camera = new THREE.PerspectiveCamera(
  75, // FOV
  window.innerWidth / window.innerHeight, // Aspect ratio
  0.1, // Near clipping plane
  1000 // Far clipping plane
);
camera.position.set(0, 2, 5);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 7.5);
directionalLight.castShadow = true;
scene.add(directionalLight);

// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;

// Animation Loop
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

// Handle Resize
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});
javascript
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// Scene, Camera, Renderer
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x333333);

const camera = new THREE.PerspectiveCamera(
  75, // FOV
  window.innerWidth / window.innerHeight, // Aspect ratio
  0.1, // Near clipping plane
  1000 // Far clipping plane
);
camera.position.set(0, 2, 5);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 7.5);
directionalLight.castShadow = true;
scene.add(directionalLight);

// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;

// Animation Loop
function animate() {
  requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
}

animate();

// Handle Resize
window.addEventListener('resize', () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

WebGPU Setup (Modern Alternative)

WebGPU搭建(现代替代方案)

javascript
import * as THREE from 'three/webgpu';

const renderer = new THREE.WebGPURenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
renderer.toneMapping = THREE.LinearToneMapping;
renderer.toneMappingExposure = 1;
document.body.appendChild(renderer.domElement);
javascript
import * as THREE from 'three/webgpu';

const renderer = new THREE.WebGPURenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setAnimationLoop(animate);
renderer.toneMapping = THREE.LinearToneMapping;
renderer.toneMappingExposure = 1;
document.body.appendChild(renderer.domElement);

Common Patterns

常用实现方案

1. Creating Meshes with Materials

1. 创建带材质的网格

javascript
// Basic Mesh
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({
  color: 0x00ff00,
  roughness: 0.5,
  metalness: 0.5
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// Textured Mesh
const loader = new THREE.TextureLoader();
const texture = loader.load('texture.jpg');
texture.colorSpace = THREE.SRGBColorSpace;

const texturedMaterial = new THREE.MeshStandardMaterial({
  map: texture
});
const mesh = new THREE.Mesh(geometry, texturedMaterial);
scene.add(mesh);
javascript
// Basic Mesh
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({
  color: 0x00ff00,
  roughness: 0.5,
  metalness: 0.5
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// Textured Mesh
const loader = new THREE.TextureLoader();
const texture = loader.load('texture.jpg');
texture.colorSpace = THREE.SRGBColorSpace;

const texturedMaterial = new THREE.MeshStandardMaterial({
  map: texture
});
const mesh = new THREE.Mesh(geometry, texturedMaterial);
scene.add(mesh);

2. Lighting Strategies

2. 灯光配置方案

javascript
// Three-Point Lighting Setup
function setupThreePointLight(scene) {
  // Key Light (Main)
  const keyLight = new THREE.DirectionalLight(0xffffff, 3);
  keyLight.position.set(5, 10, 7.5);
  keyLight.castShadow = true;
  scene.add(keyLight);

  // Fill Light (Softens shadows)
  const fillLight = new THREE.DirectionalLight(0xffffff, 1);
  fillLight.position.set(-5, 5, -5);
  scene.add(fillLight);

  // Rim Light (Edge definition)
  const rimLight = new THREE.DirectionalLight(0xffffff, 0.5);
  rimLight.position.set(0, 5, -10);
  scene.add(rimLight);

  // Ambient (Base illumination)
  const ambient = new THREE.AmbientLight(0x404040, 0.5);
  scene.add(ambient);
}

// Physical Light (Realistic)
const bulbLight = new THREE.PointLight(0xffee88, 1, 100, 2);
bulbLight.power = 1700; // Lumens (100W bulb equivalent)
bulbLight.castShadow = true;
scene.add(bulbLight);

// Hemisphere Light (Sky + Ground)
const hemiLight = new THREE.HemisphereLight(
  0xddeeff, // Sky color
  0x0f0e0d, // Ground color
  0.02
);
scene.add(hemiLight);
javascript
// Three-Point Lighting Setup
function setupThreePointLight(scene) {
  // Key Light (Main)
  const keyLight = new THREE.DirectionalLight(0xffffff, 3);
  keyLight.position.set(5, 10, 7.5);
  keyLight.castShadow = true;
  scene.add(keyLight);

  // Fill Light (Softens shadows)
  const fillLight = new THREE.DirectionalLight(0xffffff, 1);
  fillLight.position.set(-5, 5, -5);
  scene.add(fillLight);

  // Rim Light (Edge definition)
  const rimLight = new THREE.DirectionalLight(0xffffff, 0.5);
  rimLight.position.set(0, 5, -10);
  scene.add(rimLight);

  // Ambient (Base illumination)
  const ambient = new THREE.AmbientLight(0x404040, 0.5);
  scene.add(ambient);
}

// Physical Light (Realistic)
const bulbLight = new THREE.PointLight(0xffee88, 1, 100, 2);
bulbLight.power = 1700; // Lumens (100W bulb equivalent)
bulbLight.castShadow = true;
scene.add(bulbLight);

// Hemisphere Light (Sky + Ground)
const hemiLight = new THREE.HemisphereLight(
  0xddeeff, // Sky color
  0x0f0e0d, // Ground color
  0.02
);
scene.add(hemiLight);

3. Instanced Geometry (Performance)

3. 实例化几何体(性能优化)

javascript
// For rendering thousands of similar objects efficiently
const geometry = new THREE.SphereGeometry(0.1, 16, 16);
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);

const matrix = new THREE.Matrix4();
const color = new THREE.Color();

for (let i = 0; i < 1000; i++) {
  matrix.setPosition(
    Math.random() * 10 - 5,
    Math.random() * 10 - 5,
    Math.random() * 10 - 5
  );
  instancedMesh.setMatrixAt(i, matrix);
  instancedMesh.setColorAt(i, color.setHex(Math.random() * 0xffffff));
}

instancedMesh.instanceMatrix.needsUpdate = true;
scene.add(instancedMesh);
javascript
// For rendering thousands of similar objects efficiently
const geometry = new THREE.SphereGeometry(0.1, 16, 16);
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 1000);

const matrix = new THREE.Matrix4();
const color = new THREE.Color();

for (let i = 0; i < 1000; i++) {
  matrix.setPosition(
    Math.random() * 10 - 5,
    Math.random() * 10 - 5,
    Math.random() * 10 - 5
  );
  instancedMesh.setMatrixAt(i, matrix);
  instancedMesh.setColorAt(i, color.setHex(Math.random() * 0xffffff));
}

instancedMesh.instanceMatrix.needsUpdate = true;
scene.add(instancedMesh);

4. Loading 3D Models (glTF)

4. 加载3D模型(glTF格式)

javascript
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

// Setup loaders
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');

const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);

// Load model
gltfLoader.load('model.glb', (gltf) => {
  const model = gltf.scene;

  // Enable shadows
  model.traverse((child) => {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });

  scene.add(model);

  // Handle animations
  if (gltf.animations.length > 0) {
    const mixer = new THREE.AnimationMixer(model);
    const action = mixer.clipAction(gltf.animations[0]);
    action.play();

    // In animation loop:
    // mixer.update(deltaTime);
  }
});
javascript
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js';

// Setup loaders
const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');

const gltfLoader = new GLTFLoader();
gltfLoader.setDRACOLoader(dracoLoader);

// Load model
gltfLoader.load('model.glb', (gltf) => {
  const model = gltf.scene;

  // Enable shadows
  model.traverse((child) => {
    if (child.isMesh) {
      child.castShadow = true;
      child.receiveShadow = true;
    }
  });

  scene.add(model);

  // Handle animations
  if (gltf.animations.length > 0) {
    const mixer = new THREE.AnimationMixer(model);
    const action = mixer.clipAction(gltf.animations[0]);
    action.play();

    // In animation loop:
    // mixer.update(deltaTime);
  }
});

5. Shadow Configuration

5. 阴影配置

javascript
// Enable shadows on renderer
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // or VSMShadowMap

// Configure light shadows
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.camera.left = -10;
directionalLight.shadow.camera.right = 10;
directionalLight.shadow.camera.top = 10;
directionalLight.shadow.camera.bottom = -10;
directionalLight.shadow.radius = 4;
directionalLight.shadow.blurSamples = 8;

// Objects casting/receiving shadows
mesh.castShadow = true;
mesh.receiveShadow = true;
javascript
// Enable shadows on renderer
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap; // or VSMShadowMap

// Configure light shadows
directionalLight.castShadow = true;
directionalLight.shadow.mapSize.width = 2048;
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.camera.left = -10;
directionalLight.shadow.camera.right = 10;
directionalLight.shadow.camera.top = 10;
directionalLight.shadow.camera.bottom = -10;
directionalLight.shadow.radius = 4;
directionalLight.shadow.blurSamples = 8;

// Objects casting/receiving shadows
mesh.castShadow = true;
mesh.receiveShadow = true;

6. Raycasting (Interaction)

6. 射线检测(交互)

javascript
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;
    object.material.color.set(0xff0000);
  }
}

window.addEventListener('click', onMouseClick);
javascript
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;
    object.material.color.set(0xff0000);
  }
}

window.addEventListener('click', onMouseClick);

Integration Patterns

集成方案

With GSAP for Animation

结合GSAP实现动画

javascript
import gsap from 'gsap';

// Animate camera
gsap.to(camera.position, {
  x: 5,
  y: 3,
  z: 10,
  duration: 2,
  ease: "power2.inOut",
  onUpdate: () => {
    camera.lookAt(scene.position);
  }
});

// Animate mesh properties
gsap.to(mesh.rotation, {
  y: Math.PI * 2,
  duration: 3,
  repeat: -1,
  ease: "none"
});
javascript
import gsap from 'gsap';

// Animate camera
gsap.to(camera.position, {
  x: 5,
  y: 3,
  z: 10,
  duration: 2,
  ease: "power2.inOut",
  onUpdate: () => {
    camera.lookAt(scene.position);
  }
});

// Animate mesh properties
gsap.to(mesh.rotation, {
  y: Math.PI * 2,
  duration: 3,
  repeat: -1,
  ease: "none"
});

With React (see react-three-fiber skill)

结合React(参考react-three-fiber技能)

javascript
// Three.js integrates naturally with React Three Fiber
// Use the react-three-fiber skill for React integration patterns
javascript
// Three.js integrates naturally with React Three Fiber
// Use the react-three-fiber skill for React integration patterns

With Post-Processing

结合后处理

javascript
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(
  new THREE.Vector2(window.innerWidth, window.innerHeight),
  1.5, // strength
  0.4, // radius
  0.85 // threshold
);
composer.addPass(bloomPass);

// In animation loop:
composer.render();
javascript
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(
  new THREE.Vector2(window.innerWidth, window.innerHeight),
  1.5, // strength
  0.4, // radius
  0.85 // threshold
);
composer.addPass(bloomPass);

// In animation loop:
composer.render();

Performance Optimization

性能优化

1. Geometry Reuse

1. 几何体复用

javascript
// Bad: Creates new geometry for each mesh
for (let i = 0; i < 100; i++) {
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}

// Good: Reuse geometry
const sharedGeometry = new THREE.BoxGeometry(1, 1, 1);
for (let i = 0; i < 100; i++) {
  const mesh = new THREE.Mesh(sharedGeometry, material);
  scene.add(mesh);
}
javascript
// Bad: Creates new geometry for each mesh
for (let i = 0; i < 100; i++) {
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const mesh = new THREE.Mesh(geometry, material);
  scene.add(mesh);
}

// Good: Reuse geometry
const sharedGeometry = new THREE.BoxGeometry(1, 1, 1);
for (let i = 0; i < 100; i++) {
  const mesh = new THREE.Mesh(sharedGeometry, material);
  scene.add(mesh);
}

2. Use InstancedMesh for Repeated Objects

2. 重复对象使用InstancedMesh

For hundreds/thousands of identical objects, use
InstancedMesh
(see pattern above).
针对成百上千个相同的对象,可使用
InstancedMesh
(参考上文的实现方案)。

3. Texture Optimization

3. 纹理优化

javascript
// Compress textures
texture.generateMipmaps = true;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;

// Use power-of-two dimensions (512, 1024, 2048)
// Consider texture atlases for multiple small textures
javascript
// Compress textures
texture.generateMipmaps = true;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.magFilter = THREE.LinearFilter;

// Use power-of-two dimensions (512, 1024, 2048)
// Consider texture atlases for multiple small textures

4. Level of Detail (LOD)

4. 细节层次(LOD)

javascript
const lod = new THREE.LOD();
lod.addLevel(highDetailMesh, 0);    // 0-50 units
lod.addLevel(mediumDetailMesh, 50);  // 50-100 units
lod.addLevel(lowDetailMesh, 100);    // 100+ units
scene.add(lod);
javascript
const lod = new THREE.LOD();
lod.addLevel(highDetailMesh, 0);    // 0-50 units
lod.addLevel(mediumDetailMesh, 50);  // 50-100 units
lod.addLevel(lowDetailMesh, 100);    // 100+ units
scene.add(lod);

5. Frustum Culling

5. 视锥体剔除

Three.js automatically culls objects outside the camera's view. Ensure objects have correct bounding spheres:
javascript
mesh.geometry.computeBoundingSphere();
Three.js会自动剔除相机视野外的对象,请确保对象的包围球配置正确:
javascript
mesh.geometry.computeBoundingSphere();

6. Dispose Resources

6. 资源释放

javascript
function disposeScene() {
  scene.traverse((object) => {
    if (object.geometry) object.geometry.dispose();
    if (object.material) {
      if (Array.isArray(object.material)) {
        object.material.forEach(material => material.dispose());
      } else {
        object.material.dispose();
      }
    }
  });
  renderer.dispose();
}
javascript
function disposeScene() {
  scene.traverse((object) => {
    if (object.geometry) object.geometry.dispose();
    if (object.material) {
      if (Array.isArray(object.material)) {
        object.material.forEach(material => material.dispose());
      } else {
        object.material.dispose();
      }
    }
  });
  renderer.dispose();
}

Best Practices

最佳实践

1. Use Animation Clocks for Consistent Timing

1. 使用动画时钟保证时序一致

javascript
const clock = new THREE.Clock();

function animate() {
  const deltaTime = clock.getDelta();
  const elapsedTime = clock.getElapsedTime();

  // Use deltaTime for frame-independent animations
  mesh.rotation.y += deltaTime * Math.PI * 0.5; // 90° per second

  renderer.render(scene, camera);
}
javascript
const clock = new THREE.Clock();

function animate() {
  const deltaTime = clock.getDelta();
  const elapsedTime = clock.getElapsedTime();

  // Use deltaTime for frame-independent animations
  mesh.rotation.y += deltaTime * Math.PI * 0.5; // 90° per second

  renderer.render(scene, camera);
}

2. Camera Setup Guidelines

2. 相机设置指南

  • FOV: 45-75° for most applications
  • Near plane: As far as possible (avoid z-fighting)
  • Far plane: As close as possible (precision)
  • Aspect ratio: Always match canvas dimensions
  • FOV:大多数应用建议设置为45-75°
  • 近裁剪面:尽可能远(避免Z轴冲突)
  • 远裁剪面:尽可能近(保证精度)
  • 宽高比:始终与canvas尺寸保持一致

3. Material Selection

3. 材质选择

  • MeshBasicMaterial: Unlit, flat colors (debugging, UI)
  • MeshLambertMaterial: Cheap diffuse lighting (mobile)
  • MeshPhongMaterial: Specular highlights (older standard)
  • MeshStandardMaterial: PBR, realistic (recommended)
  • MeshPhysicalMaterial: Advanced PBR (clearcoat, transmission)
  • MeshBasicMaterial:无光照、纯色(用于调试、UI)
  • MeshLambertMaterial:低成本漫反射光照(移动端适用)
  • MeshPhongMaterial:支持高光(旧标准)
  • MeshStandardMaterial:PBR物理渲染,效果真实(推荐)
  • MeshPhysicalMaterial:高级PBR(支持清漆、透射效果)

4. Coordinate System

4. 坐标系

  • Three.js uses right-handed coordinate system
  • +Y is up, +Z is toward camera, +X is right
  • Rotations use radians (Math.PI = 180°)
  • Three.js使用右手坐标系
  • +Y轴为向上方向,+Z轴朝向相机,+X轴为向右方向
  • 旋转使用弧度制(Math.PI = 180°)

5. Scene Organization

5. 场景组织

javascript
// Group related objects
const building = new THREE.Group();
building.add(walls, roof, windows);
scene.add(building);

// Use meaningful names
mesh.name = 'player-character';
const found = scene.getObjectByName('player-character');
javascript
// Group related objects
const building = new THREE.Group();
building.add(walls, roof, windows);
scene.add(building);

// Use meaningful names
mesh.name = 'player-character';
const found = scene.getObjectByName('player-character');

Common Pitfalls

常见问题

1. Not Updating Aspect Ratio on Resize

1. 窗口调整大小时未更新宽高比

Always update camera aspect ratio and projection matrix when window resizes.
窗口大小变化时,请务必更新相机的宽高比和投影矩阵。

2. Creating New Objects in Animation Loop

2. 在动画循环中创建新对象

javascript
// Bad: Memory leak
function animate() {
  const geometry = new THREE.BoxGeometry(); // Created every frame!
  // ...
}

// Good: Create once outside loop
const geometry = new THREE.BoxGeometry();
function animate() {
  // Reuse geometry
}
javascript
// Bad: Memory leak
function animate() {
  const geometry = new THREE.BoxGeometry(); // Created every frame!
  // ...
}

// Good: Create once outside loop
const geometry = new THREE.BoxGeometry();
function animate() {
  // Reuse geometry
}

3. Forgetting to Enable Shadows

3. 忘记开启阴影

Remember to enable shadows on renderer, lights, and objects.
需要在渲染器、灯光、对应对象上都开启阴影配置才能正常显示阴影。

4. Z-Fighting (Flickering)

4. Z轴冲突(闪烁问题)

  • Increase near plane distance
  • Decrease far plane distance
  • Avoid overlapping coplanar surfaces
  • Use
    material.polygonOffset = true
    with
    material.polygonOffsetFactor
  • 增加近裁剪面距离
  • 减小远裁剪面距离
  • 避免重叠的共面
  • 可配置
    material.polygonOffset = true
    搭配
    material.polygonOffsetFactor
    解决

5. Color Space Issues

5. 颜色空间问题

javascript
// Always set color space for textures
texture.colorSpace = THREE.SRGBColorSpace;

// Set renderer output encoding
renderer.outputColorSpace = THREE.SRGBColorSpace;
javascript
// Always set color space for textures
texture.colorSpace = THREE.SRGBColorSpace;

// Set renderer output encoding
renderer.outputColorSpace = THREE.SRGBColorSpace;

6. Not Disposing Resources

6. 未释放资源

Always call
.dispose()
on geometries, materials, textures, and renderers when no longer needed.
不再使用的几何体、材质、纹理、渲染器都需要调用
.dispose()
方法释放资源。

Resources

资源

This skill includes bundled resources to accelerate Three.js development:
本技能包含打包资源,可加速Three.js开发:

references/

references/

  • api_reference.md
    : Quick API reference for core classes (Scene, Camera, Renderer, etc.)
  • materials_guide.md
    : Comprehensive material types and properties
  • optimization_checklist.md
    : Performance optimization strategies
  • api_reference.md
    :核心类(Scene、Camera、Renderer等)的快速API参考
  • materials_guide.md
    :全面的材质类型和属性说明
  • optimization_checklist.md
    :性能优化策略清单

scripts/

scripts/

  • setup_scene.py
    : Generate boilerplate Three.js scene setup code
  • texture_optimizer.py
    : Batch optimize textures for web (resize, compress)
  • gltf_validator.py
    : Validate glTF models before use
  • setup_scene.py
    :生成Three.js场景搭建的样板代码
  • texture_optimizer.py
    :批量优化网页适用纹理(调整尺寸、压缩)
  • gltf_validator.py
    :使用前验证glTF模型

assets/

assets/

  • starter_scene/
    : Complete HTML/JS boilerplate project
  • shaders/
    : Custom GLSL shader examples (vertex, fragment)
  • hdri/
    : Environment maps for PBR lighting
  • draco/
    : DRACO decoder for compressed models
  • starter_scene/
    :完整的HTML/JS样板项目
  • shaders/
    :自定义GLSL着色器示例(顶点着色器、片元着色器)
  • hdri/
    :用于PBR光照的环境贴图
  • draco/
    :用于压缩模型的DRACO解码器

Advanced Topics

高级主题

Custom Shaders (GLSL)

自定义着色器(GLSL)

javascript
const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0.0 },
    uColor: { value: new THREE.Color(0x00ff00) }
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(uColor * vUv.x, 1.0);
    }
  `
});
javascript
const material = new THREE.ShaderMaterial({
  uniforms: {
    uTime: { value: 0.0 },
    uColor: { value: new THREE.Color(0x00ff00) }
  },
  vertexShader: `
    varying vec2 vUv;
    void main() {
      vUv = uv;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform float uTime;
    uniform vec3 uColor;
    varying vec2 vUv;
    void main() {
      gl_FragColor = vec4(uColor * vUv.x, 1.0);
    }
  `
});

Render Targets (Render-to-Texture)

渲染目标(离屏渲染到纹理)

javascript
const renderTarget = new THREE.WebGLRenderTarget(512, 512);

// Render scene to texture
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.setRenderTarget(null);

// Use texture
const material = new THREE.MeshBasicMaterial({
  map: renderTarget.texture
});
javascript
const renderTarget = new THREE.WebGLRenderTarget(512, 512);

// Render scene to texture
renderer.setRenderTarget(renderTarget);
renderer.render(scene, camera);
renderer.setRenderTarget(null);

// Use texture
const material = new THREE.MeshBasicMaterial({
  map: renderTarget.texture
});

GPU Computation (GPGPU)

GPU计算(GPGPU)

Use
GPUComputationRenderer
for particle simulations, cloth physics, etc.
可使用
GPUComputationRenderer
实现粒子模拟、布料物理等效果。

When to Use This Skill

何时使用该技能

Use this skill when:
  • Building interactive 3D web experiences
  • Creating product configurators or visualizers
  • Implementing WebGL/WebGPU rendering
  • Working with 3D models, scenes, or animations
  • Optimizing Three.js performance
  • Integrating Three.js with other libraries (GSAP, React, etc.)
  • Debugging Three.js rendering issues
For React integration, use the react-three-fiber skill. For animation, combine with the gsap-scrolltrigger skill. For UI animations, use the motion-framer skill.
符合以下场景时可使用本技能:
  • 构建交互式3D网页体验
  • 创建产品配置器或可视化工具
  • 实现WebGL/WebGPU渲染功能
  • 处理3D模型、场景或动画相关需求
  • 优化Three.js性能
  • 将Three.js与其他库(GSAP、React等)集成
  • 调试Three.js渲染问题
如需React集成,请使用react-three-fiber技能。 如需动画相关能力,可搭配gsap-scrolltrigger技能使用。 如需UI动画,可使用motion-framer技能。