关于 ohos-dev-graphics3d-combined-postprocess
该技能指导在 OpenHarmony Graphics3D 的 LumeRender、Lume3D 和 LumeScene 中实现单次渲染通道后处理效果,并说明实现顺序及 Combined 流程的适用边界。
主要功能
- 01三模块实现流程
- 02配置到着色器的数据映射
- 03着色器与渲染管线集成
- 04ECS 组件和场景 API 注册
- 05参数与索引限制说明
适用场景
- 01添加色调映射或色彩分级
- 02实现单次通道的暗角效果
- 03判断效果是否需要多通道管线
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openharmonyinsight/ openharmony-skills --skill ohos-dev-graphics3d-combined-postprocess安装后在 Claude Code 中输入/ohos-dev-graphics3d-combined-postprocess确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
README.mdreferences/advanced_reference.mdcode_templates.md详细介绍
Combined 后期处理实现指南
按照以下依赖链,在三个模块中实现 Combined 后期处理效果: LumeRender → Lume3D → LumeScene
任务和适用范围
本指南介绍如何在 OpenHarmony Graphics3D 中实现单次处理通道的后期处理效果。
适用范围:
- 在单个全屏着色器通道中运行的效果(色调映射、色彩分级、暗角)
- 向 Combined 后期处理系统添加效果
不适用范围:
- 需要单独渲染通道的效果(需要模糊通道的泛光、景深、运动模糊)
模块依赖关系概览
LumeRender (AGPRender)
↓
Lume3D (AGP3D)
↓
LumeScene
- LumeRender:底层渲染模块,提供着色器/渲染节点基础设施
- Lume3D:3D 场景模块,提供 ECS 组件,依赖于 LumeRender
- LumeScene:高层场景模块,提供易用的接口,依赖于 Lume3D
实现前检查清单
实现任何 Combined 后期处理效果之前,请先问自己:
- 视觉效果目标:你想实现什么视觉效果?(色调映射、色彩分级、暗角、自定义效果)
- 参数复杂度:此效果需要多少个参数?
- 1-4 个参数:仅使用
factors[]Vec4 - 5-8 个参数:拆分到
factors[]+userFactors[] -
8 个参数:考虑此效果是否适用于 Combined 系统
- 1-4 个参数:仅使用
- 渲染通道要求:此效果是否需要中间帧缓冲区?
- 单个全屏通道:✓ 使用 Combined 后期处理(本指南)
- 模糊通道、缩小/放大、时域处理:✗ 使用多通道系统(不适用于本指南)
- 索引可用性:Combined 系统中的索引 0-7 是否可用?
- 当前已使用:0(色调)、1(暗角)、2(抖动)、3(色彩转换)、4(色差)、5(升频)、6(白平衡)、7(色彩调整)
- 需要未使用的索引:必须在着色器和 C++ 中注册新索引
决策树:
Effect needs >4 params? ─────YES──→ Split: factors[] + userFactors[]
│
NO
↓
Effect needs blur/temporal? ─YES──→ Use multi-pass system (EXIT this skill)
│
NO
↓
Index 0-7 available? ──────YES──→ Continue with Combined implementation ✓
│
NO
↓
Need to register new index → Follow LumeRender Step 1-3 first
工作流
LumeRender(8 个步骤):
- 定义配置结构
- 注册元数据
- 定义着色器常量
- 实现配置到着色器的转换
- 填充后期处理栈
- 在 RenderNodeUtil 中添加转换
- 实现着色器处理函数
- 集成到渲染管线
Lume3D(5 个步骤):
- 添加标志位
- 定义组件属性
- 注册元数据
- 集成到渲染系统
- 集成到 Lume3D 着色器
LumeScene(9 个步骤):
- 定义接口
- 添加到 IPostProcess 接口
- 实现 API 封装
- 实现效果类
- 在 PostProcess 中注册
- 注册组件类型
- 注册插件类型
- 注册 Any 类型
- 更新构建文件
LumeRender 实现
必须阅读整个文件:开始 LumeRender 步骤之前,必须完整阅读 references/code_templates.md 中的“LumeRender Templates”部分(步骤 1-8,约 300 行)。读取此文件时不得设置任何范围限制。
暂时不要加载 advanced_reference.md —— 留到故障排查阶段再查看。
步骤 1:定义配置结构
文件:api/render/datastore/render/render_data_store_render_pods.h
定义包含属性和默认值的效果配置结构体。添加枚举索引、标志位和属性类型声明。
详情:请参阅 references/code_templates.md#step-1-define-configuration-structure
步骤 2:注册元数据
文件:src/postprocesses/render_post_process_combined_node.cpp
为反射系统注册枚举值、类型元数据和配置结构元数据。
详情:请参阅 references/code_templates.md#step-2-register-metadata
第 3 步:定义着色器常量
文件:api/render/shaders/common/render_post_process_structs_common.h
为效果专用化位和索引定义着色器宏常量。
详情:参见 references/code_templates.md#step-3-define-shader-constants
第 4 步:实现配置到着色器的转换
文件:src/datastore/render_data_store_post_process.h
实现转换函数,将配置打包为适用于着色器的 Vec4 因子。
详情:参见 references/code_templates.md#step-4-implement-config-to-shader-conversion
第 5 步:填充后处理堆栈
文件:src/datastore/render_data_store_post_process.cpp
将效果及内置数据和因子添加到后处理堆栈。
详情:参见 references/code_templates.md#step-5-fill-post-process-stack
第 6 步:在 RenderNodeUtil 中添加转换
文件:src/nodecontext/render_node_util.cpp
在 GetRenderPostProcessConfiguration() 函数中添加因子转换调用。
详情:参见 references/code_templates.md#step-6-add-conversion-in-rendernodeutil
第 7 步:实现着色器处理函数
文件:api/render/shaders/common/render_post_process_blocks.h
实现包含效果逻辑的 GLSL 着色器处理函数。
详情:参见 references/code_templates.md#step-7-implement-shader-processing-function
第 8 步:集成到渲染管线
文件:assets/render/shaders/shader/fullscreen_combined_post_process.frag
在全屏渲染管线中调用着色器处理函数。
详情:参见 references/code_templates.md#step-8-integrate-into-render-pipeline
Lume3D 实现
必须阅读本节:现在请阅读 references/code_templates.md 中的“Lume3D Templates”部分(步骤 1–5,约 100 行),了解 ECS 集成示例。
暂勿加载 advanced_reference.md——继续按照工作流步骤操作。
第 1 步:添加标志位
文件:api/3d/ecs/components/post_process_component.h
向 PostProcessComponent::FlagBits 枚举添加标志位。
详情:参见 references/code_templates.md#lume3d-step-1-add-flag-bit
第 2 步:定义组件属性
文件:api/3d/ecs/components/post_process_component.h
使用 DEFINE_PROPERTY 宏定义组件属性。
详情:参见 references/code_templates.md#lume3d-step-2-define-component-property
第 3 步:注册元数据
文件:src/ecs/components/post_process_component_manager.cpp
注册枚举值和配置元数据。
详情:参见 references/code_templates.md#lume3d-step-3-register-metadata
第 4 步:集成到渲染系统
文件:src/ecs/systems/render_system.cpp
在 ProcessPostProcessComponents() 函数中赋值配置。
详情:参见 references/code_templates.md#lume3d-step-4-integrate-into-render-system
第 5 步:集成到 Lume3D 着色器
文件:api/3d/shaders/common/3d_dm_inplace_post_process.h
在 Lume3D 原位后处理中调用着色器处理函数。
详情:参见 references/code_templates.md#lume3d-step-5-integrate-into-lume3d-shader
LumeScene 实现
必须阅读本节:阅读 references/code_templates.md 中的 “LumeScene Templates” 部分(步骤 1–9,约 400 行),了解 API 包装器和注册示例。
暂勿加载 advanced_reference.md ——仅在遇到错误或需要数据流图时加载。
步骤 1:定义接口
文件:include/scene/interface/postprocess/intf_your_effect.h
使用 META_INTERFACE 和属性声明定义接口类。
详情:请参阅 references/code_templates.md#lumescene-step-1-define-interface
步骤 2:添加到 IPostProcess 接口
文件:include/scene/interface/intf_postprocess.h
为效果接口添加 include 和 META_READONLY_PROPERTY。
详情:请参阅 references/code_templates.md#lumescene-step-2-add-to-ipostprocess-interface
步骤 3:实现 API 包装器
文件:include/scene/api/post_process.h
使用 META_INTERFACE_OBJECT 和属性宏实现包装器类。
详情:请参阅 references/code_templates.md#lumescene-step-3-implement-api-wrapper
步骤 4:实现效果类
文件:
- 头文件:
src/postprocess/your_effect.h - 实现文件:
src/postprocess/your_effect.cpp
实现继承自 PostProcessEffect 模板、包含 META_OBJECT 宏的效果类。
详情:请参阅 references/code_templates.md#lumescene-step-4-implement-effect-class
步骤 5:在 PostProcess 中注册
文件:
- 头文件:
src/postprocess/postprocess.h - 实现文件:
src/postprocess/postprocess.cpp
添加静态属性数据和 InitDynamicProperty 处理程序。
详情:请参阅 references/code_templates.md#lumescene-step-5-register-in-postprocess
步骤 6:注册组件类型
文件:src/component/postprocess_component.h
添加 META_TYPE 注册和属性宏。
详情:请参阅 references/code_templates.md#lumescene-step-6-register-component-type
步骤 7:注册插件类型
文件:src/plugin.cpp
添加 RegisterObjectType 和 UnregisterObjectType 调用。
详情:请参阅 references/code_templates.md#lumescene-step-7-register-plugin-type
步骤 8:注册 Any 类型
文件:src/register_anys.cpp
将接口指针类型添加到 ObjectTypes 列表中。
详情:请参阅 references/code_templates.md#lumescene-step-8-register-any-type
步骤 9:更新构建文件
文件:
include/CMakeLists.txtsrc/CMakeLists.txtBUILD.gn
将接口和源文件添加到构建目标中。
详情:请参阅 references/code_templates.md#lumescene-step-9-update-build-files
禁止的做法
切勿用于多通道效果
需要单独渲染通道的效果(带模糊的泛光、景深、运动模糊、FXAA、TAA):
- 原因:组合式后处理着色器(
fullscreen_combined_post_process.frag)仅处理索引 0-7。多通道效果使用索引 8 及以上,并通过单独的着色器和中间帧缓冲区处理。 - 后果:尝试使用组合式方法会导致组合式着色器忽略
factors[INDEX_BLOOM](索引 9)。效果不会渲染,或者可能会从错误的内存偏移处读取垃圾数据。 - 验证:检查效果是否需要中间渲染通道(模糊通道、缩小/放大)。如果需要 → 使用多通道系统,而非组合式方法。
- 正确做法:使用带有单独渲染节点图的专用多通道后处理实现。
切勿让着色器与 C++ 索引不匹配
GLSL 常量与 C++ 枚举之间的索引一致性:
- 原因:着色器直接访问
uGlobalData.factors[POST_PROCESS_INDEX_TONEMAP]。如果着色器定义POST_PROCESS_INDEX_TONEMAP 0,而 C++ 定义INDEX_TONEMAP 1,着色器就会从 factors 数组中读取错误的 Vec4。 - 后果:产生视觉瑕疵(颜色错误、参数未应用),或者索引超出
POST_PROCESS_GLOBAL_VEC4_FACTOR_COUNT (14)时出现 GPU 验证错误“array index out of bounds”。 - 验证:交叉检查以下三个文件:
- 着色器:
render_post_process_structs_common.h→POST_PROCESS_INDEX_*值 - C++ 配置:
render_data_store_render_pods.h→PostProcessConfiguration::INDEX_*值 - DataStore 转换:
render_data_store_post_process.cpp→factors[INDEX_*]赋值
- 着色器:
- 正确做法:确保三个位置使用相同的数值。文件注释明确指出:“需要与 api/core/render/render_data_store_render_pods.h 保持一致”。
参数超过 4 个时,切勿忘记 userFactors
需要超过 4 个浮点参数的效果:
- 原因:Vec4 只能容纳 4 个浮点数。GlobalPostProcessStruct 有
factors[14](Vec4 数组)和userFactors[16](Vec4 数组)。如果效果有 5 个或更多参数,则必须将参数拆分到 factors 和 userFactors 中。 - 后果:着色器尝试读取
uGlobalData.userFactors[USER_INDEX_*],但常量未定义 → 出现“undefined macro”编译错误。或者常量已定义但未填充 → 着色器读取全零 Vec4 → 效果参数错误。 - 验证:统计效果参数的数量。如果超过 4 个,请确认:
USER_INDEX_*常量已在render_data_store_render_pods.h中定义render_data_store_post_process.h中有用于 userFactors 的GetFactorXXX()函数- 着色器使用了正确的 userFactors 索引:
uGlobalData.userFactors[POST_PROCESS_USER_INDEX_*]
- 正确做法:对于 5-8 个参数:使用 factors[0-3] + userFactors[0-3]。定义
USER_INDEX_*常量,实现转换函数,并在 FillDefaultPostProcessData 中调用。
切勿跳过 LumeRender/Lume3D/LumeScene 一致性检查
必须更新全部三个模块:
- 原因:组合式后处理会经过三个模块:LumeRender 定义着色器常量 → Lume3D 集成到 ECS → LumeScene 封装 API。跳过任何一个模块都会中断整个链路。
- 后果:
- 跳过 LumeRender:着色器找不到
PostProcessXXXBlock()函数 → 编译错误 - 跳过 Lume3D:
PostProcessComponent缺少属性 → ECS 系统无法传递配置 → 着色器收到的 factors 全为零 - 跳过 LumeScene:缺少用户 API → 开发者无法配置效果 → 效果无法使用
- 跳过 LumeRender:着色器找不到
- 验证:使用实现检查清单(涵盖 3 个模块的 22 个步骤)。检查每个模块的关键文件是否存在并已修改。
- 正确做法:完成全部 22 个步骤。依次处理 LumeRender(8 步)→ Lume3D(5 步)→ LumeScene(9 步)。
例外和回退
效果需要多次渲染遍历
症状:效果需要模糊遍历、缩小/放大、时间累积。
- 回退方案:此技能不适用。请使用专用的多遍后处理系统,并采用独立的渲染节点图。
- 依据:检查着色器是否需要
uImgSampler+uBloomSampler+ 中间帧缓冲区(如泛光效果)。如果需要 → 多遍处理。
着色器编译错误
症状:“undefined macro POST_PROCESS_INDEX_XXX”或“array index out of bounds”。
- 诊断:索引不匹配或缺少常量定义。
- 修复:检查着色器常量是否与 C++ 枚举值匹配。确认索引 < 14(POST_PROCESS_GLOBAL_VEC4_FACTOR_COUNT)。
视觉伪影或效果未应用
症状:颜色错误、参数被忽略、效果不可见。
- 诊断:因子索引错误,或 DataStore 中未调用 GetFactorXXX()。
- 修复:确认在
render_data_store_post_process.cpp(步骤 5)和render_node_util.cpp(步骤 6)中都调用了转换函数。
参考资料
主要参考文件
references/code_templates.md(785 行):包含全部 22 个步骤的完整代码模板,其中包括通用模板和色调映射示例。实现期间必须加载。references/advanced_reference.md(306 行):高级参考资料,包含数据流图、实现检查清单和故障排查指南。仅在排查问题或需要了解数据流时加载。
加载策略
阶段 1 - 初始实现:
- ✅ 必须:分三个阶段加载
code_templates.md(LumeRender → Lume3D → LumeScene 部分) - ❌ 不要加载:
advanced_reference.md(留待之后使用)
阶段 2 - 故障排查:
- ✅ 按需加载:遇到错误、需要数据流图或实现检查清单时,加载
advanced_reference.md - ❌ 不要重新加载:如果已加载
code_templates.md,则无需重新加载
要点
-
架构:配置与转换分离
- 配置结构体用于用户界面
- 转换函数将数据打包为适合着色器使用的 Vec4
-
关键:着色器与 C++ 的索引/位保持一致
POST_PROCESS_INDEX_*↔PostProcessConfiguration::INDEX_*POST_PROCESS_SPECIALIZATION_*_BIT↔FlagBits枚举- 不匹配会导致 GPU 验证错误或视觉伪影
-
必须:支持双路径
- 在 DataStore(步骤 5)和 RenderNodeUtil(步骤 6)中都添加转换
- 单路径实现会在某些场景中失效
-
命名和宏约定
- 着色器函数:采用
PostProcess<Effect>Block命名 - META_TYPE:仅当接口包含枚举类型时才添加
- META_READONLY_PROPERTY:必须添加到 IPostProcess 接口
- 着色器函数:采用