Untoon Engine
Renderer-Architecture
本页目录
渲染器架构说明
文档目标
这一页给引擎维护者和图形程序员看:untoon 在渲染器层改了哪些地方,读代码时从哪里进。
分支基于 Unreal Engine 5.8。相对上游 release,Untoon 的改动横跨材质、SceneTexture、Deferred Renderer、Nanite compute shading 和 pass 调度,几个部分之间有数据依赖。
相机优先显示集成
新增功能复用 MSM_Untoon,不改变 GBuffer/GBufferToon 或 GPUScene primitive 数据步长。材质资产不需要迁移。
- 引擎接口:
Engine/Source/Runtime/Engine/Classes/Components/UntoonRenderGroupComponent.h;Engine/Source/Runtime/Engine/Public/Materials/MaterialExpressionToonPriority.h。 - 传统编译与 MIR:
Engine/Source/Runtime/Engine/Private/Materials/MaterialExpressionsUntoonVisibility.cpp。CachedExpressionData 保存默认关闭的角色标志,ShaderParameters 复用 PackedFlags16 的空余位,供 shader permutation 与 mesh processor 一致筛选。 - 优先显示:
Engine/Source/Runtime/Renderer/Private/Untoon/UntoonPriorityRendering.cpp;Engine/Shaders/Private/Untoon/UntoonPriorityCommon.ush、UntoonPriorityShader.usf、UntoonPriorityDepth.usf。
渲染组标识位于组件/Proxy 的普通 CPU 字段,上传时按 persistent primitive index 映射到紧凑组索引。图集记录同时包含 GPU view ID、组 ID、源屏幕矩形、图集偏移和有效位;每帧重建,无效记录只返回零覆盖,不借用其他组数据,不占用 CustomDepth/CustomStencil。
Scene.UntoonVisibility 是独立 Scene Uniform Buffer 扩展。Mode 1 的基线 Pass 仅绑定默认空图集,避免对未来目标图集形成 RDG 环依赖;Mode 2 在图集填充后绑定最终参数。原生深度与 Velocity 的 opaque 让位材质必须使用真实材质像素着色器,不能被 position-only/null PS 优化跳过。
优先 Pass 会把整张场景深度保守地重做一遍;组测试的 viewport 保持原视图投影,scissor 限制在角色的屏幕范围内。每组临时深度和目标纹理保持场景尺寸以复用材质坐标,组覆盖再拷入紧凑 R32F 图集;临时资源可由 RDG 复用。最坏情况仍有全场景深度重绘和逐组头发重绘成本,不能把图集尺寸视为全部内存或 GPU 成本。
恢复头发发生在 Nanite 深度导出之后、最终 HZB 和后续着色之前。头发替换可见表面时清空该像素 Nanite shading mask,更新 decal stencil,并清除旧速度;DDM_AllOpaqueNoVelocity 的普通网格 Velocity 延后到最终深度之后。所有新增 mesh shader 有对应 PSO collector,绘制与预缓存共享状态和筛选规则。
LOD 过渡由 UntoonCameraMeshShader 传递每次绘制的判定参数,复现原生 stencil raster/compute 的坐标和阈值规则。完整基线在预深度清除 LOD stencil 前生成;逐组补绘和 Toon 光照不依赖该 stencil 后续仍然存在。Masked 裁剪统一使用原生 coverage 计算,避免额外的硬裁剪破坏抖动遮罩。
支持范围、资源检查和运行验收见优先显示验收。未经编译、编辑器或 GPU 验证的部分仍须在可用构建上确认。
架构层级
untoon 的改动可以按七层来看:
- 引擎 API 层
- 材质编译与 Shader 生成层
- GBuffer / Scene Texture 层
- Renderer Pass 层
- Nanite post-light export 层
- Light Parameter / Scene Parameter 层
- Lumen / Ray Tracing / Debug 兼容层
1. 引擎 API 层
涉及的文件:
Engine/Source/Runtime/Engine/Classes/Engine/EngineTypes.hEngine/Source/Runtime/Engine/Classes/Components/LightComponent.hEngine/Source/Runtime/Engine/Classes/Components/LocalLightComponent.hEngine/Source/Runtime/Engine/Classes/Engine/Scene.h
这里定义的内容:
MSM_Untoon- Untoon 灯光参数
- Untoon 场景参数
- Untoon 材质节点对外接口
2. 材质编译与 Shader 生成层
编译与生成相关的文件:
Engine/Source/Runtime/Engine/Private/Materials/*Engine/Source/Runtime/Engine/Private/ShaderCompiler/ShaderGenerationUtil.cppEngine/Source/Runtime/Engine/Public/MaterialCompiler.h
这一层做的事:
- Untoon 材质节点编译
Toon Light、ToonShadowMaskcustom output 生成ToonPassSwitch的 pass-dependent 分支生成- GBuffer Slot 分配
- Shading Model 宏与分支生成
维护时要特别注意 MIR 与传统 HLSL translator 的一致性。Nanite compute material shader 也会依赖材质 custom output 和 pass switch 语义。
3. GBuffer / Scene Texture 层
相关文件:
Engine/Source/Runtime/Renderer/Private/SceneTextures.cppEngine/Source/Runtime/Renderer/Internal/SceneTextures.hEngine/Source/Runtime/RenderCore/Public/GBufferInfo.hEngine/Shaders/Private/SceneTexturesCommon.ush
这里管四件事:
- 增加
GBufferUntoon - 创建
UntoonShadow - 提供
UntoonShadowTexture读取 helper - 为 Untoon pass 和 Nanite compute export 提供 SceneTexture 输入
当前 UntoonShadow 通道语义:
R:RenderLights使用红色写掩码写入的表面阴影G:RenderToonShadowMask写入的材质 Shadow Mask,1表示阴影B:Shadow blur 使用蓝色写掩码写入的光照遮罩,1表示光照区域A:Untoon 覆盖标记,1表示当前像素属于 Untoon shadow mask export 覆盖范围
Nanite ToonLight export 会通过 compute UAV 写回 SceneColor,因此 SceneColor 需要具备 TexCreate_UAV 创建能力。
4. Renderer Pass 层
Pass 调度与实现文件:
Engine/Source/Runtime/Renderer/Private/Untoon/ToonBasePassRendering.*Engine/Source/Runtime/Renderer/Private/Untoon/ToonLightPassRendering.*Engine/Source/Runtime/Renderer/Private/Untoon/ToonShadowMaskRendering.*Engine/Source/Runtime/Renderer/Private/Untoon/ToonShadowBlur.*Engine/Source/Runtime/Renderer/Private/Untoon/ToonOutlinePassRendering.*Engine/Source/Runtime/Renderer/Private/DeferredShadingRenderer.*
这一层的职责:
- Pass 的注册、调度与执行
- 普通 mesh 的 Untoon ShadowMask 和 ToonLight mesh pass
FToonLightPassLightParameters的构建- Untoon 光照和阴影的独立计算
- 最终描边合成
当前有效标准顺序是:
- 常规 Base Pass 写入
SceneColor、常规 GBuffer 和GBufferToon RenderLights写入UntoonShadow.RRenderToonShadowMask写入UntoonShadow.G和覆盖标记UntoonShadow.AAddToonMainLightShadowBlurPass基于G的反向光照区域生成晕染,并写入UntoonShadow.BRenderToonLightPass合成 ToonLight 到SceneColor- Outline / 后处理继续消费 Untoon 数据
RenderToonBasePass 仍在 DeferredShadingRenderer.cpp 中保留调用点,但 ToonBasePassRendering.cpp 当前用 if (false) 禁用了实际执行体。因此它是保留入口,不是当前有效数据流的一环。
实现细节上,Shadow Blur 是在 RenderToonLightPass 准备 FToonLightPassLightParameters 时触发;架构上仍应把它理解为 UntoonShadow.G/A 和 ToonLight 合成之间的中间数据生成步骤。
flowchart LR
A["Base Pass<br/>GBufferToon"] --> B["RenderLights<br/>UntoonShadow.R"]
B --> C["RenderToonShadowMask<br/>UntoonShadow.G/A"]
C --> D["Shadow Blur<br/>UntoonShadow.B"]
D --> E["RenderToonLightPass<br/>SceneColor"]
E --> F["RenderToonOutlinePass"]
5. Nanite post-light export 层
Nanite 与 Base Pass 相关文件:
Engine/Source/Runtime/Renderer/Private/Nanite/NaniteShading.cppEngine/Source/Runtime/Renderer/Private/Nanite/NaniteShading.hEngine/Source/Runtime/Renderer/Private/BasePassRendering.*Engine/Shaders/Private/BasePassPixelShader.usfEngine/Shaders/Private/Common.ush
Nanite 不进入普通 EMeshPass::UntoonShadowMaskPass 和 EMeshPass::UntoonLightPass,因此 Untoon 为 Nanite 增加了两条 post-light compute export:
DispatchUntoonToonShadowMaskPassDispatchUntoonToonLightPass
Nanite ToonShadowMask export:
- 从 Nanite base pass shading commands 中筛选
MSM_Untoon材质 - 复用 Nanite 可见性、shading mask、shading bins 和材质 bindings
- 创建可读取的
UntoonShadowsnapshot - 重新评估
ToonShadowMaskOutput - 写入
UntoonShadow.G,并将UntoonShadow.A置为覆盖标记
Nanite ToonLight export:
- 复用 Nanite 可见像素
- 读取与普通 mesh 相同语义的
PreLightSceneColorCopy/PostLightSceneColorCopy - 使用完整
LightPassLight上下文 - 重新评估
ToonLightOutput - 通过 compute UAV 合成回
SceneColor
维护要求:
- Nanite 与普通 mesh 的材质编译环境必须表达相同 pass 语义
- Nanite ShadowMask export 必须能读取
UntoonShadow.R - Nanite ToonLight export 必须能读取
PreLightSceneColorCopy/PostLightSceneColorCopy - post-light export 只能处理最终可见 Nanite 像素
6. Shader 层
Shader 文件:
Engine/Shaders/Private/Untoon/*Engine/Shaders/Private/ShadingModels.ushEngine/Shaders/Private/DeferredLightPixelShaders.usfEngine/Shaders/Private/BasePassPixelShader.usfEngine/Shaders/Private/Common.ush
这里放的是:
- Untoon 光照函数
GBufferToon材质载荷编码与读取- Untoon Shadow Mask 输出
- pass switch 与 post-light export helper
- Nanite compute export 的 root flag 判断
- Outline 计算与合成
重要环境定义:
TOONMAINLIGHTTOONLIGHTPASSUNTOON_POST_LIGHT_TOON_SHADOW_MASK_EXPORTUNTOON_ALLOW_UNTOONSHADOW_TEXTURE_READUNTOON_NANITE_TOON_SHADOW_MASK_EXPORTUNTOON_NANITE_TOON_LIGHT_EXPORT
这些 define 是材质图判断当前阶段的标准接口,不应随意改变语义。
7. 兼容路径
当前分支还触达以下兼容区域:
- Nanite
- Lumen
- Ray Tracing
- Deferred Lighting
- Virtual Shadow Maps
- Pixel Inspector / Debug View
兼容原则:
- Untoon 不替换 UE 默认 Deferred Lighting 或 Lumen。
- Untoon 结果主要通过后续 pass 写入
UntoonShadow和最终SceneColor。 - Nanite 几何仍走 Nanite 主路径,Untoon 只补齐 Nanite 缺失的 post-light 材质导出机会。
- Lumen GI 本身仍按 UE 主路径工作,Untoon 最终合成通常不反向写回 Lumen 解算输入。
调试入口
常用调试开关:
r.Untoon.ShadingQualityr.Untoon.ShadowBlur.ShadingQualityr.Untoon.Outline.ShadingQualityr.Untoon.DebugLogNaniteToonShadowMaskExportr.Untoon.DebugForceNaniteToonShadowMaskGr.Untoon.DebugForceNaniteToonLightSceneColorr.Untoon.DebugClearToonShadowMaskG
调试时:
- 如果 Untoon Shadow Blur 或 Outline 成本过高,先用
r.Untoon.ShadingQuality做全局降档,再用 pass 级 CVar 单独覆盖。 - 如果
UntoonShadow.G为空,先看 ToonShadowMask export 是否 build / dispatch。 - 如果
G正确但画面不变,检查 ToonLight export 是否写回SceneColor。 - 如果 force 输出有效但材质结果错误,检查材质编译环境和
LightPassLight绑定。 - 如果需要新增或整理 RDG、CPU trace、Stats、CSV、LLM 标记,先参考 追踪宏速查 统一命名和宏选择。
推荐阅读顺序
要理解整体架构,按这个顺序读代码:
LightComponent.hMaterialExpressionToon*ShaderGenerationUtil.cppSceneTextures.cpp与SceneTexturesCommon.ushRenderer/Private/Untoon/*Renderer/Private/Nanite/NaniteShading.*Shaders/Private/BasePassPixelShader.usfShaders/Private/Untoon/*
源码标记规则
渲染器维护时需要区分 Untoon 自有目录和上游引擎文件:
Engine/Shaders/Private/Untoon不需要Untoon Engine Start/Endmarker。Engine/Source/Runtime/Renderer/Private/Untoon不需要Untoon Engine Start/Endmarker。- 其他 engine、renderer、shader、runtime 文件中的 Untoon 改动必须位于 marker 内。
- marker 只保留一层;如果当前代码已经在 marker 内,不要再添加嵌套 marker。
完整说明见 维护者规则。
后续扩展建议
继续加 Untoon 功能时,这几条约束值得保留:
- 新的材质语义先定义清楚数据归属,再进入 GBuffer 或 SceneTexture
- 新的渲染阶段优先复用现有 pass 调度框架
- Nanite 路径不能只复用普通 mesh shader,需要明确 compute material export 语义
- 新参数需要同时考虑编辑器暴露、Shader 结构体、MIR / HLSL translator 和序列化兼容性
- 所有新增能力都要标注相对
release的冲突点