- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
VisibleOnScreenEnabler3D是 Godot 引擎中一个基于"屏幕可见性"自动管理目标节点启停状态的 3D 节点:它维护一个盒状空间区域,只要该区域有任何部分出现在屏幕上,就会通过改写目标节点的process_mode自动启用目标节点,反之则自动停用。本文以官方类参考文档为主体,结合仓库中的相关教程与类文档,完整讲解其属性、枚举、底层原理与实战用法,帮助你在场景优化(如按需激活敌人、暂停远处动画)中落地这套机制。
VisibleOnScreenEnabler3D 是什么
VisibleOnScreenEnabler3D包含一块盒状 3D 空间区域(box-shaped region)和一个目标节点。当该区域的任意部分在屏幕上可见时,目标节点会被自动启用(通过其Node.process_mode属性);当区域完全不可见时,目标节点会被自动停用。
典型应用场景包括:只有当玩家靠近时才激活敌人,从而节省离屏敌人的 CPU/渲染开销。如果你只需要在区域可见/不可见时获得通知(而不自动启用节点),应当改用它的父类VisibleOnScreenNotifier3D,后者会发出screen_entered与screen_exited信号。
类参考文档(class_visibleonscreenenabler3d.rst)对该节点的定位描述为:"A box-shaped region of 3D space that, when visible on screen, enables a target node."
继承关系与类层次
从类参考文档的头部可以读出完整的继承链:
VisibleOnScreenEnabler3D < VisibleOnScreenNotifier3D (盒状区域可见性检测) < VisualInstance3D (3D 渲染实例,提供 AABB 与剔除相关能力) < Node3D < Node < Object它在VisibleOnScreenNotifier3D之上增加了"自动启用目标节点"的能力,而VisibleOnScreenNotifier3D本身(见 class_visibleonscreennotifier3d.rst)负责:
- 维护一个
AABB属性(默认AABB(-1, -1, -1, 2, 2, 2)),表示检测区域的包围盒; - 在区域进入/离开屏幕时发出
screen_entered/screen_exited信号; - 提供
is_on_screen()方法返回当前是否在屏幕上。
VisibleOnScreenNotifier3D又被列为VisibleOnScreenEnabler3D的直接父类,因此 Enabler 天然继承了上述全部能力。
核心属性详解
VisibleOnScreenEnabler3D只定义了两个属性:目标节点路径enable_node_path与启用模式enable_mode。
enable_node_path:指定要启停的目标节点
- 类型:
NodePath - 默认值:
NodePath("..")(即指向自身父节点)
该属性为目标节点的路径,相对于 VisibleOnScreenEnabler3D 自身。文档特别说明了两点缓存语义:
- 目标节点会被缓存:仅在"设置该属性时(且 Enabler 已在场景树内)"以及"每次 Enabler 进入场景树时"被重新解析赋值;
- 路径为空时,不会影响任何节点;路径无效时还会产生错误。
因此,在运行时如果场景结构发生大范围变动(如目标节点被移除后重新实例化),需要重新设置enable_node_path或让 Enabler 重新进入场景树,缓存才会刷新。
enable_mode:可见后以何种方式启用目标节点
- 类型:
EnableMode枚举 - 默认值:
0(ENABLE_MODE_INHERIT)
该属性决定目标节点被启用时采用的模式,与Node.ProcessMode枚举一一对应。关键约束是:当节点被停用时,始终使用Node.PROCESS_MODE_DISABLED,无论enable_mode取值如何。
EnableMode枚举的三个取值(2D 版VisibleOnScreenEnabler2D与之完全相同):
| 常量 | 值 | 对应Node.ProcessMode | 含义 |
|---|---|---|---|
ENABLE_MODE_INHERIT | 0 | PROCESS_MODE_INHERIT | 继承父节点的process_mode |
ENABLE_MODE_ALWAYS | 1 | PROCESS_MODE_ALWAYS | 始终处理,忽略暂停状态 |
ENABLE_MODE_WHEN_PAUSED | 2 | PROCESS_MODE_WHEN_PAUSED | 仅在SceneTree.paused为true时处理 |
注意:
Node.ProcessMode完整枚举为PROCESS_MODE_INHERIT = 0、PROCESS_MODE_PAUSABLE = 1、PROCESS_MODE_WHEN_PAUSED = 2、PROCESS_MODE_ALWAYS = 3、PROCESS_MODE_DISABLED = 4(见 class_node.rst)。EnableMode仅暴露前三个作为"启用时的模式";而"停用"恒定为PROCESS_MODE_DISABLED,即完全禁用目标节点的处理与输入回调。
Node.process_mode与can_process()的语义可进一步参考 class_node.rst:设为PROCESS_MODE_DISABLED时can_process()恒为false,节点不再收到_process()、_physics_process()、_input()等回调。
底层原理与使用限制
VisibleOnScreenEnabler3D的可见性判定基于渲染剔除代码(culling),而非精确的几何遮挡计算。类参考文档明确给出两条限制:
- 近似启发式,不考虑墙体遮挡:它只判断包围盒与相机视锥(frustum)的关系,墙壁等遮挡物不会参与计算,除非开启了遮挡剔除(occlusion culling);
- 要求
Node3D.visible为true:如果节点的visible属性为false,检测不会生效。
此外,从父类VisibleOnScreenNotifier3D的方法说明可知:节点加入场景树后需要一帧时间才会完成可见性评估,因此实例化后立即调用is_on_screen()会恒返回false(见 class_visibleonscreennotifier3d.rst)。
检测区域可通过继承自VisibleOnScreenNotifier3D的aabb属性调整(默认AABB(-1, -1, -1, 2, 2, 2),即原点为中心、边长 2 的立方体)。在编辑器中,该区域以 gizmo 形式显示,其颜色由EditorSettings中的 3D 编辑器 gizmo 颜色配置控制,该配置项同样作用于VisibleOnScreenNotifier3D与VisibleOnScreenEnabler3D(见 class_editorsettings.rst)。
实战:按需激活场景中的敌人
下面是一个最小可运行示例:在一个 3D 敌人场景中,用VisibleOnScreenEnabler3D包裹敌人,让其在进入屏幕前完全停用,接近后才开始运行。
场景结构建议:
Enemy (Node3D, process_mode = DISABLED 作为初始状态) ├── VisibleOnScreenEnabler3D (enable_node_path = ".." 默认即父节点) │ └── (调整 aabb 覆盖敌人模型范围) ├── MeshInstance3D └── 敌人 AI 相关逻辑节点GDScript 示例(挂在敌人 AI 节点上,演示enable_mode的运行时设置与screen_entered/screen_exited信号的可选用法):
extends Node3D @onready var enabler: VisibleOnScreenEnabler3D = $VisibleOnScreenEnabler3D func _ready() -> void: # 目标节点:Enabler 自身的父节点(默认 NodePath("..")) enabler.enable_node_path = ".." # 敌人进入屏幕后使用"继承父级"的 process_mode,暂停时随场景暂停 enabler.enable_mode = VisibleOnScreenEnabler3D.EnableMode.ENABLE_MODE_INHERIT # 如果只想做额外通知,可使用父类的信号 if enabler is VisibleOnScreenNotifier3D: enabler.screen_entered.connect(_on_screen_entered) enabler.screen_exited.connect(_on_screen_exited) func _on_screen_entered() -> void: print("敌人区域进入屏幕,AI 已启用") func _on_screen_exited() -> void: print("敌人区域离开屏幕,AI 已停用")要点回顾:
- 目标节点被停用时统一写入
PROCESS_MODE_DISABLED,其_process()、_physics_process()与输入回调全部停止; - 区域可见后,
process_mode被改写为enable_mode对应的模式(如PROCESS_MODE_INHERIT继承父级暂停规则); - 由于检测基于视锥而非遮挡,敌人隔着墙仍会被激活——若场景墙体密集且开启遮挡剔除,行为会有所不同。
在性能优化中的应用
官方 3D 性能优化教程(optimizing_3d_performance.rst)明确推荐将VisibleOnScreenEnabler3D与VisibleOnScreenNotifier3D用于动画与蒙皮的优化:
- 动画与顶点动画(蒙皮、形变)在部分平台上开销很高,可能需要大幅降低动画模型的面数,或限制同一时刻屏幕上的动画角色数量;
- 对于远处的网格或已被遮挡的网格,可以降低动画帧率,甚至直接暂停动画(玩家大概率不会察觉);
VisibleOnScreenEnabler3D/VisibleOnScreenNotifier3D正是实现"暂停离屏动画"的现成手段。
具体做法:为带动画(AnimationPlayer)的远距离装饰物挂一个VisibleOnScreenEnabler3D,目标路径指向动画节点;离屏时动画随PROCESS_MODE_DISABLED停止,进入屏幕后自动恢复播放,从而在不改变任何美术资源的前提下削减离屏动画的 CPU 开销。
2D 对应物与 Godot 4 迁移
该机制在 2D 中有完全对应的VisibleOnScreenEnabler2D(矩形区域,继承VisibleOnScreenNotifier2D<Node2D<CanvasItem,见 class_visibleonscreenenabler2d.rst),其属性、枚举与语义与 3D 版一一对应,仅检测依赖CanvasItem.visible为true。
在 Godot 4 迁移表中(upgrading_to_godot_4.rst),旧 Godot 3 节点的对应关系为:
| Godot 3 | Godot 4 |
|---|---|
VisibilityEnabler | VisibleOnScreenEnabler3D |
VisibilityNotifier/VisibilityNotifier3D | VisibleOnScreenNotifier3D |
VisibilityNotifier2D | VisibleOnScreenNotifier2D |
迁移时只需将旧节点替换为上述新类,属性名与默认值基本一致(enable_node_path默认..、enable_mode默认ENABLE_MODE_INHERIT),即可保持原有行为。
小结
VisibleOnScreenEnabler3D用极小的成本(一个包围盒 + 视锥检测)实现了"屏幕可见即启用、离屏即停用"的节点生命周期管理,是 Godot 3D 场景在动画、AI 与特效层面做运行时优化的基础组件。使用时要牢记三点:检测是近似视锥判定(不考虑普通墙体遮挡)、要求节点visible = true、首次加入场景树需等待一帧。配合aabb区域调整与enable_mode模式选择,它能稳定服务于"敌人靠近才激活""离屏动画暂停"等常见需求;而当你需要更细粒度的可见性通知时,直接使用其父类VisibleOnScreenNotifier3D的screen_entered/screen_exited信号即可。
- 文档
- 教程
- 游戏开发
【免费下载链接】godot-docs
Godot Engine official documentation
相关推荐
Godot 4.6 逆向运动学关节限制详解:JointLimitationCone3D 圆锥形限制
Godot 4.6 逆向运动学关节限制详解:JointLimitationCone3D 圆锥形限制 JointLimitationCone3D 是 Godot
文档教程游戏开发Godot RootMotionView 节点详解:在编辑器中可视化调试根运动(Root Motion)
Godot RootMotionView 节点详解:在编辑器中可视化调试根运动(Root Motion) 根运动(Root Motion)是 3D 角色动画中让
文档教程游戏开发GraphFrame 图框节点详解:Godot 节点图编辑器中的分组与自动布局利器
GraphFrame 图框节点详解:Godot 节点图编辑器中的分组与自动布局利器 GraphFrame(图框)是 Godot Engine 中 GraphEd
文档教程游戏开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考