Shader Graph:能做什么、做不到什么、何时手写

Unity 知识 · Shader 区域 · 管线与工程 · 第 2 篇 更新于 2026-10-15

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/)。
  • UnityPerMaterial CBUFFER 自动打包,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 文本友好。

何时手写

  1. 需要自定义 Pass(描边、回照光、平面反射的额外遍)。
  2. 已有 shader 代码库/跨项目复用(文本文件好 diff、好测试)。
  3. 明确要抠指令数、寄存器、采样数的移动端项目。
  4. 做引擎级系统(后处理、屏幕空间效果管线)。

其余情况——尤其美术参与迭代的材质——用 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 里做不了?
  • 什么时候「读生成代码」比读教程有效?