CommonMenuExtensions 插件全面系统分析
目录
### 文章目录
- [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(编辑器视口客户端),以及各渲染系统的可视化数据组件(BufferVisualizationData、NaniteVisualizationData、LumenVisualizationData 等)。
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 不是一个功能模块,而是一个"桥接层"。它的核心价值在于:
-
解耦:每个渲染子系统(Buffer Visualization、Nanite、Lumen 等)的可视化数据定义在自己的模块里,但菜单的注册和管理统一放在 CommonMenuExtensions 中。如果将来某个渲染功能被废弃或替换,只需要在这里添加/移除一个 Register/Unregister 调用,渲染模块本身不需要知道菜单系统的存在。
-
统一模式 :所有可视化菜单命令都遵循一模一样的设计模式:继承
TCommands→ 构建CommandMap→ 注册命令 → 绑定到视口客户端。任何人要新增一个可视化菜单,照着现有代码复制改改五分钟就能搞定。 -
关注点分离 :
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 架构设计优势
- 高度统一的模式:六个可视化菜单类遵循完全相同的设计模式,学习成本低,维护成本低
- 数据驱动:菜单内容不由代码写死,而是从各渲染系统的可视化数据注册表中动态读取。新增一种可视化模式只需在对应渲染模块里注册数据,菜单会自动展现
- 模块边界清晰 :CommonMenuExtensions 只负责"菜单注册"这一件事。可视化模式的具体含义、切换逻辑都留在各渲染模块中,通过
FEditorViewportClient的方法间接调用 - 关注点分离:ShowFlag 菜单(通用渲染开关)和可视化菜单(特定管线的调试视图)分别由不同的类管理
- 安全的生命周期管理 :对
FEditorViewportClient使用TWeakPtr,避免视口关闭后回调访问悬空指针 - 灵活过滤系统 :
FShowFlagFilter采用优先级链式调用,使用者可以精确控制菜单中展示哪些条目
潜在改进点
- 旧版 API 混用 :
FBufferVisualizationMenuCommands::BuildVisualisationSubMenu仍在使用FMenuBuilder(旧版),而其他类已经迁移到UToolMenu。可以考虑统一升级 - C++ 模板化 :六个可视化菜单类共享大量相似代码(
BuildCommandMap、BindCommands、CreateCommandConstIterator等),可以考虑提取公共基类或使用模板减少重复 - ShowFlag 命令懒初始化 :当前
CreateShowFlagCommands在RegisterCommands时全量创建所有 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();
}
功能分析:
- 依次调用七个子菜单命令类的
Register()静态方法 Register()是TCommands基类提供的方法,它会触发RegisterCommands()虚函数- 注册顺序没有硬性依赖,但代码按功能分组:可视化命令 → ShowFlag 命令
ShutdownModule() - 模块关闭
cpp
void FCommonMenuExtensionsModule::ShutdownModule()
{
FShowFlagMenuCommands::Unregister();
FVirtualShadowMapVisualizationMenuCommands::Unregister();
FNaniteVisualizationMenuCommands::Unregister();
FGroomVisualizationMenuCommands::Unregister();
FSubstrateVisualizationMenuCommands::Unregister();
FLumenVisualizationMenuCommands::Unregister();
FBufferVisualizationMenuCommands::Unregister();
}
功能分析:
- 反注册顺序与启动顺序完全镜像(倒序)
Unregister()是TCommands基类提供的方法,用于从全局命令列表中移除- 镜像释放是一种良好的资源管理惯用法------先注册的应该后释放,避免可能的依赖问题
设计意图:
- 确保编辑器关闭时不会残留任何 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));
}
}
功能分析:
- 去重检查 :使用
TBitArray记录已存在的命令,避免重复创建(支持热更新,如果有新的 ShowFlag 被动态添加) - 数据驱动 :从
GetShowFlagMenuItems()获取引擎全局的 ShowFlag 列表------不需要在 CommonMenuExtensions 中硬编码任何 Flag 名称 - 本地化 :通过
GetLocalizedShowFlagName()自动区分SFG_Visualize组的标签格式("Visualize XXX")和普通组的标签格式("Show XXX") - 命令类型 :全部使用
ToggleButton,因为 ShowFlag 本质上就是开关 - 快捷键支持:直接将 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 个),用数组在缓存层面效率更高 - 链式调用 API :
IncludeFlag().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 可视化菜单命令类的统一模式
六个可视化菜单命令类(FBufferVisualizationMenuCommands、FNaniteVisualizationMenuCommands、FLumenVisualizationMenuCommands、FSubstrateVisualizationMenuCommands、FGroomVisualizationMenuCommands、FVirtualShadowMapVisualizationMenuCommands)共享完全相同的架构。这里以最典型的模式进行统一分析。
共同结构
┌─────────────────────────────────────────────┐
│ 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;
}
}
}
关键点:
- 数据源解耦 :
GetNaniteVisualizationData()是一个全局函数,返回 Nanite 渲染模块注册的可视化数据。CommonMenuExtensions 不需要知道 Nanite 有哪些模式------它只是把数据"翻译"成菜单项 - RadioButton 类型:可视化模式是互斥选择,不是开关,所以用 RadioButton 而非 ToggleButton
- 空快捷键 :可视化模式通常不需要快捷键,
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--- 用于普通视口,不显示MacroGroups、LightBounds、DeepOpacityMaps等部分模式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 总结与最佳实践
核心要点
-
CommonMenuExtensions 是"翻译官",不是"功能实现者"
- 它不实现任何渲染逻辑,所有可视化切换逻辑都在
FEditorViewportClient和各渲染系统内部 - 它的唯一职责是从渲染数据中读取可用模式,翻译成菜单项,再把用户操作翻译回客户端方法调用
- 它不实现任何渲染逻辑,所有可视化切换逻辑都在
-
TCommands 模式是 UE 编辑器 UI 的基础设施
- 所有菜单命令都通过
TCommands<T>模板类注册到全局命令系统 RegisterCommands()在模块启动时被调用,Unregister()在关闭时清理- CRTP(奇异递归模板模式)使得每个命令类都是全局单例
- 所有菜单命令都通过
-
数据驱动优于硬编码
- ShowFlag 菜单的内容来自
GetShowFlagMenuItems() - 可视化菜单的内容来自
GetXxxVisualizationData() - 新增渲染模式不需要修改 CommonMenuExtensions 的菜单逻辑,只在渲染模块登记数据即可
- ShowFlag 菜单的内容来自
-
RadioButton vs ToggleButton 的选择
- 互斥选择(如可视化模式)→ RadioButton
- 独立开关(如 ShowFlag)→ ToggleButton
-
弱指针安全模式
- 所有命令回调都使用
TWeakPtr<FEditorViewportClient> - 回调中先
Pin()检查有效性,静默处理已销毁的视口
- 所有命令回调都使用
最佳实践
-
新增可视化菜单时,复制现有代码改名字即可
- 所有六个可视化菜单类遵循完全相同模式
- 选择最接近需求的那个(如 Lumen 最简单,Nanite 支持 CVar 控制的 Advanced 模式)作为模板
-
Take care of menu section transitions
- 使用
AddCommandTypeToMenu的返回值判断是否需要分隔符 - 避免在空分组后留下孤立的 separator
- 使用
-
镜像配对 Register/Unregister
- 始终确保 ShutdownModule 中的 Unregister 顺序与 StartupModule 中的 Register 顺序相反
- 这是资源管理中公认的安全习惯
-
ShowFlagFilter 使用链式调用
IncludeXxx和ExcludeXxx都返回*this,允许流式 API- 选择默认模式时,
IncludeAllFlagsByDefault适合"排除少数不需要的",ExcludeAllFlagsByDefault适合"只包含少数需要的"
-
不要直接持有 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