关于 threejs-core-scene-graph
threejs-core-scene-graph 是面向 Three.js 开发者的场景图参考技能,涵盖对象层级、变换、遍历、渲染图层及资源管理注意事项。
主要功能
- 01Object3D 层级与变换
- 02Scene、Group 和 Mesh 用法
- 03遍历与世界矩阵更新
- 04用于渲染和射线检测的图层
- 05场景雾效与环境设置
- 06资源释放注意事项
适用场景
- 01组织 Three.js 场景中的对象
- 02重新设置父级时保留世界位置
- 03在帧内读取世界坐标值
- 04安全管理对象和 GPU 资源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ impertio-studio/ three.js-claude-skill-package --skill threejs-core-scene-graph安装后在 Claude Code 中输入/threejs-core-scene-graph确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitkeepreferences/anti-patterns.mdexamples.mdmethods.md详细介绍
threejs-core-scene-graph
快速参考
场景图层级结构
| 类 | 继承自 | 用途 |
|---|---|---|
Object3D | EventDispatcher | 所有 3D 对象的基类。提供变换、层级结构和遍历功能 |
Scene | Object3D | 根容器。添加背景、环境、雾和 overrideMaterial |
Group | Object3D | 无额外功能的语义容器。用于逻辑分组 |
Mesh | Object3D | 几何体 + 材质。场景中的主要可见对象 |
Camera | Object3D | 视图投影。始终添加到场景中以更新矩阵 |
Light | Object3D | 照明。始终添加到场景中以进行渲染 |
Object3D 核心属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
position | Vector3 | (0,0,0) | 相对于父对象的局部位置 |
rotation | Euler | (0,0,0,'XYZ') | 局部旋转。与 quaternion 关联——修改其中一个会始终更新另一个 |
quaternion | Quaternion | (0,0,0,1) | 用四元数表示的局部旋转。与 rotation 关联 |
scale | Vector3 | (1,1,1) | 局部缩放。非均匀缩放会导致法线失真 |
visible | boolean | true | 当值为 false 时,渲染过程中会跳过该对象及其所有后代对象 |
layers | Layers | layer 0 | 用于选择性渲染和射线检测的 32 位位掩码 |
castShadow | boolean | false | 对象是否投射阴影 |
receiveShadow | boolean | false | 对象是否接收阴影 |
frustumCulled | boolean | true | 对于天空盒或必须始终渲染的对象,设为 false |
renderOrder | number | 0 | 值越大,渲染越晚。用于透明度排序 |
name | string | "" | 易读标签。使用 getObjectByName() 查找 |
userData | object | {} | 自定义应用数据字典 |
标识属性
| 属性 | 类型 | 说明 |
|---|---|---|
uuid | string | 只读的 RFC 4122 v4 标识符。自动生成 |
id | number | 自动递增的整数。在每个运行时会话中唯一 |
name | string | 用户指定。绝不能将其作为唯一标识符 |
type | string | 只读的类名(例如,"Mesh"、"Group") |
重要警告
绝不要直接修改 children 数组——始终使用 add()、remove()、clear() 或 attach()。直接修改会破坏内部记录(父对象引用、事件分发)。
绝不要在 traverse() 期间修改 children 数组——先收集对象,再在遍历完成后修改。在遍历期间添加对象会导致不可预测的迭代行为。
绝不要在重新设置父对象时使用 add(),否则对象无法保持其世界位置——始终改用 attach()。add() 保留局部变换;attach() 保留世界变换。
绝不要在同一帧中更改位置、旋转或缩放后,未先调用 updateWorldMatrix(true, false) 就读取 matrixWorld——直到下一次渲染或显式更新前,世界矩阵都是过期的。
绝不要在未手动释放的情况下将 Three.js 对象存储在 userData 中——dispose() 不会自动清理 userData。
绝不要在移除对象时忘记释放纹理、几何体和材质——remove() 和 clear() 只会将对象从场景图中分离,不会释放 GPU 内存。
层级结构方法
add() 与 attach()——关键区别
import { Scene, Group, Mesh, BoxGeometry, MeshStandardMaterial } from 'three';
const scene = new Scene();
const groupA = new Group();
const groupB = new Group();
groupA.position.set(10, 0, 0);
groupB.position.set(0, 5, 0);
scene.add(groupA, groupB);
const mesh = new Mesh(new BoxGeometry(), new MeshStandardMaterial());
mesh.position.set(0, 0, 0);
groupA.add(mesh);
// mesh world position = (10, 0, 0) -- inherited from groupA
// WRONG: add() preserves LOCAL transform -- mesh jumps to (0, 5, 0) world
groupB.add(mesh); // auto-removes from groupA first
// CORRECT: attach() preserves WORLD transform -- mesh stays at (10, 0, 0) visually
groupA.add(mesh); // reset
groupB.attach(mesh); // mesh.position is recalculated to maintain world position
remove()、removeFromParent()、clear()
// Remove specific children
group.remove(meshA, meshB);
// Remove self from parent (safe when parent is null)
mesh.removeFromParent();
// Remove ALL children -- ALWAYS prefer over manual iteration
group.clear();
**边缘情况:**如果对象不是子对象,remove() 绝不会抛出异常——它会静默无操作。
遍历
// Depth-first traversal of ALL descendants
scene.traverse((object) => {
if (object.isMesh) {
object.castShadow = true;
}
});
// Skip invisible objects and their subtrees
scene.traverseVisible((object) => {
// only visits objects where visible === true
});
// Walk UP to root (does NOT include the starting object)
mesh.traverseAncestors((ancestor) => {
console.log(ancestor.name);
});
// Find by name, id, or arbitrary property
const wall = scene.getObjectByName('north-wall');
const obj = scene.getObjectById(42);
const selectable = scene.getObjectByProperty('userData', { selectable: true });
**性能:**所有搜索方法的复杂度均为 O(n)。如果需要频繁查找,务必缓存引用。
矩阵系统
自动模式(默认)
渲染器会在每次渲染前对场景调用 updateMatrixWorld(),该方法会递归执行:
- 对每个对象调用
updateMatrix()(根据位置/旋转/缩放合成matrix) - 计算
matrixWorld = parent.matrixWorld * matrix
手动模式(性能优化)
// For static objects -- skip per-frame matrix recomputation
object.matrixAutoUpdate = false;
object.matrix.compose(position, quaternion, scale);
object.matrixWorldNeedsUpdate = true;
在帧中途读取世界空间值
import { Vector3, Quaternion } from 'three';
object.position.set(10, 0, 0);
object.updateWorldMatrix(true, false); // update parents first
const worldPos = new Vector3();
object.getWorldPosition(worldPos);
const worldQuat = new Quaternion();
object.getWorldQuaternion(worldQuat);
const worldScale = new Vector3();
object.getWorldScale(worldScale);
const worldDir = new Vector3();
object.getWorldDirection(worldDir);
坐标转换
// MUTATION WARNING: both methods modify the input vector in-place
const localPoint = new Vector3(5, 0, 0);
object.localToWorld(localPoint); // localPoint is now in world coordinates
const worldPoint = new Vector3(15, 3, 0);
object.worldToLocal(worldPoint); // worldPoint is now in object's local coordinates
Scene 类
import { Scene, Color, Fog, FogExp2, TextureLoader } from 'three';
const scene = new Scene();
scene.background = new Color(0x222222); // solid color
scene.environment = hdrTexture; // IBL for all PBR materials
scene.environmentIntensity = 1.5; // boost environment lighting
scene.environmentRotation.set(0, Math.PI, 0); // rotate environment
scene.fog = new Fog(0xcccccc, 10, 100); // linear fog
scene.overrideMaterial = depthMaterial; // debug: force all objects to one material
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
background | Color | Texture | CubeTexture | null | null | 场景背景 |
environment | Texture | null | null | 用于所有未设置自身 envMap 的 PBR 材质的 IBL 环境贴图 |
fog | Fog | FogExp2 | null | null | 场景雾效 |
overrideMaterial | Material | null | null | 强制所有对象使用此材质 |
backgroundBlurriness | number | 0 | 背景模糊程度(0-1) |
backgroundIntensity | number | 1 | 背景亮度乘数 |
backgroundRotation | Euler | (0,0,0) | 背景旋转 |
environmentIntensity | number | 1 | 环境贴图亮度乘数 |
environmentRotation | Euler | (0,0,0) | 环境贴图旋转 |
Fog
Fog(线性插值)
import { Fog } from 'three';
scene.fog = new Fog(0xffffff, 10, 200); // color, near, far
FogExp2(指数密度)
import { FogExp2 } from 'three';
scene.fog = new FogExp2(0xffffff, 0.01); // color, density
材质交互: 每种材质都有一个 fog 属性(默认值:true)。ShaderMaterial 和 RawShaderMaterial 的默认值为 fog: false——对于自定义着色器,必须设置 fog: true 并手动包含雾效着色器代码块,才能让其响应雾效。
Group
Group 扩展了 Object3D,但没有增加任何功能。它纯粹是一个用于组织对象的语义容器:
import { Group } from 'three';
const buildingGroup = new Group();
buildingGroup.name = 'building-01';
buildingGroup.add(walls, roof, foundation);
scene.add(buildingGroup);
// Transform all children together
buildingGroup.position.set(50, 0, 0);
buildingGroup.rotation.y = Math.PI / 4;
Mesh
Mesh 将 BufferGeometry 与 Material 组合起来,创建可见表面:
import { Mesh, BoxGeometry, MeshStandardMaterial } from 'three';
const mesh = new Mesh(
new BoxGeometry(1, 1, 1),
new MeshStandardMaterial({ color: 0x00ff00 })
);
// Multi-material with geometry groups
const materials = [materialA, materialB];
geometry.addGroup(0, 36, 0); // start, count, materialIndex
geometry.addGroup(36, 36, 1);
const multiMesh = new Mesh(geometry, materials);
// Morph targets
mesh.morphTargetInfluences[0] = 0.5; // blend between base and morph target
Layers 系统
用于选择性渲染和射线投射的 32 位位掩码系统:
import { Layers } from 'three';
// Objects are on layer 0 by default
mesh.layers.set(1); // ONLY layer 1 (removes from layer 0)
mesh.layers.enable(2); // add layer 2 (keep layer 1)
mesh.layers.disable(1); // remove layer 1
mesh.layers.toggle(3); // flip layer 3
// Camera renders only objects with overlapping layers
camera.layers.enable(1); // camera now sees layers 0 AND 1
// Test overlap
const visible = camera.layers.test(mesh.layers); // true if any layer overlaps
使用场景:
- 第 0 层:默认可见对象
- 第 1 层:辅助对象/控件(在生产环境的摄像机上禁用)
- 第 2 层:仅用于泛光的对象(选择性后期处理)
- 第 3-31 层:自定义(碰撞组、选择集、LOD 组)
lookAt() 行为差异
// Camera: points NEGATIVE-Z toward target (looks AT the target)
camera.position.set(0, 5, 10);
camera.lookAt(0, 0, 0);
// Non-camera objects: points POSITIVE-Z toward target
mesh.lookAt(targetPosition);
设置 position 后,务必调用 lookAt()——它会根据当前位置计算旋转。
参考链接
- references/methods.md -- 完整的 Object3D、Scene、Group、Mesh、Layers API 签名
- references/examples.md -- 常见场景图操作的可运行代码示例
- references/anti-patterns.md -- 场景图管理中应避免的做法
官方来源
- https://threejs.org/docs/#api/en/core/Object3D
- https://threejs.org/docs/#api/en/scenes/Scene
- https://threejs.org/docs/#api/en/scenes/Fog
- https://threejs.org/docs/#api/en/scenes/FogExp2
- https://threejs.org/docs/#api/en/objects/Group
- https://threejs.org/docs/#api/en/objects/Mesh
- https://threejs.org/docs/#api/en/core/Layers