Shader Graph:能做什么、做不到什么、何时手写
Shader Graph 不是「不会写 shader 的人的玩具」——它生成的就是 HLSL 代码,而且自动处理了手写最容易错的协议层(Pass 标签、CBUFFER、keyword)。这篇讲清它的机制、边界,以及什么时候手写仍然更对。
机制:节点图 → 生成的 HLSL
每个 Shader Graph 资产编译时生成一份真实 shader 文件(可在 Library 里或右键查看生成代码):节点图决定片元/顶点里的数学,Master Node 决定材质模型(Lit/Unlit/Fabric)。你连线写的只是「光照公式里的那几行」——本区域前四章学的正是这几行;剩下的管线集成它代劳:
UniversalForward/ShadowCaster/DepthOnly等 Pass 自动生成(见 /notes/unity/engineering-1/)。UnityPerMaterialCBUFFER 自动打包,SRP Batcher 天然兼容(见 /notes/unity/structure-4/)。- 光照库调用(
LightingPhysicallyBased)、lightmap/probe 采样、雾、keyword 变体全部接好(见 /notes/unity/lighting-4/)。
擅长什么
| 场景 | 为什么合适 |
|---|---|
| 标准 PBR 材质 + 贴图混合 | 参数化工作流,美术可迭代 |
| 顶点动画(风摆、水波) | Vertex Position 偏移 + Custom Node 写波形(见 /notes/unity/effects-5/) |
| 溶解/扭曲/菲涅尔类效果 | 本区域效果章的公式,连出来就几节点 |
| 需要 URP/HDRP 全功能集成 | 手写要补的 Pass/keyword,它默认全有 |
| 局部复杂数学 | Custom HLSL Node:一小段真代码嵌进图里 |
做不到 / 做得别扭什么
- 自定义多 Pass 效果:URP Shader Graph 的 Extra Pass 只支持固定类型(Depth/ShadowCaster/DepthNormals 等)。倒模描边这种「自定义第二遍绘制」做不了或很别扭——手写 Pass 更直接(见 /notes/unity/effects-3/)。
- 自定义渲染 Pass / 全屏效果:那是 Render Graph / Renderer Feature 的 C# 侧工作,Shader Graph 只负责材质。
- 复杂分支与状态逻辑:节点图表达
if/else树迅速膨胀成意大利面;可读性断崖。 - 指令级控制:生成的代码有固定样板,抠移动端最后 20% 性能时不如手写可控(见 /notes/unity/performance-1/)。
- 版本迁移:图资产跨 URP 大版本升级偶发断链,且 diff 不可读(二进制资产),代码管理不如
.shader文本友好。
何时手写
- 需要自定义 Pass(描边、回照光、平面反射的额外遍)。
- 已有 shader 代码库/跨项目复用(文本文件好 diff、好测试)。
- 明确要抠指令数、寄存器、采样数的移动端项目。
- 做引擎级系统(后处理、屏幕空间效果管线)。
其余情况——尤其美术参与迭代的材质——用 Shader Graph 是工程上更优的选择,别为「都会写」的自尊手写 40 个 PBR 变体。
读生成代码:最快的学习法
生成代码是免费的「URP shader 教科书」:连一个 Lit 图,看它生成的 ShadowCaster Pass 长什么样、CBUFFER 怎么排、LightingPhysicallyBased 在哪调用——比任何教程都贴近真实工程。反过来,手写 shader 卡协议时,也可以连个等价图看它怎么解决。
Custom Node 的正确用法
Custom Node 里写的是真 HLSL 函数(输入输出端口即函数参数)——把 /notes/unity/lighting-3/ 的自定义 BRDF、/notes/unity/effects-4/ 的扭曲函数塞进去,图的其余部分保持可读。图 + Custom Node 的混合形态,是「美术可维护」与「代码可控」的最佳折中。
自检三问
- Shader Graph 生成的代码里,哪些部分是你没写但替你补上的?
- 倒模描边为什么在 Shader Graph 里做不了?
- 什么时候「读生成代码」比读教程有效?