Untoon Engine
Material-Authoring-Guide
本页目录
材质编写指南
目标
这一页讲怎么在 untoon 分支里创建和组织 Untoon 材质。
基础原则
Untoon 材质基于原生 Toon Shading Model,不是在默认 Lit 材质上挂几个技巧节点。项目里最好统一这几样东西:
- 一个 Untoon Master Material
- 一组 Untoon Material Function
- 一套参数命名规范
必备入口
Shading Model
材质先设为 Shading Model = Toon。
Toon Light
Toon Light 在 RenderToonLightPass 阶段提供风格化光照结果。常见用法是自定义明暗分界颜色、控制与原始 post-light 结果的混合比例,以及按材质特性调制或改写区域光照结果。
节点有两个输入:
ToonLighting:float4rgb:材质希望在 Toon Light Pass 中提供的风格化颜色a:与原始 post-light 场景色之间的混合权重
AreaLightLightingModulate:float3- 调制
PostLightSceneColor - PreLightSceneColor得到的区域光照结果 - 未连接时默认视为白色乘子
1,1,1
- 调制
其中:
PreLightSceneColor:RenderLights之前保存的SceneColor快照,主要表示间接光、底色、emissive 等灯光前底色PostLightSceneColor:RenderLights/RenderMegaLights之后、RenderToonLightPass开始时保存的SceneColor快照AreaLightLighting:max(PostLightSceneColor - PreLightSceneColor, 0),用于表达当前后置阶段看到的区域光照差分结果SimpleMainDirectionalDiffuse:基于BaseColor / PI、主方向光颜色、NdotL与1 - UntoonShadow.R的简化漫反射补偿
当前 Toon Light Pass 的合成语义为:
AreaLightLighting = max(PostLightSceneColor - PreLightSceneColor, 0.0f);
AreaLightLighting *= AreaLightLightingModulate;
SimpleMainDirectionalDiffuse = (BaseColor / PI) * MainLightColor * saturate(dot(N, L)) * (1.0 - UntoonShadow.R);
FinalColor = lerp(PostLightSceneColor + SimpleMainDirectionalDiffuse, ToonLighting.rgb + AreaLightLighting, saturate(ToonLighting.a));
这意味着:
ToonLighting.a = 0:输出PostLightSceneColor + SimpleMainDirectionalDiffuseToonLighting.a = 1:输出ToonLighting.rgb + AreaLightLightingAreaLightLightingModulate只调制差分得到的区域光照结果,不改变PreLightSceneColor本身
Toon Priority 与 Untoon Render Group
为角色 Actor 添加 Untoon Render Group 组件。默认自动登记该 Actor 的 Mesh Component;跨组件成员可用 Members 或 Blueprint AddMember 显式登记。每个注册实例获得独立组标识,共享眼睛/头发材质不会让不同角色串组。
在眼睛、眼线或眉毛材质加入 Toon Priority,将 Role 设为 Target;在允许让位的头发材质中设为 YieldingOccluder。两个角色值都沿用 Shading Model = Toon、Opaque 或 Masked。一个网格通过材质槽区分眼睛和头发;一个材质只选择一种角色。
Mask 是单通道像素遮罩,默认 1;Mask >= 0.5 才参与,不做半透明边缘混合。未添加节点、Disabled、未登记渲染组或关闭 r.Untoon.Priority 时使用普通遮挡。
目标只穿过同组允许让位的像素。脸、墙和其他角色的头发照常遮挡;墙夹在头发与眼睛之间时,眼睛不可见,前方头发保留。运行时隐藏、距离和 LOD 规则仍有效。图集容量不足或组内需要的着色器未就绪时,该组使用普通遮挡。
运行时创建、删除或更换成员后调用 RefreshMembers。自动包含所属 Actor 网格时,RemoveMember 只删除显式登记;需要完全手动控制时先关闭 bIncludeOwnerMeshes。一个 Mesh Component 只能归属一个组,重复登记会保留先前归属并输出日志。
优先显示节点的输入应来自在相机各阶段一致的材质数据,例如 UV、纹理、顶点色、参数和表面法线。不要让 Priority Mask、WPO、Opacity Mask 或 PDO 依赖 ToonPassSwitch 的不同阶段结果、Toon 灯光结果或后置 SceneColor:深度阶段不能读取尚未产生的光照资源。
首版限定桌面 Deferred 普通静态/骨骼 Opaque、Masked Toon 网格。Nanite、Groom Strands、Forward、Mobile、Path Tracing、Scene Capture、Instanced Stereo 不参与。功能开关与排查方法见灯光与后处理指南,验收状态见优先显示验收。
ToonShadowMask
ToonShadowMask 在 post-light ShadowMask export 阶段输出风格化阴影遮罩,用来控制阴影区域的形状,也是后面晕染和模糊的输入。
执行顺序是:
RenderLights先把表面阴影写入UntoonShadow.RToonShadowMaskOutput再读取这个结果并输出最终 Shadow Mask- 输出写入
UntoonShadow.G - 后续 blur 会消费
G并写入B
所以 ToonShadowMask 回答的是「怎么根据已有受光结果生成风格化阴影」,主光阴影本身不在这里重新定义。
ToonPassSwitch
ToonPassSwitch 用于让同一材质在不同 Untoon Pass 中输出不同结果。
推荐只在确实需要分离逻辑时使用,避免材质图过度复杂。
当前可稳定区分的语义上下文包括:
- 默认路径
- 保留的 Untoon Base Pass 语义入口
- Untoon Light / post-light 阶段
普通 mesh 与 Nanite 的 post-light export 已对齐到同一套材质环境语义,因此 ToonPassSwitch 不应再因为是否启用 Nanite 而看到不同分支结果。
推荐材质组织方式
主材质只定义 Shading Model 和主输出,Toon Light 结果与 Shadow Mask 生成各交给一个 Material Function。分开封装之后,排查普通 mesh 与 Nanite 的差异时可以直接换掉单个函数做最小验证,不用动整张材质图。
调参建议
风格化光照
- 风格化光照颜色与后置阶段区域光照调制交给
Toon Light。 - 基于
UntoonShadow.R的阴影形状交给ToonShadowMask。 ToonPassSwitch只在材质确实需要区分不同 Untoon Pass 时使用。
常见错误
- 用默认 Lit 材质模拟 Untoon,而不使用
ToonShading Model - 在材质图中直接硬编码大量 Untoon 参数
- 过度依赖
ToonPassSwitch,导致材质难以维护 - 在
ToonShadowMask中假设某些 LightPass 变量只会出现在普通 mesh 路径 - 把
ToonShadowMask当作「主光阴影源」,而不是 post-light 风格化导出阶段