SceneUtils 有七个静态方法
- createMeshesFromInstancedMesh ( instancedMesh : InstancedMesh ) : Group createMeshesFromInstancedMesh 是 Three.js 中的一个工具方法,用于将一个 InstancedMesh 对象分解为多个单独的 Mesh 对象,并返回一个包含这些 Mesh 的 Group 对象。
- 需求背景:
- InstancedMesh 在性能上非常高效,因为它可以通过共享几何体和材质渲染多个实例。然而,在某些情况下,你可能需要将实例化的网格分解为独立的 Mesh 对象(例如为了单独控制某些实例的属性)。
- 应用场景:
- 动态调整实例的材质、变换或其他属性。
- 需要将 InstancedMesh 转换为普通的 Mesh 进行编辑。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 5);
const dummy = new THREE.Object3D();
for (let i = 0; i < 5; i++) {
dummy.position.set(i * 2, 0, 0);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
scene.add(instancedMesh);
const group = createMeshesFromInstancedMesh(instancedMesh);
scene.remove(instancedMesh);
scene.add(group);
- createMeshesFromMultiMaterialMesh ( mesh : Mesh ) : Group createMeshesFromMultiMaterialMesh 是一个工具方法,用于将具有多材质的 Mesh 对象分解为多个单独的 Mesh 对象,每个 Mesh 对应一个材质,并将它们包含在一个 Group 对象中。
- 需求背景:
- 在 Three.js 中,某些复杂模型可能会使用多材质(Material[])渲染几何体的不同部分。默认情况下,这些材质通过索引映射到几何体的各个部分。但在某些情况下,你可能需要将多材质对象分解为独立的 Mesh,以便对其进行单独控制。
- 应用场景:
- 独立控制每个材质部分的可见性、变换或其他属性。
- 分析或编辑多材质几何体的结构。
- 需要将多材质对象拆分为多个对象用于动画或交互。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
new THREE.MeshBasicMaterial({ color: 0xff0000 }),
new THREE.MeshBasicMaterial({ color: 0x00ff00 }),
new THREE.MeshBasicMaterial({ color: 0x0000ff })
];
const multiMaterialMesh = new THREE.Mesh(geometry, materials);
const group = SceneUtils.createMeshesFromMultiMaterialMesh(multiMaterialMesh);
scene.add(group);
- createMultiMaterialObject ( geometry : BufferGeometry, materials : Array ) : Group createMultiMaterialObject 用于将一个几何体(BufferGeometry)与多个材质(Material[])结合,创建一个包含多个子 Mesh 的 Group 对象,每个子 Mesh 使用相同的几何体但应用不同的材质。
- 需求背景:
- 有时我们希望为同一个几何体同时显示多个渲染效果(如一个材质显示实体颜色,另一个显示线框)。而直接为几何体指定多个材质并不能满足这个需求,因为它只能按照 geometry.groups 来分配材质。此时可以利用 createMultiMaterialObject 方法快速生成多个材质组合。
- 应用场景:
- 创建多材质对象用于显示多种渲染效果(如线框 + 实体)。
- 用于调试几何体不同渲染表现。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const materials = [
new THREE.MeshBasicMaterial({ color: 0x00ff00 }),
new THREE.MeshBasicMaterial({ wireframe: true, color: 0x000000 })
];
const multiMaterialObject = SceneUtils.createMultiMaterialObject(geometry, materials);
scene.add(multiMaterialObject);

