
在使用 three.js 的过程中,我们经常会遇到这样的需求:
-
有些物体 只想让某个相机看到
-
有些辅助线、调试对象 不想被最终渲染
-
多相机渲染时,希望 不同相机关注不同的物体
-
做选中 / 拾取时,只想检测部分物体
three.js 并没有提供"分组渲染开关"这样的显式 API,但其实它内部提供了一套非常轻量、但功能强大的机制 ------ Layers(层)。
这篇文章将从概念、原理、用法、常见误区、实战场景几个方面,完整讲清 three.js 的 Layers。
一、什么是 Layers?
Layers 是 three.js 中用于控制对象是否会被相机看到的一套机制。
一句话总结:
只有当「物体的 layer」和「相机的 layer」有交集时,物体才会被渲染
一个直观的类比(非常重要)
你可以把 Layers 理解为:
"物体和相机身上贴的标签"
-
物体:贴了哪些标签
-
相机:只看哪些标签
只有标签匹配,物体才会被看到。
二、Layers 的底层结构:其实是一个位掩码
three.js 的 Layers 本质上是一个 32 位的位掩码(bitmask)。
javascript
object.layers.mask // number
camera.layers.mask // number
-
three.js 最多支持 32 个 layer
-
layer 编号范围是:
0 ~ 31 -
每一位表示是否属于某一层
默认情况
javascript
layer 0:开启
layer 1~31:关闭
也就是说:
-
所有 Object3D 默认都在 layer 0
-
所有 Camera 默认也只看 layer 0
所以你平时不用 layers,也能正常渲染
三、一个最基础的示意图
javascript
┌─────────────┐ ┌─────────────┐
│ Object A │ │ Object B │
│ layer 0 │ │ layer 1 │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌────────────────────────────────────┐
│ Camera │
│ enabled: layer 0 │
└────────────────────────────────────┘
结果:
-
Object A ✅ 可见
-
Object B ❌ 不可见
四、Layers 的常用 API
1️⃣ 设置物体所在的层
javascript
mesh.layers.set(1); // 只属于 layer 1
⚠️ 注意:set 会清空原有层
2️⃣ 追加一个 layer(常用)
javascript
mesh.layers.enable(2); // 同时属于 layer 0 和 2
3️⃣ 移除某个 layer
javascript
mesh.layers.disable(0);
4️⃣ 相机只渲染某一层
javascript
camera.layers.set(1);
5️⃣ 判断 layer 是否匹配(底层逻辑)
javascript
object.layers.test(camera.layers);
只有返回 true,物体才会被渲染。
五、渲染阶段 Layers 到底发生在什么时候?
这是一个非常容易被忽略,但非常关键的点。
three.js 在渲染时,逻辑大致是:
javascript
scene.traverse(object)
└─ if object.layers.test(camera.layers)
└─ push 到渲染队列
也就是说:
Layers 是在"渲染收集阶段"生效的
而不是在 GPU 阶段
带来的好处
-
几乎 没有性能开销
-
比 visible = false 更"底层"
-
对拾取、辅助相机特别友好
六、一个最经典的例子:主相机 + 辅助相机
场景需求
-
主相机:渲染正常场景
-
辅助相机:只渲染辅助线 / Gizmo / 调试物体
javascript
// 主相机
const mainCamera = new THREE.PerspectiveCamera();
mainCamera.layers.enable(0);
// 辅助相机
const helperCamera = new THREE.PerspectiveCamera();
helperCamera.layers.set(1);
// 普通物体
mesh.layers.set(0);
// 辅助线
helperLine.layers.set(1);
渲染流程
javascript
renderer.render(scene, mainCamera);
renderer.render(scene, helperCamera);
结构示意图
七、Layers 和 visible 的区别(重点)
| 对比点 | layers | visible |
|---|---|---|
| 是否参与遍历 | ❌ | ❌ |
| 是否被相机控制 | ✅ | ❌ |
| 是否支持多相机 | ✅ | ❌ |
| 语义 | "谁能看到" | "是否存在" |
一个非常重要的结论
visible 更像是"物体存在与否"
layers 更像是"谁能看到它"
八、Layers 在 Raycaster(拾取)中的用法
这是 layers 的一个高级但极其实用的用法。
javascript
raycaster.layers.set(1);
此时:
-
Raycaster 只会检测 layer 1 的物体
-
其他物体直接被忽略
常见应用
-
只拾取可交互物体
-
忽略背景 / 装饰模型
-
点云拾取时分层处理
九、一个容易踩的坑(很多人中招)
❌ 误区:以为 set 是"追加"
javascript
mesh.layers.set(1);
mesh.layers.set(2);
结果:
-
mesh 只在 layer 2
-
layer 1 被清掉了
✅ 正确方式
javascript
mesh.layers.set(1);
mesh.layers.enable(2);
十、一个完整的小 Demo(可直接跑)
javascript
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
60,
window.innerWidth / window.innerHeight,
0.1,
1000
);
// 只看 layer 1
camera.layers.set(1);
const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
// 红色立方体(不可见)
const cube1 = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshBasicMaterial({ color: 'red' })
);
cube1.layers.set(0);
scene.add(cube1);
// 绿色立方体(可见)
const cube2 = new THREE.Mesh(
new THREE.BoxGeometry(),
new THREE.MeshBasicMaterial({ color: 'green' })
);
cube2.layers.set(1);
cube2.position.x = 2;
scene.add(cube2);
renderer.render(scene, camera);
十一、什么时候应该用 Layers?
✅ 推荐使用场景:
-
多相机渲染
-
辅助对象 / Gizmo
-
Raycaster 精确控制
-
Debug / Overlay 渲染
-
点云 / 标注系统分层
❌ 不适合用 Layers 的场景:
-
单纯开关物体显示(用
visible) -
逻辑分组(用
Group)
十二、总结
Layers 是 three.js 中一个"存在感很低,但设计非常优雅"的功能
它本质上是:
-
位掩码
-
相机过滤机制
-
渲染前裁剪
一旦理解了它的原理,你会发现:
-
多相机渲染会变得非常干净
-
调试工具的实现会优雅很多
-
拾取逻辑会更可控