☰
Godot 3D 视锥可见性驱动的自动启停:VisibleOnScreenEnabler3D 节点详解
2026/10/14 16:55:15 网站建设 项目流程
  • 文档
  • 教程
  • 游戏开发

【免费下载链接】godot-docs

Godot Engine official documentation

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

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 自身。文档特别说明了两点缓存语义:

  1. 目标节点会被缓存:仅在"设置该属性时(且 Enabler 已在场景树内)"以及"每次 Enabler 进入场景树时"被重新解析赋值;
  2. 路径为空时,不会影响任何节点;路径无效时还会产生错误。

因此,在运行时如果场景结构发生大范围变动(如目标节点被移除后重新实例化),需要重新设置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_INHERIT0PROCESS_MODE_INHERIT继承父节点的process_mode
ENABLE_MODE_ALWAYS1PROCESS_MODE_ALWAYS始终处理,忽略暂停状态
ENABLE_MODE_WHEN_PAUSED2PROCESS_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),而非精确的几何遮挡计算。类参考文档明确给出两条限制:

  1. 近似启发式,不考虑墙体遮挡:它只判断包围盒与相机视锥(frustum)的关系,墙壁等遮挡物不会参与计算,除非开启了遮挡剔除(occlusion culling);
  2. 要求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 3Godot 4
VisibilityEnablerVisibleOnScreenEnabler3D
VisibilityNotifier/VisibilityNotifier3DVisibleOnScreenNotifier3D
VisibilityNotifier2DVisibleOnScreenNotifier2D

迁移时只需将旧节点替换为上述新类,属性名与默认值基本一致(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

项目地址:https://gitcode.com/GitHub_Trending/go/godot-docs
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询