外观
Lesson 040|Camera、可见性判断与渲染顺序
Tags: #Creator2.x #Stage04 #Camera #Culling #RenderOrderDifficulty: ⭐⭐⭐⭐☆
真实问题:节点 active、opacity 255,为什么仍然看不见
战斗场景新增一台 SkillCamera,只渲染技能预览层。特效节点在 Hierarchy 中 active,位置也在屏幕中央,却只在场景编辑器里可见,运行时完全消失。
开发者依次检查 SpriteFrame、材质、透明度,都正常。真正原因是:
text
Effect 节点所属 Group
不在 SkillCamera.cullingMask 中“节点存在”和“Camera 会提交它”是两层条件。多 Camera 时还要考虑清屏、深度和 viewport,后绘制的 Camera 甚至可能覆盖前一台的结果。
🎯 本课目标
本课回答:
世界里有这么多节点,Camera 最终决定哪些能看见、以什么顺序画出来吗?
需要区分:
- Node 是否 active。
- 对象是否在 Camera 视野内。
- Camera 的 group 筛选与空间裁剪不是一回事。
- 2D 节点树顺序、zIndex 与 Camera 顺序。
- 不可见对象是否仍有 CPU 成本。
二、Camera 不只是一个坐标点
Camera 参与:
text
视图变换
投影
可见范围
渲染层
清屏和目标
多 Camera 顺序它把世界坐标映射到屏幕,并通过 cullingMask 等配置选择允许当前 Camera 渲染的 group。这里的“选择 group”不能直接等同于“自动剔除所有屏幕外 2D Sprite”。
三、active 和可见不是一回事
text
node.active = false
→ 节点树最终不激活
node.active = true
→ 仍可能在 Camera 视野外即使对象不在屏幕上,它可能仍然带来:
- Node 和 Component 调度成本。
- Transform 更新。
- Layout 或动画成本。
- 资源占用。
可见性优化和逻辑停用是两个问题。
四、Creator 2.4 的 cullingMask 与离屏对象
text
Node.group
↓ 与 Camera.cullingMask 按位匹配
当前 Camera 是否负责渲染这一组节点Creator 2.x 新 Renderer 中,旧的通用自动 culling 机制已移除。对于普通 2D Sprite,不能默认假设引擎会逐个计算世界包围盒,并自动跳过所有屏幕外对象。
因此大量离屏 2D 对象通常仍要由业务按场景设计管理:
- 地图使用空间分区,只激活可见区域附近对象。
- ScrollView 使用虚拟列表或复用 Item。
- 远处对象关闭不需要的 Renderer、动画和脚本。
- 3D Mesh 是否参与视锥裁剪,应按对应 3D Renderer 和批处理实现单独验证。
版本边界:
cullingMask是 group 过滤;视锥裁剪、遮挡剔除和 2D 列表虚拟化是不同机制,不能混写成一条通用流程。
官方版本依据:Creator 2.4 Camera、ENABLE_CULLING 版本说明。
五、渲染顺序为什么重要
2D 画面中后画的内容可能覆盖先画的内容:
text
背景
→ 地面
→ 角色
→ 特效
→ UICreator 2.4.x 的普通 2D 节点首先要看:
- 父子节点遍历顺序。
- 兄弟节点顺序和
zIndex。 - Canvas 与 Camera 的渲染顺序。
- Mask 等组件插入的渲染边界。
3D Mesh、透明材质和多 Pass 还会涉及深度测试、材质队列与透明排序。不要把这些 3D 规则直接套到普通 2D UI。
六、多 Camera 的成本
多个 Camera 可能用于:
- 主世界。
- UI。
- 小地图。
- 后处理或独立视口。
但每个 Camera 都可能增加:
text
对象筛选
渲染队列构建
状态切换
额外目标或清屏不需要的 Camera 应禁用,而不是只把画面内容移走。
七、案例:为什么节点不显示
排查顺序:
text
1. Node.active 是否为 true?
2. activeInHierarchy 是否为 true?
3. Sprite / Label 组件是否启用?
4. Node.group 是否包含在 Camera.cullingMask 中?
5. 世界位置是否在可见区域?
6. 尺寸、Anchor、Scale 是否合理?
7. 是否被后绘制对象遮挡?
8. 材质透明度或混合状态是否正确?“看不见”不一定是资源丢失。
八、案例:屏幕外对象仍然卡
如果对象逻辑仍运行:
text
屏幕外
≠
没有 update / 动画 / Layout 成本可以按场景选择:
- 只关闭 Renderer。
- 关闭不需要的脚本组件。
- 使用对象池回收远处对象。
- 使用空间分区或可见范围管理。
- 对 UI 列表做虚拟化。
不要盲目将所有离屏对象 destroy,频繁重建可能更贵。
九、常见误区
误区一:active=true 就一定能看到
还要满足渲染组件、Camera、位置、层级和材质条件。
误区二:Camera 只负责缩放
它还参与视图、投影、可见性和渲染目标。
误区三:屏幕外对象没有任何成本
逻辑、Transform、动画、Layout 和资源仍可能消耗 CPU 或内存。
误区四:Camera 会自动剔除所有屏幕外 2D 节点
Creator 2.x 新 Renderer 不能这样假设。普通 2D 大地图和长列表仍需要业务侧可见范围管理或虚拟化。
误区五:2D 和 3D 使用完全相同的排序规则
普通 2D UI 重点看节点树、zIndex、Canvas 和 Camera;3D 还涉及深度、材质队列和透明排序。
十、深入推导:对象通过 Camera 的检查链
“节点存在”“节点参与更新”“节点被某台 Camera 收集”“最终像素可见”是四件不同的事:
text
存在:对象还在场景树和内存中
参与更新:activeInHierarchy、组件 enabled、调度条件允许
被收集:Group、cullingMask、视锥或可见范围允许
产生可见像素:材质、透明度、Depth、Stencil、顺序最终通过因此 active = true 只证明第一段条件之一,不能证明最后一定看得见。
一个对象可能被 Camera 收集却没有可见贡献,例如:
text
opacity 为 0;
完全被不透明对象遮住;
Fragment Shader 输出透明;
Depth Test 失败;
Stencil Test 失败;
几何落在 Viewport 外。反过来,一个屏幕外 Node 也可能继续执行脚本、动画、Layout 和 Transform。渲染不可见不等于整个对象停止工作。
高层模型:
text
Node activeInHierarchy
→ Renderer Component enabled
→ 资源和材质可用
→ Node Group 被 Camera cullingMask 接受
→ 几何位于 Camera 视体/Viewport 的有效区域
→ 渲染顺序与遮挡允许看到
→ Camera 清屏没有覆盖预期结果不同组件可能有额外裁剪规则。这个链用于确定排查方向,不等于逐行引擎源码。
十一、Creator 2.4.x 实验:两台 Camera 看不同 Group
Group、Camera、节点和组件都通过 Creator 编辑器配置。不要直接修改场景序列化文件。
场景结构
text
WorldCamera
SkillCamera
WorldGroupNode/Sprite
SkillGroupNode/Sprite
Canvas/StatusLabel在 Project Settings 中通过编辑器创建或确认 Group,再把两个 Sprite 分配到不同 Group。分别配置 Camera 的 cullingMask。
实验步骤
- WorldCamera 只勾选 World Group。
- SkillCamera 只勾选 Skill Group。
- 两个 Sprite 放在画面不同位置,确认各自可见。
- 取消 SkillCamera 对 Skill Group 的勾选,观察特效消失。
- 恢复 Mask,再调整 Camera depth/clearFlags,观察两台 Camera 组合。
- 缩小 SkillCamera viewport,观察技能内容只出现在局部区域。
CameraProbe.ts
ts
const { ccclass, property } = cc._decorator;
@ccclass
export default class CameraProbe extends cc.Component {
@property(cc.Camera)
worldCamera: cc.Camera = null;
@property(cc.Camera)
skillCamera: cc.Camera = null;
@property(cc.Node)
target: cc.Node = null;
logState() {
cc.log(
'[camera]',
'targetGroup=', this.target.group,
'worldMask=', this.worldCamera.cullingMask,
'skillMask=', this.skillCamera.cullingMask,
'worldEnabled=', this.worldCamera.enabled,
'skillEnabled=', this.skillCamera.enabled
);
}
}不要在课程代码中硬编码 Group 位值解决正式问题;通过编辑器配置并用日志验证最终值。
十二、渲染顺序必须分层讨论
“谁先画”至少有三层答案:
text
Camera 层:哪台 Camera 先执行、Clear 什么目标
对象层:同一 Camera 中哪些 Render Component 先提交
Pass 层:同一对象的多个 Pass 以什么顺序执行例如小地图 Camera 最后执行且清空颜色缓冲,即使它只想画右上角,也可能先把主 Camera 已经画好的内容清掉。问题不在节点 siblingIndex,而在 Camera 的执行与 Clear 配置。
透明对象还存在顺序依赖。假设红色和蓝色都为 50% 透明:
text
先红后蓝
≠
先蓝后红因为后画颜色会以上一次 FrameBuffer 结果为目标继续混合。Renderer 不能为了合批任意跨越这些对象。
至少区分:
Camera 之间
Camera 的 depth、clear flags 和 viewport 决定多相机如何叠加。后一台若清除颜色缓冲,可能覆盖前一台结果。
同一 Camera 内
2D UI 常受节点层级与兄弟顺序影响;不同渲染组件和材质队列也可能参与排序。
单个对象内部
Mask、Spine、Particle 等可能产生多个渲染阶段,不能简单等价为一个 Sprite。
不要用“把节点移到 Hierarchy 最后”解决所有顺序问题。先确定冲突发生在哪一层。
十三、屏幕外对象为什么仍可能有成本
可以用“关逻辑”和“关渲染”两步对照区分:
text
只让 Camera 看不到对象
→ 若 CPU 仍高,说明脚本/动画/布局/Transform 仍在工作
再把对象或相关组件真正停用
→ 若 CPU 降低,证明成本不只来自像素绘制但 active=false 会触发生命周期和业务语义变化,不能直接当作所有离屏优化方案。虚拟列表、暂停动画、降低更新频率或缩小活跃子树通常需要分别设计。
“没有最终像素”不保证“没有任何 CPU 工作”:
- 脚本 update 仍运行;
- Animator/Tween 仍更新;
- Layout/Widget 仍遍历;
- 粒子系统仍模拟;
- Transform Dirty 仍传播;
- 某些渲染数据可能在裁剪前准备;
- 自定义系统可能全量遍历。
Camera 裁剪主要减少提交和 GPU 工作,不会自动暂停游戏逻辑。大规模屏外对象需要独立的激活、LOD、虚拟列表或模拟策略。
十四、真实项目故障:小地图 Camera 把主画面清黑
现象
加入小地图 Camera 后,主画面偶尔只剩小地图区域,其余变黑。
根因
小地图 Camera 的 viewport 和 clear flags 配置错误,在后续渲染阶段清除了不该清除的颜色区域。
排查证据
text
依次禁用 Camera
→ 确认是哪台启用后出现
→ 记录 depth、clearFlags、viewport
→ 记录 cullingMask
→ 用纯色背景验证清屏范围
→ 再恢复 RenderTexture/小地图内容修复原则
明确每台 Camera 的职责:渲染谁、画到哪里、是否清颜色/深度/模板、与其他 Camera 的先后关系。
十五、不显示问题的证据式排查
text
1. 节点 activeInHierarchy / 组件 enabled
2. SpriteFrame、材质、颜色、opacity
3. 世界位置、尺寸、scale、Camera viewport
4. Node Group 与每台 Camera cullingMask
5. Camera enabled、depth、clear flags
6. 层级遮挡、Mask/Stencil
7. 构建平台 shader/纹理错误每次只改变一个条件。把所有 Camera mask 全勾上只能作为定位实验,不是最终配置。
十六、练习、推导答案与版本边界
本课以 Creator 2.4.x Camera、Group 和 cullingMask 为主。具体排序、clear flag 枚举和内置 Canvas Camera 行为应以项目小版本为准。
- active 为 true 为什么仍可能不可见? Camera mask、视体、viewport、材质、透明度、遮挡和清屏都在 active 之后。
- Camera 裁掉对象后,update 会自动停止吗? 不会。逻辑生命周期与 Camera 可见性没有默认等价关系。
- 多 Camera 排查为何先逐台禁用? 可以隔离清屏、顺序和 mask 责任,避免在组合结果中猜测。
- UI 顺序错时为什么不应先改 z/兄弟顺序? 冲突可能来自不同 Camera、Mask 或渲染队列;应先确定排序层。
能力验收
你应该能用两台 Camera 和两个 Group 构造可见性对照,区分 active、被 Camera 看见、最终出现在屏幕三件事,并沿组件、Group、cullingMask、Viewport、Clear、Depth 和 Material 顺序取证。
本课总结
text
Camera 决定看哪里、如何投影、渲染哪些 group 以及提交到哪里。
激活、可见、可渲染不是同一个概念。
Creator 2.4 的 cullingMask 不等于通用的 2D 空间裁剪。
2D 与 3D 排序规则需要分开理解。
离屏对象仍可能有逻辑、渲染收集和资源成本。十二、下一课预告
text
Lesson041|Sprite 从 SpriteFrame 到 RenderData 经历了什么?