- sortInstancedMesh ( mesh : InstancedMesh, compareFn : Function ) : undefined sortInstancedMesh 方法用于对 InstancedMesh 的实例进行排序。排序的依据是提供的比较函数(compareFn),它可以基于实例的矩阵或其他属性进行自定义逻辑排序。
- 需求背景:
- 在使用 InstancedMesh 时,所有实例的绘制顺序默认由实例的创建顺序决定。但在某些情况下(如按距离排序以实现透明度正确性、按属性分组渲染等),需要自定义实例的顺序。此方法通过重新排序 instanceMatrix 和其他实例数据,满足这一需求。
- 应用场景:
- 对实例按距离排序,避免透明物体渲染错误。
- 按实例属性(如颜色或大小)排序以分组显示。
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const instancedMesh = new THREE.InstancedMesh(geometry, material, 5);
const dummy = new THREE.Object3D();
for (let i = 0; i < 5; i++) {
dummy.position.set(Math.random() * 10, Math.random() * 10, Math.random() * 10);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
}
const cameraPosition = new THREE.Vector3(0, 0, 0);
SceneUtils.sortInstancedMesh(instancedMesh, (indexA, indexB) => {
const matrixA = new THREE.Matrix4();
const matrixB = new THREE.Matrix4();
instancedMesh.getMatrixAt(indexA, matrixA);
instancedMesh.getMatrixAt(indexB, matrixB);
const positionA = new THREE.Vector3().setFromMatrixPosition(matrixA);
const positionB = new THREE.Vector3().setFromMatrixPosition(matrixB);
return positionA.distanceTo(cameraPosition) - positionB.distanceTo(cameraPosition);
});
scene.add(instancedMesh);
- traverseGenerator ( object : Object3D ) : Generator traverseGenerator 方法是一个生成器函数,用于遍历一个 Object3D 对象及其所有子对象。它通过 Generator 的方式,按深度优先顺序(从父到子)逐个返回场景树中的每个对象。
- 需求背景:
- 在 Three.js 场景中,Object3D 是场景树的基础结构,包含子对象的层级关系。Three.js 提供了 Object3D.traverse() 方法用于遍历场景树,但该方法采用回调函数的形式处理对象。traverseGenerator 则通过生成器提供了更灵活的迭代方式,可以与现代 for...of 语法结合使用。
- 应用场景:
- 按顺序访问场景中的所有对象。
- 筛选或操作特定类型的对象(如仅处理 Mesh)。
- 实现异步或暂停的场景遍历。
const group = new THREE.Group();
const mesh1 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({ color: 0xff0000 }));
const mesh2 = new THREE.Mesh(new THREE.SphereGeometry(), new THREE.MeshBasicMaterial({ color: 0x00ff00 }));
group.add(mesh1);
scene.add(group);
scene.add(mesh2);
for (const obj of SceneUtils.traverseGenerator(scene)) {
if (obj instanceof THREE.Mesh) {
console.log('Found a mesh:', obj);
} else {
console.log('Found an object:', obj);
}
}
- traverseVisibleGenerator ( object : Object3D ) : Generator traverseVisibleGenerator 是一个生成器函数,用于遍历 Object3D 对象及其所有子对象,但仅包含 visible 属性为 true 的对象。它按深度优先顺序(从父到子)返回场景树中的可见对象。
- 需求背景:
- 在场景树中,Object3D 的 visible 属性控制对象及其子对象是否渲染。如果你需要操作或检查当前可见的对象(如更新它们的状态、执行特定逻辑等),使用 traverseVisibleGenerator 可以高效地筛选并遍历这些对象。
- 应用场景:
- 更新或修改场景中当前可见对象的属性。
- 查找特定类型的可见对象(如渲染中的 Mesh)。
- 优化场景逻辑,避免处理不可见对象。
const group = new THREE.Group();
const mesh1 = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({ color: 0xff0000 }));
const mesh2 = new THREE.Mesh(new THREE.SphereGeometry(), new THREE.MeshBasicMaterial({ color: 0x00ff00 }));
group.add(mesh1);
group.visible = false;
scene.add(group);
scene.add(mesh2);
for (const obj of SceneUtils.traverseVisibleGenerator(scene)) {
if (obj instanceof THREE.Mesh) {
obj.material.color.set(0x0000ff);
console.log('Modified visible mesh:', obj);
} else {
console.log('Visible object:', obj);
}
}
- traverseAncestorsGenerator ( object : Object3D ) : Generator traverseAncestorsGenerator 是一个生成器函数,用于遍历 Object3D 对象的所有父对象(祖先对象)。它会返回给定对象的祖先链中的每一个对象,直到场景树的根(通常是 null 或 undefined)为止。
- 需求背景:
- 在 Three.js 中,Object3D 对象是场景图中元素的基础单位,它们通过父子关系构成层级结构。使用 traverseAncestorsGenerator 方法可以轻松访问某个对象的所有父对象。该方法是基于生成器实现的,能有效控制遍历过程。
- 应用场景:
- 查找某个对象的所有祖先,并对这些祖先进行操作。
- 访问对象所在层级结构中的所有父级对象,如 Group 和 Scene。
- 获取对象的祖先信息,以便做条件判断(例如,确定对象是否位于某个特定的 Group 内)。
const group1 = new THREE.Group();
const group2 = new THREE.Group();
const mesh = new THREE.Mesh(new THREE.BoxGeometry(), new THREE.MeshBasicMaterial({ color: 0xff0000 }));
group2.add(mesh);
group1.add(group2);
scene.add(group1);
for (const ancestor of SceneUtils.traverseAncestorsGenerator(mesh)) {
console.log('Ancestor:', ancestor.constructor.name);
}