mcpField
T
threejs-core-scene-graph

threejs-core-scene-graph

github.com/impertio-studio开发23138 次安装30 周前更新
代码仓库

关于 threejs-core-scene-graph

threejs-core-scene-graph 是面向 Three.js 开发者的场景图参考技能,涵盖对象层级、变换、遍历、渲染图层及资源管理注意事项。

主要功能

  1. 01Object3D 层级与变换
  2. 02Scene、Group 和 Mesh 用法
  3. 03遍历与世界矩阵更新
  4. 04用于渲染和射线检测的图层
  5. 05场景雾效与环境设置
  6. 06资源释放注意事项

适用场景

  1. 01组织 Three.js 场景中的对象
  2. 02重新设置父级时保留世界位置
  3. 03在帧内读取世界坐标值
  4. 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 外,安装时一起下载的参考资料和脚本。

.gitkeep
references/
anti-patterns.md
examples.md
methods.md

详细介绍

threejs-core-scene-graph

快速参考

场景图层级结构
类继承自用途
Object3DEventDispatcher所有 3D 对象的基类。提供变换、层级结构和遍历功能
SceneObject3D根容器。添加背景、环境、雾和 overrideMaterial
GroupObject3D无额外功能的语义容器。用于逻辑分组
MeshObject3D几何体 + 材质。场景中的主要可见对象
CameraObject3D视图投影。始终添加到场景中以更新矩阵
LightObject3D照明。始终添加到场景中以进行渲染
Object3D 核心属性
属性类型默认值说明
positionVector3(0,0,0)相对于父对象的局部位置
rotationEuler(0,0,0,'XYZ')局部旋转。与 quaternion 关联——修改其中一个会始终更新另一个
quaternionQuaternion(0,0,0,1)用四元数表示的局部旋转。与 rotation 关联
scaleVector3(1,1,1)局部缩放。非均匀缩放会导致法线失真
visiblebooleantrue当值为 false 时,渲染过程中会跳过该对象及其所有后代对象
layersLayerslayer 0用于选择性渲染和射线检测的 32 位位掩码
castShadowbooleanfalse对象是否投射阴影
receiveShadowbooleanfalse对象是否接收阴影
frustumCulledbooleantrue对于天空盒或必须始终渲染的对象,设为 false
renderOrdernumber0值越大,渲染越晚。用于透明度排序
namestring""易读标签。使用 getObjectByName() 查找
userDataobject{}自定义应用数据字典
标识属性
属性类型说明
uuidstring只读的 RFC 4122 v4 标识符。自动生成
idnumber自动递增的整数。在每个运行时会话中唯一
namestring用户指定。绝不能将其作为唯一标识符
typestring只读的类名(例如,"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(),该方法会递归执行:

  1. 对每个对象调用 updateMatrix()(根据位置/旋转/缩放合成 matrix)
  2. 计算 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
属性类型默认值说明
backgroundColor | Texture | CubeTexture | nullnull场景背景
environmentTexture | nullnull用于所有未设置自身 envMap 的 PBR 材质的 IBL 环境贴图
fogFog | FogExp2 | nullnull场景雾效
overrideMaterialMaterial | nullnull强制所有对象使用此材质
backgroundBlurrinessnumber0背景模糊程度(0-1)
backgroundIntensitynumber1背景亮度乘数
backgroundRotationEuler(0,0,0)背景旋转
environmentIntensitynumber1环境贴图亮度乘数
environmentRotationEuler(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()——它会根据当前位置计算旋转。


参考链接

官方来源

评论

支持 Markdown