UE5源码分析之Editor——CommonMenuExtensions插件全面分析

CommonMenuExtensions 插件全面系统分析


目录

  1. 插件概述
  2. 插件整体架构解析
  3. 类级代码注释详解
  4. 功能使用示例编写
  5. 总结与最佳实践

### 文章目录

  • [CommonMenuExtensions 插件全面系统分析](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [目录](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [@toc](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [1 插件概述](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [1.1 基本信息](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2 插件整体架构解析](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2.1 架构图](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2.2 模块间依赖关系](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2.3 模块划分](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2.4 数据流走向](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2.5 核心技术栈](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [2.6 架构设计优势](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [潜在改进点](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [3 类级代码注释详解](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [3.1 FCommonMenuExtensionsModule 类](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [StartupModule() - 模块启动](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [ShutdownModule() - 模块关闭](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [3.2 FShowFlagMenuCommands 类](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [构造函数](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [BuildShowFlagsMenu() - 构建完整菜单](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [PopulateAllShowFlagsSection() - 分组子菜单](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [BindCommands() - 绑定到视口](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [3.3 FShowFlagFilter 类](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [过滤规则优先级](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [ShouldIncludeFlag() - 核心判断逻辑](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [RebuildIndexArray() - 构建索引缓存](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [3.4 可视化菜单命令类的统一模式](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [共同结构](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [BuildCommandMap() 模式](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [BuildVisualisationSubMenu() 模式](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [BindCommands() 模式](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [FVirtualShadowMapVisualizationMenuCommands 的特殊之处](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [FGroomVisualizationMenuCommands 的特殊之处](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [3.5 FEditorViewportClient 交互总结](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [4 功能使用示例编写](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [示例1:在自定义编辑器视口中集成 ShowFlag 菜单](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [示例2:扩展新的可视化菜单](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [第一步:在自己的渲染模块中定义可视化数据](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [第二步:在 CommonMenuExtensions 中新增菜单命令类](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [第三步:在模块入口注册](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [示例3:动态启用/禁用高级调试模式](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [示例4:ShowFlagFilter 的高级用法](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [5 总结与最佳实践](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [核心要点](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [最佳实践](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [常见问题解决](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [附录](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [A. 相关源码文件](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)
  • [B. 模块文件结构](#文章目录 CommonMenuExtensions 插件全面系统分析 目录 @[toc] 1 插件概述 1.1 基本信息 2 插件整体架构解析 2.1 架构图 2.2 模块间依赖关系 2.3 模块划分 2.4 数据流走向 2.5 核心技术栈 2.6 架构设计优势 潜在改进点 3 类级代码注释详解 3.1 FCommonMenuExtensionsModule 类 StartupModule() - 模块启动 ShutdownModule() - 模块关闭 3.2 FShowFlagMenuCommands 类 构造函数 CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令 BuildShowFlagsMenu() - 构建完整菜单 PopulateAllShowFlagsSection() - 分组子菜单 BindCommands() - 绑定到视口 3.3 FShowFlagFilter 类 过滤规则优先级 ShouldIncludeFlag() - 核心判断逻辑 RebuildIndexArray() - 构建索引缓存 3.4 可视化菜单命令类的统一模式 共同结构 BuildCommandMap() 模式 BuildVisualisationSubMenu() 模式 BindCommands() 模式 FVirtualShadowMapVisualizationMenuCommands 的特殊之处 FGroomVisualizationMenuCommands 的特殊之处 3.5 FEditorViewportClient 交互总结 4 功能使用示例编写 示例1:在自定义编辑器视口中集成 ShowFlag 菜单 示例2:扩展新的可视化菜单 第一步:在自己的渲染模块中定义可视化数据 第二步:在 CommonMenuExtensions 中新增菜单命令类 第三步:在模块入口注册 示例3:动态启用/禁用高级调试模式 示例4:ShowFlagFilter 的高级用法 5 总结与最佳实践 核心要点 最佳实践 常见问题解决 附录 A. 相关源码文件 B. 模块文件结构)

1 插件概述

1.1 基本信息

属性
插件名称 CommonMenuExtensions
类型 Editor(仅编辑器)
模块名称 CommonMenuExtensions
描述 为编辑器视口提供可视化菜单扩展,包括 Show Flags 菜单和各种渲染可视化子菜单

整个模块由 1 个模块类 + 7 个功能类 构成,代码量适中、结构清晰。它的核心职责非常单纯:把引擎中各类渲染可视化选项,按照统一的模式注册到编辑器菜单系统中

在这个模块中,主要依赖了引擎的 Core、InputCore、Slate、SlateCore、Engine、UnrealEd、ToolMenus 这 7 个模块。核心技术栈包括:TCommands(UI 命令系统)、FUICommandInfo(命令信息)、UToolMenu(工具菜单框架)、FEditorViewportClient(编辑器视口客户端),以及各渲染系统的可视化数据组件(BufferVisualizationDataNaniteVisualizationDataLumenVisualizationData 等)。


2 插件整体架构解析

2.1 架构图

先来看一张全景架构图。CommonMenuExtensions 的设计是一个典型的"注册中心 + 功能模块"模式------模块启动时把各个子系统的菜单命令逐一向引擎注册,关闭时再逐一反注册。

复制代码
┌─────────────────────────────────────────────────────────────────────┐
│                    FCommonMenuExtensionsModule                        │
│                        (模块启动/关闭入口)                             │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │  StartupModule():                                                │ │
│  │    注册所有子菜单命令:                                            │ │
│  │    ├─ FBufferVisualizationMenuCommands::Register()              │ │
│  │    ├─ FNaniteVisualizationMenuCommands::Register()              │ │
│  │    ├─ FLumenVisualizationMenuCommands::Register()               │ │
│  │    ├─ FSubstrateVisualizationMenuCommands::Register()           │ │
│  │    ├─ FGroomVisualizationMenuCommands::Register()               │ │
│  │    ├─ FVirtualShadowMapVisualizationMenuCommands::Register()    │ │
│  │    └─ FShowFlagMenuCommands::Register()                         │ │
│  └────────────────────────────────────────────────────────────────┘ │
│  ┌────────────────────────────────────────────────────────────────┐ │
│  │  ShutdownModule():                                               │ │
│  │    反注册所有子菜单命令(顺序与启动相反)                          │ │
│  └────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
                                  │
        ┌─────────────────────────┼─────────────────────────┐
        ▼                         ▼                         ▼
┌───────────────┐   ┌───────────────────────┐   ┌───────────────────────┐
│ ShowFlagMenu  │   │ 可视化菜单命令基类      │   │ 可视化菜单命令基类      │
│   Commands    │   │ (BufferVisualization)  │   │ (Nanite / Lumen / ...)│
├───────────────┤   ├───────────────────────┤   ├───────────────────────┤
│ - 构建 Show   │   │ - TCommands 子类       │   │ - TCommands 子类       │
│   Flags 菜单  │   │ - CommandMap (TMultiMap)│   │ - CommandMap (TMultiMap)│
│ - 子菜单分组  │   │ - BuildVisualisation   │   │ - BuildVisualisation   │
│   (后处理、    │   │   SubMenu()           │   │   SubMenu()           │
│    灯光、     │   │ - BindCommands()       │   │ - BindCommands()       │
│    Lumen、    │   │ - 读取引擎的可视化数据   │   │ - 读取引擎的可视化数据   │
│    Nanite等)  │   │   注册为 FUICommandInfo │   │   注册为 FUICommandInfo │
│ - 过滤系统    │   └───────────────────────┘   └───────────────────────┘
│   (ShowFlag   │
│    Filter)    │
└───────────────┘

2.2 模块间依赖关系

如果上述架构图看起来还有点抽象,可以参考下面的依赖关系进行理解。

复制代码
FCommonMenuExtensionsModule (模块入口)
    │
    ├──→ FShowFlagMenuCommands
    │       ├──→ FShowFlagFilter (过滤规则)
    │       ├──→ GetShowFlagMenuItems() (引擎 ShowFlag 数据)
    │       ├──→ FUICommandInfo (Slate 命令系统)
    │       └──→ FEditorViewportClient (视口交互)
    │
    ├──→ FBufferVisualizationMenuCommands
    │       ├──→ GetBufferVisualizationData() (材质可视化数据)
    │       ├──→ FUICommandInfo
    │       └──→ FEditorViewportClient
    │
    ├──→ FNaniteVisualizationMenuCommands
    │       ├──→ GetNaniteVisualizationData() (Nanite 可视化数据)
    │       ├──→ 控制台变量: r.Nanite.Visualize.Advanced
    │       ├──→ FUICommandInfo
    │       └──→ FEditorViewportClient
    │
    ├──→ FLumenVisualizationMenuCommands
    │       ├──→ GetLumenVisualizationData() (Lumen 可视化数据)
    │       ├──→ FUICommandInfo
    │       └──→ FEditorViewportClient
    │
    ├──→ FSubstrateVisualizationMenuCommands
    │       ├──→ GetSubstrateVisualizationData() (Substrate 可视化数据)
    │       ├──→ FUICommandInfo
    │       └──→ FEditorViewportClient
    │
    ├──→ FGroomVisualizationMenuCommands
    │       ├──→ GetGroomVisualizationData() (Groom 可视化数据)
    │       ├──→ FUICommandInfo
    │       └──→ FEditorViewportClient
    │
    └──→ FVirtualShadowMapVisualizationMenuCommands
            ├──→ GetVirtualShadowMapVisualizationData() (VSM 可视化数据)
            ├──→ 控制台变量: r.Shadow.Virtual.Visualize.Advanced
            ├──→ IConsoleManager (控制台命令绑定)
            ├──→ FUICommandInfo
            └──→ FEditorViewportClient

可能大家看到这里会感到好奇------这个模块看起来就是"把一堆可视化菜单注册到编辑器",为什么要搞得这么模块化?

其实,这正是 UE 编辑器架构设计精妙的地方。CommonMenuExtensions 不是一个功能模块,而是一个"桥接层"。它的核心价值在于:

  1. 解耦:每个渲染子系统(Buffer Visualization、Nanite、Lumen 等)的可视化数据定义在自己的模块里,但菜单的注册和管理统一放在 CommonMenuExtensions 中。如果将来某个渲染功能被废弃或替换,只需要在这里添加/移除一个 Register/Unregister 调用,渲染模块本身不需要知道菜单系统的存在。

  2. 统一模式 :所有可视化菜单命令都遵循一模一样的设计模式:继承 TCommands → 构建 CommandMap → 注册命令 → 绑定到视口客户端。任何人要新增一个可视化菜单,照着现有代码复制改改五分钟就能搞定。

  3. 关注点分离FShowFlagMenuCommands 负责的是"通用渲染开关"(灯光、后处理、开发者调试等),而各个 XxxVisualizationMenuCommands 负责的是特定渲染管线的"调试可视化模式"。两者职责清晰,互不干扰。

2.3 模块划分

对于每个模块的功能总结如下:

1. FCommonMenuExtensionsModule - 模块入口层

职责:

  • 作为 Editor 模块的入口点
  • 在编辑器启动时注册所有子系统的菜单命令
  • 在编辑器关闭时反注册所有命令

特点:

  • 极简设计------仅有一个 StartupModule() 和一个 ShutdownModule()
  • 关机时采用与开机相反的顺序反注册(镜像配对)

2. FShowFlagMenuCommands - Show Flags 菜单层

职责:

  • 构建和管理"Show Flags"下拉菜单的所有条目
  • 支持按 ShowFlag 分组(视觉化、后处理、灯光类型、Lumen、Nanite 等)创建子菜单
  • 管理 ShowFlag 命令的注册、绑定、切换逻辑

特点:

  • 动态创建 UI 命令------从 GetShowFlagMenuItems() 获取所有已注册的 ShowFlag 数据
  • 支持 FShowFlagFilter 进行灵活过滤
  • 可通过 BindCommands() 将命令绑定到指定视口

3. FShowFlagFilter - 过滤系统层

职责:

  • 提供对 ShowFlag 菜单项的灵活过滤
  • 支持按组(Group)和按单个 Flag 的包含/排除规则
  • 采用优先级链式调用设计

特点:

  • 支持两种默认模式:全包含(IncludeAllFlagsByDefault)和全排除(ExcludeAllFlagsByDefault)
  • 过滤规则优先级:显式包含 Flag > 显式排除 Flag > 包含的组 > 排除的组 > 默认模式
  • 支持链式调用,接口流畅

4. 可视化菜单命令层(6 个类)

这六个类共享完全相同的架构模式,权限统一列出:

类名 数据源 分类维度 特殊功能
FBufferVisualizationMenuCommands GetBufferVisualizationData() 无分类(平铺列表) 支持 Overview 命令用于回到默认
FNaniteVisualizationMenuCommands GetNaniteVisualizationData() Overview / Standard / Advanced 通过 CVar 控制 Advanced 显示
FLumenVisualizationMenuCommands GetLumenVisualizationData() Overview / Standard 最简洁的命名风格参考
FSubstrateVisualizationMenuCommands GetSubstrateVisualizationData() 按 FSubstrateViewMode 分类 分 General / Advanced 两个 Section
FGroomVisualizationMenuCommands GetGroomVisualizationData() 按 EGroomViewMode 分类 分 General / Attributes / Guides / Strands / Advanced 五个 Section;另有 GroomEditor 变体
FVirtualShadowMapVisualizationMenuCommands GetVirtualShadowMapVisualizationData() Standard / Advanced 额外绑定 NextLight / PrevLight 控制台命令

共同职责:

  • 从对应渲染系统的可视化数据注册表读取可用模式
  • 将每种模式注册为 FUICommandInfo(RadioButton 类型)
  • 构建分类的子菜单(BuildVisualisationSubMenu
  • 绑定命令到 FEditorViewportClient 的对应方法

共同特点:

  • 继承 TCommands<Self>(CRTP 模式)
  • 使用 TMultiMap<FName, Record> 管理命令映射
  • 提供 IsPopulated() 检测数据是否可用
  • 通过 TWeakPtr<FEditorViewportClient> 安全访问视口客户端
  • 全部 RadioButton 类型,同一时刻只能选中一个模式

2.4 数据流走向

ShowFlag 菜单加载流程:

复制代码
1. 模块启动: FShowFlagMenuCommands::Register()
   ↓
2. RegisterCommands() → CreateShowFlagCommands()
   ↓
3. 从引擎全局获取 GetShowFlagMenuItems()(所有已注册的 ShowFlag 数据)
   ↓
4. 为每个 ShowFlag 创建 FUICommandInfo(ToggleButton 类型)
   ↓
5. 将命令存入 ShowFlagCommands 数组
   ↓
6. 视口打开菜单时调用 BuildShowFlagsMenu()
   ↓
7. 通过 FShowFlagFilter 过滤 → 分组填充到菜单 Section
   ↓
8. 用户点击菜单项 → ToggleShowFlag() → Client->HandleToggleShowFlag()

可视化模式菜单加载流程:

复制代码
1. 模块启动: FNaniteVisualizationMenuCommands::Register()
   ↓
2. RegisterCommands() → BuildCommandMap()
   ↓
3. 从 GetNaniteVisualizationData() 获取所有可用可视化模式
   ↓
4. 遍历 modeMap,为每个模式创建 FUICommandInfo(RadioButton 类型)
   ↓
5. 按 ModeType 分类存入 CommandMap
   ↓
6. 视口打开菜单时调用 BuildVisualisationSubMenu()
   ↓
7. 按类型分组填充菜单 Section(Overview → Separator → Standard → Separator → Advanced)
   ↓
8. 用户点击 → ChangeNaniteVisualizationMode() → Client->ChangeNaniteVisualizationMode()

2.5 核心技术栈

技术/类 用途
TCommands<T> Slate UI 命令系统的基类模板,CRTP 模式
FUICommandInfo 单个 UI 命令的描述信息(标签、快捷键、图标)
FUICommandList UI 命令列表,管理和绑定命令的执行
UToolMenu / FToolMenuSection 工具菜单框架,构建层级菜单
FMenuBuilder 旧版菜单构建器(BufferVisualization 仍在使用)
FEditorViewportClient 编辑器视口客户端,承载可视化切换的具体逻辑
FShowFlagData 单个 ShowFlag 的元数据(名称、分组、快捷键等)
FShowFlagFilter ShowFlag 的过滤规则引擎
*VisualizationData 各渲染系统的可视化数据注册表(Provider 模式)
TMultiMap 一对多映射,存储可视化命令
TWeakPtr 弱指针,安全访问可能已销毁的视口客户端
IConsoleManager 控制台变量/命令管理器(VSM 使用)
FAutoConsoleVariableRef 自动注册的控制台变量(Nanite/VSM Advanced 开关)

2.6 架构设计优势

  1. 高度统一的模式:六个可视化菜单类遵循完全相同的设计模式,学习成本低,维护成本低
  2. 数据驱动:菜单内容不由代码写死,而是从各渲染系统的可视化数据注册表中动态读取。新增一种可视化模式只需在对应渲染模块里注册数据,菜单会自动展现
  3. 模块边界清晰 :CommonMenuExtensions 只负责"菜单注册"这一件事。可视化模式的具体含义、切换逻辑都留在各渲染模块中,通过 FEditorViewportClient 的方法间接调用
  4. 关注点分离:ShowFlag 菜单(通用渲染开关)和可视化菜单(特定管线的调试视图)分别由不同的类管理
  5. 安全的生命周期管理 :对 FEditorViewportClient 使用 TWeakPtr,避免视口关闭后回调访问悬空指针
  6. 灵活过滤系统FShowFlagFilter 采用优先级链式调用,使用者可以精确控制菜单中展示哪些条目

潜在改进点

  1. 旧版 API 混用FBufferVisualizationMenuCommands::BuildVisualisationSubMenu 仍在使用 FMenuBuilder(旧版),而其他类已经迁移到 UToolMenu。可以考虑统一升级
  2. C++ 模板化 :六个可视化菜单类共享大量相似代码(BuildCommandMapBindCommandsCreateCommandConstIterator 等),可以考虑提取公共基类或使用模板减少重复
  3. ShowFlag 命令懒初始化 :当前 CreateShowFlagCommandsRegisterCommands 时全量创建所有 ShowFlag 的命令,而不管用户是否会打开对应的菜单。对于项目自定义的大量 ShowFlag,可以考虑延迟创建

3 类级代码注释详解

3.1 FCommonMenuExtensionsModule 类

概述

FCommonMenuExtensionsModule 是 CommonMenuExtensions 模块的唯一模块类,负责整个模块的生命周期管理。它在编辑器的 Startup 和 Shutdown 阶段作为总调度中心,协调所有子菜单命令类的注册和反注册。


核心设计理念:

  • 单一入口:所有菜单扩展的注册都在这一个模块类中完成
  • 镜像配对:启动和关闭的注册顺序互为镜像,确保资源正确释放
  • 全局单例 :每个 TCommands 子类都是全局唯一的单例

StartupModule() - 模块启动

cpp 复制代码
void FCommonMenuExtensionsModule::StartupModule()
{
    FBufferVisualizationMenuCommands::Register();
    FNaniteVisualizationMenuCommands::Register();
    FLumenVisualizationMenuCommands::Register();
    FSubstrateVisualizationMenuCommands::Register();
    FGroomVisualizationMenuCommands::Register();
    FVirtualShadowMapVisualizationMenuCommands::Register();
    FShowFlagMenuCommands::Register();
}

功能分析:

  1. 依次调用七个子菜单命令类的 Register() 静态方法
  2. Register()TCommands 基类提供的方法,它会触发 RegisterCommands() 虚函数
  3. 注册顺序没有硬性依赖,但代码按功能分组:可视化命令 → ShowFlag 命令

ShutdownModule() - 模块关闭

cpp 复制代码
void FCommonMenuExtensionsModule::ShutdownModule()
{
    FShowFlagMenuCommands::Unregister();
    FVirtualShadowMapVisualizationMenuCommands::Unregister();
    FNaniteVisualizationMenuCommands::Unregister();
    FGroomVisualizationMenuCommands::Unregister();
    FSubstrateVisualizationMenuCommands::Unregister();
    FLumenVisualizationMenuCommands::Unregister();
    FBufferVisualizationMenuCommands::Unregister();
}

功能分析:

  1. 反注册顺序与启动顺序完全镜像(倒序)
  2. Unregister()TCommands 基类提供的方法,用于从全局命令列表中移除
  3. 镜像释放是一种良好的资源管理惯用法------先注册的应该后释放,避免可能的依赖问题

设计意图:

  • 确保编辑器关闭时不会残留任何 UI 命令引用
  • 镜像顺序虽然在这里没有实际的依赖关系,但体现了一种防御性的编程习惯

3.2 FShowFlagMenuCommands 类

概述

FShowFlagMenuCommands 是负责整个"Show Flags"菜单的命令管理类。视口左上角的那个"Show"下拉菜单就是由它来填充的。它从引擎全局的 GetShowFlagMenuItems() 动态读取所有可用的 ShowFlag,为每一个自动生成 ToggleButton 类型的 UI 命令。


构造函数

cpp 复制代码
FShowFlagMenuCommands::FShowFlagMenuCommands()
    : TCommands<FShowFlagMenuCommands>
    (
        TEXT("ShowFlagsMenu"),                              // Context name
        NSLOCTEXT("Contexts", "ShowFlagsMenu", "Show Flags Menu"), // Localized name
        NAME_None,                                          // Parent context
        FAppStyle::GetAppStyleSetName()                     // Icon style set
    ),
    ShowFlagCommands(),
    bCommandsInitialised(false)
{
}

关键参数:

  • ContextName = "ShowFlagsMenu" --- 用于在命令系统中快速查找
  • Parent = NAME_None --- 没有父上下文,属于顶级命令组
  • StyleSetName --- 使用编辑器默认的 AppStyle

CreateShowFlagCommands() - 动态创建所有 ShowFlag 命令

cpp 复制代码
void FShowFlagMenuCommands::CreateShowFlagCommands()
{
    TBitArray<> ExistingCommands;
    // ... 构建已存在命令的位数组 ...

    const TArray<FShowFlagData>& AllShowFlags = GetShowFlagMenuItems();

    for (int32 ShowFlagIndex = 0; ShowFlagIndex < AllShowFlags.Num(); ++ShowFlagIndex)
    {
        const FShowFlagData& ShowFlag = AllShowFlags[ShowFlagIndex];
        // 跳过已经创建过命令的 Flag
        if (已存在) continue;

        const FText LocalizedName = GetLocalizedShowFlagName(ShowFlag);

        TSharedPtr<FUICommandInfo> ShowFlagCommand = FUICommandInfoDecl(
            this->AsShared(),
            ShowFlag.ShowFlagName,
            LocalizedName,
            ShowFlagDesc)
            .UserInterfaceType(EUserInterfaceActionType::ToggleButton)
            .DefaultChord(ShowFlag.InputChord)
            .Icon(GetShowFlagIcon(ShowFlag));

        ShowFlagCommands.Add(FShowFlagCommand(
            static_cast<FEngineShowFlags::EShowFlag>(ShowFlag.EngineShowFlagIndex),
            ShowFlagCommand,
            ShowFlag.DisplayName));
    }
}

功能分析:

  1. 去重检查 :使用 TBitArray 记录已存在的命令,避免重复创建(支持热更新,如果有新的 ShowFlag 被动态添加)
  2. 数据驱动 :从 GetShowFlagMenuItems() 获取引擎全局的 ShowFlag 列表------不需要在 CommonMenuExtensions 中硬编码任何 Flag 名称
  3. 本地化 :通过 GetLocalizedShowFlagName() 自动区分 SFG_Visualize 组的标签格式("Visualize XXX")和普通组的标签格式("Show XXX")
  4. 命令类型 :全部使用 ToggleButton,因为 ShowFlag 本质上就是开关
  5. 快捷键支持:直接将 ShowFlag 数据中预定义的快捷键绑定到 UI 命令

设计亮点:

  • 懒更新UpdateCustomShowFlags() 在每次构建菜单时都会检查命令数量是否与引擎中注册的 ShowFlag 数量一致。如果插件或项目新增了 ShowFlag,命令会自动扩展
  • 增量创建:不是每次都全量重建,而是只创建"还不存在的"命令

BuildShowFlagsMenu() - 构建完整菜单

cpp 复制代码
void FShowFlagMenuCommands::BuildShowFlagsMenu(UToolMenu* Menu, const FShowFlagFilter& Filter) const
{
    check(bCommandsInitialised);
    UpdateCustomShowFlags();

    const FShowFlagFilter::FGroupedShowFlagIndices& FlagIndices = Filter.GetFilteredIndices();
    if (FlagIndices.TotalIndices() < 1) return;

    // Section 1: 常用 ShowFlag
    {
        FToolMenuSection& Section = Menu->AddSection("ShowFlagsMenuSectionCommon",
            LOCTEXT("CommonShowFlagHeader", "Common Show Flags"));
        PopulateCommonShowFlagsSection(Section, Filter);
    }

    // Section 2: 全部分类的 ShowFlag 子菜单
    {
        FToolMenuSection& Section = Menu->AddSection("LevelViewportShowFlags",
            LOCTEXT("AllShowFlagHeader", "All Show Flags"));
        PopulateAllShowFlagsSection(Section, Filter);
    }
}

设计意图:

  • 两个 Section 分家 :常用的 SFG_Normal 组的 Flag 直接展示在顶层,方便快速切换;其他分类(后处理、灯光、Lumen、Nanite 等)分别放入子菜单,避免菜单过长
  • Filter 驱动 :通过传入不同的 FShowFlagFilter,同一个 BuildShowFlagsMenu 方法可以为不同的视口(如普通视口、Blueprint 编辑器视口、材质编辑器预览窗口)生成不同范围的菜单

PopulateAllShowFlagsSection() - 分组子菜单

cpp 复制代码
void FShowFlagMenuCommands::PopulateAllShowFlagsSection(FToolMenuSection& Section,
    const FShowFlagFilter& Filter) const
{
    CreateSubMenuIfRequired(Section, Filter, SFG_PostProcess,        "SFG_PostProcess",        ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_LightTypes,          "SFG_LightTypes",          ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_LightingComponents,  "SFG_LightingComponents",  ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_LightingFeatures,    "SFG_LightingFeatures",    ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_Lumen,               "SFG_Lumen",               ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_Nanite,              "SFG_Nanite",              ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_Developer,           "SFG_Developer",           ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_Visualize,           "SFG_Visualize",           ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_Advanced,            "SFG_Advanced",            ...);
    CreateSubMenuIfRequired(Section, Filter, SFG_Custom,              "SFG_Custom",              ...);
}

功能分析:

  • EShowFlagGroup 枚举的每个值创建一个子菜单
  • CreateSubMenuIfRequired 会先检查该组是否有匹配的 Flag(Filter.GetFilteredIndices()[Group].Num() > 0),没有就跳过------避免创建空子菜单
  • SFG_Custom 组不提供图标(NAME_None),因为自定义 Flag 的图标无法预知

BindCommands() - 绑定到视口

cpp 复制代码
void FShowFlagMenuCommands::BindCommands(FUICommandList& CommandList,
    const TSharedPtr<FEditorViewportClient>& Client) const
{
    for (const FShowFlagCommand& ShowFlagCommand : ShowFlagCommands)
    {
        CommandList.MapAction(
            ShowFlagCommand.ShowMenuItem,
            FExecuteAction::CreateStatic(&FShowFlagMenuCommands::ToggleShowFlag,
                Client.ToWeakPtr(), ShowFlagCommand.FlagIndex),
            FCanExecuteAction::CreateStatic(&FEngineShowFlags::IsForceFlagSet,
                static_cast<uint32>(ShowFlagCommand.FlagIndex)),
            FIsActionChecked::CreateStatic(&FShowFlagMenuCommands::IsShowFlagEnabled,
                Client.ToWeakPtr(), ShowFlagCommand.FlagIndex));
    }
}

三个回调的含义:

回调 作用
FExecuteAction 切换该 Flag 的开关状态
FCanExecuteAction 判断该 Flag 是否可切换(被强制的 Flag 不可切换,菜单项灰掉)
FIsActionChecked 获取该 Flag 当前是否启用(控制 ToggleButton 的选中/未选中状态)

安全考量:

  • Client.ToWeakPtr() --- 使用弱指针而非裸指针。如果视口在命令回调触发前被关闭,WeakClient.Pin() 将返回空,静默跳过操作,不会崩溃

3.3 FShowFlagFilter 类

概述

FShowFlagFilter 是一个轻量但精巧的过滤器,用于控制在 ShowFlag 菜单中展示哪些条目。它的设计可以让调用方以流畅的链式调用指定包含/排除规则。


过滤规则优先级

代码注释中明确列出了优先级(从高到低):

复制代码
1. 显式包含的 Flag    → IncludeFlag()
2. 显式排除的 Flag    → ExcludeFlag()
3. 包含的组           → IncludeGroup()
4. 排除的组           → ExcludeGroup()
5. 默认模式           → IncludeAllFlagsByDefault / ExcludeAllFlagsByDefault

ShouldIncludeFlag() - 核心判断逻辑

cpp 复制代码
bool FShowFlagFilter::ShouldIncludeFlag(const FShowFlagData& Flag) const
{
    if (IncludedFlags.Contains(static_cast<FEngineShowFlags::EShowFlag>(Flag.EngineShowFlagIndex)))
        return true;

    if (ExcludedFlags.Contains(static_cast<FEngineShowFlags::EShowFlag>(Flag.EngineShowFlagIndex)))
        return false;

    if (FlagGroupExistsInArray(IncludedGroups, Flag))
        return true;

    if (FlagGroupExistsInArray(ExcludedGroups, Flag))
        return false;

    return DefaultMode == IncludeAllFlagsByDefault;
}

设计亮点:

  • 短路求值:按优先级从高到低依次判断,一旦命中立即返回,避免不必要的计算
  • 组用数组而非 Set :代码注释明确说明------组的数量很少(SFG_Max 约 10 个),用数组在缓存层面效率更高
  • 链式调用 APIIncludeFlag().ExcludeGroup().IncludeGroup() 这种流式写法让调用方代码非常简洁易读

RebuildIndexArray() - 构建索引缓存

cpp 复制代码
void FShowFlagFilter::RebuildIndexArray() const
{
    AllowedFlagIndices.ClearAll();
    const TArray<FShowFlagData>& AllShowFlags = GetShowFlagMenuItems();

    for (uint32 Index = 0; Index < static_cast<uint32>(AllShowFlags.Num()); ++Index)
    {
        const FShowFlagData& Flag = AllShowFlags[Index];
        if (!ShouldIncludeFlag(Flag)) continue;
        AllowedFlagIndices[Flag.Group].Add(Index);
    }
}

功能分析:

  • 延迟计算 + 缓存bHaveFiltered 标记避免重复构建。只有第一次调用 GetFilteredIndices() 或显式 bForceRebuild = true 时才重新计算
  • 按组分类存储FGroupedShowFlagIndices 内部是一个按 EShowFlagGroup 索引的二维数组,每个组存储的是 GetShowFlagMenuItems() 数组中的索引(而非 Flag 本身),内存占用极低

3.4 可视化菜单命令类的统一模式

六个可视化菜单命令类(FBufferVisualizationMenuCommandsFNaniteVisualizationMenuCommandsFLumenVisualizationMenuCommandsFSubstrateVisualizationMenuCommandsFGroomVisualizationMenuCommandsFVirtualShadowMapVisualizationMenuCommands)共享完全相同的架构。这里以最典型的模式进行统一分析。


共同结构

复制代码
┌─────────────────────────────────────────────┐
│  class FxxxVisualizationMenuCommands         │
│    : public TCommands<Self>                  │
├─────────────────────────────────────────────┤
│  内部结构体:                                  │
│    struct FxxxVisualizationRecord {          │
│        FName Name;                           │
│        TSharedPtr<FUICommandInfo> Command;   │
│        EType Type;  // 分类                  │
│    };                                        │
├─────────────────────────────────────────────┤
│  关键成员:                                    │
│    TMultiMap<FName, Record> CommandMap;      │
├─────────────────────────────────────────────┤
│  关键方法:                                    │
│    BuildCommandMap()       → 读取数据源       │
│    BuildVisualisationSubMenu() → 构建菜单     │
│    AddCommandTypeToMenu()  → 按类型填充       │
│    BindCommands()          → 绑定到视口       │
│    RegisterCommands()      → BuildCommandMap()│
└─────────────────────────────────────────────┘

BuildCommandMap() 模式

FNaniteVisualizationMenuCommands 为例:

cpp 复制代码
void FNaniteVisualizationMenuCommands::BuildCommandMap()
{
    const FNaniteVisualizationData& VisualizationData = GetNaniteVisualizationData();
    const FNaniteVisualizationData::TModeMap& ModeMap = VisualizationData.GetModeMap();

    CommandMap.Empty();
    for (auto It = ModeMap.CreateConstIterator(); It; ++It)
    {
        const FNaniteVisualizationData::FModeRecord& Entry = It.Value();
        FNaniteVisualizationRecord& Record = CommandMap.Add(Entry.ModeName, ...);
        Record.Name = Entry.ModeName;
        Record.Command = FUICommandInfoDecl(this->AsShared(),
            Entry.ModeName, Entry.ModeText, Entry.ModeDesc)
            .UserInterfaceType(EUserInterfaceActionType::RadioButton)
            .DefaultChord(FInputChord());

        // 根据 ModeType 分类
        switch (Entry.ModeType)
        {
        case FModeType::Overview:  Record.Type = Overview;  break;
        case FModeType::Standard:  Record.Type = Standard;  break;
        case FModeType::Advanced:  Record.Type = Advanced;  break;
        }
    }
}

关键点:

  1. 数据源解耦GetNaniteVisualizationData() 是一个全局函数,返回 Nanite 渲染模块注册的可视化数据。CommonMenuExtensions 不需要知道 Nanite 有哪些模式------它只是把数据"翻译"成菜单项
  2. RadioButton 类型:可视化模式是互斥选择,不是开关,所以用 RadioButton 而非 ToggleButton
  3. 空快捷键 :可视化模式通常不需要快捷键,FInputChord() 即无快捷键

BuildVisualisationSubMenu() 模式

FNaniteVisualizationMenuCommands 为例:

cpp 复制代码
void FNaniteVisualizationMenuCommands::BuildVisualisationSubMenu(FMenuBuilder& Menu)
{
    const bool bShowAdvanced = GNaniteVisualizeAdvanced != 0;

    const auto& Commands = FNaniteVisualizationMenuCommands::Get();
    if (Commands.IsPopulated())
    {
        Menu.BeginSection("...", LOCTEXT("NaniteVisualizationHeader", "Nanite Visualization Mode"));

        if (Commands.AddCommandTypeToMenu(Menu, FNaniteVisualizationType::Overview))
            Menu.AddMenuSeparator();

        if (Commands.AddCommandTypeToMenu(Menu, FNaniteVisualizationType::Standard))
        {
            if (bShowAdvanced)
                Menu.AddMenuSeparator();
        }

        if (bShowAdvanced)
            Commands.AddCommandTypeToMenu(Menu, FNaniteVisualizationType::Advanced);

        Menu.EndSection();
    }
}

设计亮点:

  • CVar 控制高级模式r.Nanite.Visualize.Advanced 控制台变量为 0 时,Advanced 模式完全隐藏,保持菜单简洁
  • 智能分隔符:只在分类之间有内容时才插入分隔符,避免出现连续两个分隔线或末尾多余分隔线
  • IsPopulated() 保护:如果渲染模块没有注册任何可视化模式(例如在特定平台或配置下不可用),整个菜单段都不会出现,而不是显示一个空的灰色菜单

BindCommands() 模式

FBufferVisualizationMenuCommands 为例:

cpp 复制代码
void FBufferVisualizationMenuCommands::BindCommands(FUICommandList& CommandList,
    const TSharedPtr<FEditorViewportClient>& Client) const
{
    for (TCommandConstIterator It = CreateCommandConstIterator(); It; ++It)
    {
        const FBufferVisualizationRecord& Record = It.Value();
        CommandList.MapAction(
            Record.Command,
            FExecuteAction::CreateStatic(&ChangeBufferVisualizationMode,
                Client.ToWeakPtr(), Record.Name),
            FCanExecuteAction(),
            FIsActionChecked::CreateStatic(&IsBufferVisualizationModeSelected,
                Client.ToWeakPtr(), Record.Name));
    }
}

三个回调:

回调 行为
ChangeXxxMode 调用 Client->ChangeXxxVisualizationMode(Name)
FCanExecuteAction() 空委托------始终可执行
IsXxxModeSelected 调用 Client->IsXxxVisualizationModeSelected(Name)

和 ShowFlag 的 BindCommands 的关键区别:

  • 可视化菜单的 FCanExecuteAction 是空的(总是可执行),而 ShowFlag 的 FCanExecuteAction 检查 IsForceFlagSet(被强制的 Flag 不可切换)
  • 可视化菜单是 RadioButton(互斥选择),ShowFlag 是 ToggleButton(独立开关)

FVirtualShadowMapVisualizationMenuCommands 的特殊之处

VSM(Virtual Shadow Map)的命令类比其他可视化类多了两个额外功能:

1. Console Command 绑定

cpp 复制代码
UI_COMMAND(VisualizeNextLightCommand, "Visualize next light",
    "r.Shadow.Virtual.Visualize.NextLight",
    EUserInterfaceActionType::Button, FInputChord());
UI_COMMAND(VisualizePrevLightCommand, "Visualize previous light",
    "r.Shadow.Virtual.Visualize.PrevLight",
    EUserInterfaceActionType::Button, FInputChord());

这两个命令不是 RadioButton,而是 Button 类型。它们绑定到控制台命令而非视口客户端方法:

cpp 复制代码
CommandList.MapAction(VisualizeNextLightCommand,
    FExecuteAction::CreateLambda([]() {
        IConsoleCommand* Command = IConsoleManager::Get()
            .FindConsoleObject(TEXT("r.Shadow.Virtual.Visualize.NextLight"))->AsCommand();
        TArray<FString> Args;
        Command->Execute(Args, nullptr, *GLog);
    }),
    FCanExecuteAction(),
    EUIActionRepeatMode::RepeatEnabled);  // 支持长按重复

2. CVar 控制 Advanced 模式

cpp 复制代码
int32 GVirtualShadowMapVisualizeAdvanced = 0;
static FAutoConsoleVariableRef CVarVirtualShadowMapVisualizeAdvanced(
    TEXT("r.Shadow.Virtual.Visualize.Advanced"),
    GVirtualShadowMapVisualizeAdvanced,
    TEXT("Enable to show advanced VSM debug modes in the visualization UI menu.")
);

这个模式与 Nanite 的 r.Nanite.Visualize.Advanced 如出一辙------运行时通过控制台命令切换高级调试选项的可见性。


FGroomVisualizationMenuCommands 的特殊之处

Groom(毛发)的命令类有一个额外的功能:

cpp 复制代码
static void BuildVisualisationSubMenu(FMenuBuilder& Menu);
static void BuildVisualisationSubMenuForGroomEditor(FMenuBuilder& Menu);

它提供了两个构建菜单的入口:

  • BuildVisualisationSubMenu --- 用于普通视口,不显示 MacroGroupsLightBoundsDeepOpacityMaps 等部分模式
  • BuildVisualisationSubMenuForGroomEditor --- 用于 Groom 专用编辑器,显示全部模式

两套菜单通过 bIsGroomEditor 参数共享 InternalBuildVisualisationSubMenu 实现,避免了代码重复。


3.5 FEditorViewportClient 交互总结

所有菜单命令的最终执行都汇聚到 FEditorViewportClient 的方法上:

菜单系统 ViewportClient 方法调用
ShowFlag 切换 HandleToggleShowFlag(EngineShowFlagIndex)
ShowFlag 状态查询 HandleIsShowFlagEnabled(EngineShowFlagIndex)
Buffer Visualization ChangeBufferVisualizationMode(InName) / IsBufferVisualizationModeSelected(InName)
Nanite Visualization ChangeNaniteVisualizationMode(InName) / IsNaniteVisualizationModeSelected(InName)
Lumen Visualization ChangeLumenVisualizationMode(InName) / IsLumenVisualizationModeSelected(InName)
Substrate Visualization ChangeSubstrateVisualizationMode(InName) / IsSubstrateVisualizationModeSelected(InName)
Groom Visualization ChangeGroomVisualizationMode(InName) / IsGroomVisualizationModeSelected(InName)
VSM Visualization ChangeVirtualShadowMapVisualizationMode(InName) / IsVirtualShadowMapVisualizationModeSelected(InName)

可以看到,CommonMenuExtensions 只是"翻译官"------把引擎渲染数据翻译成菜单项,把用户点击翻译回客户端方法调用。渲染逻辑本身不需要知道菜单系统的存在。


4 功能使用示例编写

示例1:在自定义编辑器视口中集成 ShowFlag 菜单

假如我们正在开发一个自定义的编辑器工具,内置了一个预览视口。我们希望这个视口的 Show 菜单能过滤掉不相关的 Flag。

cpp 复制代码
// MyCustomViewportClient.h
#pragma once

#include "EditorViewportClient.h"
#include "ShowFlagFilter.h"

class FMyCustomViewportClient : public FEditorViewportClient
{
public:
    FMyCustomViewportClient();
    
    // 构建自定义的 ShowFlag 菜单
    void BuildCustomShowFlagsMenu(UToolMenu* Menu);

private:
    FShowFlagFilter CustomFilter;
};
cpp 复制代码
// MyCustomViewportClient.cpp
#include "MyCustomViewportClient.h"
#include "ShowFlagMenuCommands.h"

FMyCustomViewportClient::FMyCustomViewportClient()
    : FEditorViewportClient(nullptr, nullptr, nullptr)
    , CustomFilter(FShowFlagFilter::IncludeAllFlagsByDefault)
{
    // 排除不适用于自定义视口的组
    CustomFilter
        .ExcludeGroup(SFG_Developer)      // 开发者调试 Flag 不需要
        .ExcludeGroup(SFG_Advanced)       // 高级 Flag 不需要
        .ExcludeGroup(SFG_Lumen)          // 自定义视口不用 Lumen
        .ExcludeGroup(SFG_Nanite);        // 自定义视口不用 Nanite

    // 也可以排除单个 Flag
    CustomFilter.ExcludeFlag(FEngineShowFlags::EShowFlag::SF_Bounds);
    CustomFilter.ExcludeFlag(FEngineShowFlags::EShowFlag::SF_Collision);
}

void FMyCustomViewportClient::BuildCustomShowFlagsMenu(UToolMenu* Menu)
{
    FShowFlagMenuCommands::Get().BuildShowFlagsMenu(Menu, CustomFilter);
}

效果: 构建出来的菜单会自动隐藏被排除的组和 Flag,保持菜单简洁,只展示与这个视口相关的选项。


示例2:扩展新的可视化菜单

假设渲染团队新增了一个叫"MyRenderer"的渲染管线,我们希望为它添加一个可视化调试菜单。只需要三个步骤:

第一步:在自己的渲染模块中定义可视化数据

cpp 复制代码
// MyRendererVisualizationData.h(在渲染模块中)
#pragma once

#include "MyRendererVisualizationData.generated.h"

USTRUCT()
struct FMyRendererVisualizationData
{
    // ... 参照 NaniteVisualizationData 的实现 ...
    
    struct FModeRecord
    {
        FName ModeName;
        FText ModeText;
        FText ModeDesc;
        // ...
    };
    
    using TModeMap = TMap<FName, FModeRecord>;
    const TModeMap& GetModeMap() const;
};

// 全局访问函数
const FMyRendererVisualizationData& GetMyRendererVisualizationData();

第二步:在 CommonMenuExtensions 中新增菜单命令类

cpp 复制代码
// MyRendererVisualizationMenuCommands.h
#pragma once

#include "Framework/Commands/Commands.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"

class COMMONMENUEXTENSIONS_API FMyRendererVisualizationMenuCommands
    : public TCommands<FMyRendererVisualizationMenuCommands>
{
public:
    FMyRendererVisualizationMenuCommands();

    // 参照其他可视化类实现以下方法:
    TCommandConstIterator CreateCommandConstIterator() const;
    static void BuildVisualisationSubMenu(FMenuBuilder& Menu);
    virtual void RegisterCommands() override;
    void BindCommands(FUICommandList& CommandList,
        const TSharedPtr<FEditorViewportClient>& Client) const;
    inline bool IsPopulated() const { return CommandMap.Num() > 0; }

private:
    struct FMyRendererVisualizationRecord
    {
        FName Name;
        TSharedPtr<FUICommandInfo> Command;
    };

    void BuildCommandMap();

    static void ChangeMyRendererVisualizationMode(
        TWeakPtr<FEditorViewportClient> WeakClient, FName InName);
    static bool IsMyRendererVisualizationModeSelected(
        TWeakPtr<FEditorViewportClient> WeakClient, FName InName);

    TMultiMap<FName, FMyRendererVisualizationRecord> CommandMap;
};
cpp 复制代码
// MyRendererVisualizationMenuCommands.cpp
#include "MyRendererVisualizationMenuCommands.h"
#include "MyRendererVisualizationData.h"   // 来自渲染模块
#include "EditorViewportClient.h"

// 参照 Nanite 或 Lumen 的实现,复制粘贴改改名字即可
// ...(具体实现略)...

第三步:在模块入口注册

CommonMenuExtensionsModule.cpp(file:///f:/UE/UE_5.5/Engine/Source/Editor/CommonMenuExtensions/Private/CommonMenuExtensionsModule.cpp) 中:

cpp 复制代码
#include "MyRendererVisualizationMenuCommands.h"

void FCommonMenuExtensionsModule::StartupModule()
{
    // ... 现有的 Register ...
    FMyRendererVisualizationMenuCommands::Register();  // 新增这一行
}

void FCommonMenuExtensionsModule::ShutdownModule()
{
    FMyRendererVisualizationMenuCommands::Unregister();  // 新增这一行
    // ... 现有的 Unregister ...
}

完成。这就是 CommonMenuExtensions 作为"菜单注册中心"的扩展能力------大部分代码都可以从现有类复制粘贴,只改名字即可


示例3:动态启用/禁用高级调试模式

Nanite 和 VirtualShadowMap 的高级可视化模式通过控制台变量控制显示。我们可以在自定义工具中切换这些变量:

cpp 复制代码
void UMyEditorTool::ToggleNaniteAdvancedDebug(bool bEnable)
{
    // 运行时切换控制台变量
    IConsoleVariable* CVar = IConsoleManager::Get()
        .FindConsoleVariable(TEXT("r.Nanite.Visualize.Advanced"));
    if (CVar)
    {
        CVar->Set(bEnable ? 1 : 0);
    }
    
    // 注意:菜单内容不会自动刷新,需要视口下次打开菜单时才会看到变化
    // 这是因为 BuildVisualisationSubMenu 在每次打开菜单时调用,
    // 会重新读取控制台变量的值
}

示例4:ShowFlagFilter 的高级用法

结合使用包含和排除构造精确的过滤规则:

cpp 复制代码
// 场景:只显示灯光相关的 ShowFlag,但要排除"环境光遮蔽"这一个 Flag
FShowFlagFilter LightOnlyFilter(FShowFlagFilter::ExcludeAllFlagsByDefault);
LightOnlyFilter
    .IncludeGroup(SFG_LightTypes)
    .IncludeGroup(SFG_LightingComponents)
    .IncludeGroup(SFG_LightingFeatures)
    .ExcludeFlag(FEngineShowFlags::EShowFlag::SF_AmbientOcclusion);

// 等价写法:全包含默认,排除除了灯光之外的所有组
FShowFlagFilter LightOnlyFilter2(FShowFlagFilter::IncludeAllFlagsByDefault);
LightOnlyFilter2
    .ExcludeGroup(SFG_Normal)
    .ExcludeGroup(SFG_PostProcess)
    .ExcludeGroup(SFG_Developer)
    .ExcludeGroup(SFG_Visualize)
    .ExcludeGroup(SFG_Advanced)
    .ExcludeGroup(SFG_Lumen)
    .ExcludeGroup(SFG_Nanite)
    .ExcludeGroup(SFG_Custom)
    .ExcludeFlag(FEngineShowFlags::EShowFlag::SF_AmbientOcclusion);

两种写法功能等价,但第一种更简洁------当默认模式是"排除所有"时,只需显式包含需要的组即可。具体选哪种取决于使用场景的默认倾向。


5 总结与最佳实践

核心要点

  1. CommonMenuExtensions 是"翻译官",不是"功能实现者"

    • 它不实现任何渲染逻辑,所有可视化切换逻辑都在 FEditorViewportClient 和各渲染系统内部
    • 它的唯一职责是从渲染数据中读取可用模式,翻译成菜单项,再把用户操作翻译回客户端方法调用
  2. TCommands 模式是 UE 编辑器 UI 的基础设施

    • 所有菜单命令都通过 TCommands<T> 模板类注册到全局命令系统
    • RegisterCommands() 在模块启动时被调用,Unregister() 在关闭时清理
    • CRTP(奇异递归模板模式)使得每个命令类都是全局单例
  3. 数据驱动优于硬编码

    • ShowFlag 菜单的内容来自 GetShowFlagMenuItems()
    • 可视化菜单的内容来自 GetXxxVisualizationData()
    • 新增渲染模式不需要修改 CommonMenuExtensions 的菜单逻辑,只在渲染模块登记数据即可
  4. RadioButton vs ToggleButton 的选择

    • 互斥选择(如可视化模式)→ RadioButton
    • 独立开关(如 ShowFlag)→ ToggleButton
  5. 弱指针安全模式

    • 所有命令回调都使用 TWeakPtr<FEditorViewportClient>
    • 回调中先 Pin() 检查有效性,静默处理已销毁的视口

最佳实践

  1. 新增可视化菜单时,复制现有代码改名字即可

    • 所有六个可视化菜单类遵循完全相同模式
    • 选择最接近需求的那个(如 Lumen 最简单,Nanite 支持 CVar 控制的 Advanced 模式)作为模板
  2. Take care of menu section transitions

    • 使用 AddCommandTypeToMenu 的返回值判断是否需要分隔符
    • 避免在空分组后留下孤立的 separator
  3. 镜像配对 Register/Unregister

    • 始终确保 ShutdownModule 中的 Unregister 顺序与 StartupModule 中的 Register 顺序相反
    • 这是资源管理中公认的安全习惯
  4. ShowFlagFilter 使用链式调用

    • IncludeXxxExcludeXxx 都返回 *this,允许流式 API
    • 选择默认模式时,IncludeAllFlagsByDefault 适合"排除少数不需要的",ExcludeAllFlagsByDefault 适合"只包含少数需要的"
  5. 不要直接持有 ViewportClient 的裸指针

    • 使用 TWeakPtr 存储,回调中通过 Pin() 访问
    • 视口可能在任意时刻被关闭(用户关闭编辑器标签页、切换布局等)

常见问题解决

问题1:新增的 ShowFlag 没有出现在菜单中

  • 确认 ShowFlag 已在引擎中正确注册(通常在 EngineShowFlags.h 中定义)
  • 检查 FShowFlagFilter 的过滤规则是否意外排除了该 Flag
  • 确认菜单命令数量与 GetShowFlagMenuItems() 返回数量一致(UpdateCustomShowFlags 会动态检测)

问题2:可视化菜单显示为空

  • 确认对应渲染模块已正确加载(某些渲染功能可能需要特定 RHI 或平台支持)
  • 检查 IsPopulated() 返回值
  • 例如 Nanite 在支持 Nanite 的平台上才有可视化数据

问题3:Advanced 模式不出现

  • Nanite:检查 r.Nanite.Visualize.Advanced 是否为 0
  • VSM:检查 r.Shadow.Virtual.Visualize.Advanced 是否为 0
  • 菜单在每次打开时重新读取 CVar 值,所以修改后需要重新打开菜单

问题4:自定义视口的菜单项灰掉

  • ShowFlag 菜单项灰掉通常是因为该 Flag 被引擎强制设置了(IsForceFlagSet 返回 true)
  • 这通常发生在项目设置或 PostProcess Volume 覆盖了 ShowFlag 时
  • 在控制台用 ShowFlag.Xxx 命令可以覆盖强制设置

附录

A. 相关源码文件

文件 说明
FEngineShowFlags ShowFlag 的底层数据结构定义
EditorShowFlags.h GetShowFlagMenuItems() 和数据结构的声明
FEditorViewportClient 编辑器视口客户端,承载所有可视化切换方法
BufferVisualizationData Buffer Visualization 模式的注册表
NaniteVisualizationData Nanite Visualization 模式的注册表
LumenVisualizationData Lumen Visualization 模式的注册表
SubstrateVisualizationData Substrate Visualization 模式的注册表
GroomVisualizationData Groom Visualization 模式的注册表
VirtualShadowMapVisualizationData VSM Visualization 模式的注册表

B. 模块文件结构

复制代码
CommonMenuExtensions/
├── CommonMenuExtensions.Build.cs
├── Public/
│   ├── CommonMenuExtensionsModule.h
│   ├── BufferVisualizationMenuCommands.h
│   ├── NaniteVisualizationMenuCommands.h
│   ├── LumenVisualizationMenuCommands.h
│   ├── SubstrateVisualizationMenuCommands.h
│   ├── GroomVisualizationMenuCommands.h
│   ├── VirtualShadowMapVisualizationMenuCommands.h
│   ├── ShowFlagMenuCommands.h
│   └── ShowFlagFilter.h
└── Private/
    ├── CommonMenuExtensionsModule.cpp
    ├── BufferVisualizationMenuCommands.cpp
    ├── NaniteVisualizationMenuCommands.cpp
    ├── LumenVisualizationMenuCommands.cpp
    ├── SubstrateVisualizationMenuCommands.cpp
    ├── GroomVisualizationMenuCommands.cpp
    ├── VirtualShadowMapVisualizationMenuCommands.cpp
    ├── ShowFlagMenuCommands.cpp
    └── ShowFlagFilter.cpp
相关推荐
日月云棠1 小时前
UE5源码分析之Editor——ClothingSystemEditorInterface模块全面分析
ue5
日月云棠2 小时前
UE5源码分析之Editor——ClothPainter插件全面分析
ue5
[苦行僧]10 小时前
ue5 异步 Task
ue5
曼巴UE53 天前
Unlua UE5.3 调试
ue5·lua·unlua
远离UE45 天前
UE5 母材质 编写笔记
笔记·ue5·材质
远离UE45 天前
UE5 HLSLTranslator 与 ShaderCompiler
ue5
1204157137 肖哥6 天前
UE5.7 场景打光管线流程_【雪山】
ue5
weixin_404679316 天前
虚幻5 替代小白人角色的完整逻辑
ue5
1204157137 肖哥9 天前
UE5.7 灯光详解
ue5