Shader Graph:可视化编程在 URP/HDRP 中的应用

张开发
2026/4/14 4:46:25 15 分钟阅读

分享文章

Shader Graph:可视化编程在 URP/HDRP 中的应用
深入解析 Shader Graph 的设计理念、节点系统、与手写 HLSL Shader 的协同方式以及如何在实际项目中选择最优渲染方案。01 · 概述什么是 Shader GraphShader Graph 是 Unity 2019.1 引入的可视化着色器编辑器它让开发者通过拖拽节点、连接端口来构建复杂的渲染效果而无需手写大段 HLSL 代码。传统手写 Shader 需要开发者对 GPU 编程有深入理解——你需要熟悉顶点着色器与片元着色器的编写规范、语义绑定、寄存器分配等底层细节。Shader Graph 将这些复杂性抽象为直观的节点网络让艺术家和程序员的协作门槛大幅降低。Shader Graph 生成的并非解释型代码——它会在构建时编译为标准的 HLSL 源码。这意味着你可以随时导出生成的 .hlsl 文件进行审查和进一步的手写优化。02 · 管线对比URP 与 HDRP如何选择Unity 的 Scriptable Render PipelineSRP允许你用 C# 脚本来定义渲染流程。URP 和 HDRP 是两套官方预制管线它们对 Shader Graph 的支持程度和侧重点有所不同。特性Universal RP (URP)High Definition RP (HDRP)目标平台移动端 · 主机 · PC低至中配高端 PC · 主机 · VR高品质Shader Graph完整支持Fragment 模式完整支持Vertex Fragment 分离光照模型简化的 PBR无延迟支持完整 PBS · SSS · 体积光 · 光线追踪Master Node单个 PBR Master全部输出分立Vertex / Fragment / Forward/DeferredDecal 支持✓✓自定义光照受限需手写完整 Pass✓Layered Lit 支持渲染路径前向渲染Forward Only前向 延迟Forward Deferred推荐场景移动游戏 · 多人在线 · WebGL主机 AAA · 影视级 · 建筑可视化Shader Graph 兼容性说明URP 11 和 HDRP 12 之后两套管线都引入了Shader Graph 7.x版本节点结构趋于统一。但部分高级节点如 HDRP 的Bitangent Material、URP 的Screen Space Occlusion仅限于各自管线。跨管线迁移时请务必检查节点兼容性。URP Shader Graph 的 Master NodeURP 使用单一的 PBR Master Node 作为输出它聚合了所有标准属性03 · 节点系统核心节点类型一览Shader Graph 的强大之处在于丰富的节点库。以下按功能分类介绍最常用的节点以及它们在 URP/HDRP 中的差异。PBR 材质节点数学运算节点纹理采样节点UV/坐标节点光照相关节点自定义节点纹理与采样节点数学节点数学节点是 Shader Graph 的核心计算引擎。它们完全基于向量运算实现不存在性能陷阱——生成的 HLSL 与手写代码无异。数学Multiply / Add / Subtract最基础的算术运算。Shader Graph 中所有数值默认是 Vector4Multiply 逐分量相乘Add 逐分量相加。数学One Minus / Negate1 - x的向量版本常用于反相遮罩如 Roughness 反转为 Smoothness。数学Power / Square Root幂运算和开方。Gamma 校正中pow(color, 2.2)是典型应用。数学Clamp / Smoothstep值域限制和软边缘过渡。Smoothstep 是抗锯齿边缘和渐变遮罩的利器。数学Lerp线性插值lerp(a, b, t)a (b - a) * t。两状态之间的平滑过渡。数学Remap将一个范围的值线性映射到另一个范围。例如将 [0,1] 的噪声映射到 [0.2, 0.8] 以避免极端值。UV 节点UV 坐标是纹理采样的基础。Shader Graph 提供多种 UV 来源时间与动画节点Shader Graph 内置Time节点它暴露了 Unity 的时间数据无需任何额外 C# 脚本即可驱动动画// Shader Graph 的 Time 节点等价于以下 HLSL 全局变量 float Time ; // 自游戏启动后的时间秒 float SinTime ; // sin(Time) 的预计算值 [-1, 1] float CosTime ; // cos(Time) 的预计算值 [-1, 1] float DeltaTime ; // 上一帧的时长秒用于帧率无关动画 float SmoothDelta ; // 平滑处理后的 DeltaTime float TimeSinceLevelLoad; // 自场景加载后的时间 float4 _Time ; // float4(Time, SinTime, CosTime, TanTime) float4 _SinTime ; // 周期时间用于 uvw 动画04 · 工作流设计Shader Graph 的典型工作流将 Shader Graph 集成到项目管线中需要考虑架构设计。以下是经过验证的三种主流工作流模式。1基础材质层Shader Graph 主导使用 Shader Graph 构建 80% 的标准材质PBR 表面、地形材质、特效纹理混合、程序化噪声等。这是最快速的产出层艺术家可以直接操作无需程序员介入。推荐节点Sample Texture 2D Sample Texture 2D LOD Sample Normal Map Triplanar Blend Smoothstep2Sub Graph 模块化封装将高频复用的节点组合封装为 Sub Graph子图。例如带细节法线的 PBR、程序化砖墙、水波 UV 扰动等。Sub Graph 在项目内跨材质共享保证一致性。Sub Graph 的输入端口成为参数接口输出端口可以定义新的数据类型Struct。3Custom Function 嵌入手写 HLSL当 Shader Graph 的节点无法满足需求时例如自定义 BRDF、光线步进、体积渲染在 Custom Function 节点中直接编写 HLSL 代码。这保留了手写 Shader 的全部能力同时将入口点无缝集成到图中。4完整手写 Shader Include 混合对于高度复杂的渲染效果如地形系统、自定义光照通道完全手写一个 .hlsl 文件通过#include指令被 Shader Graph 生成的 Pass 所引用。此时 Shader Graph 成为参数面板手写代码是真正的渲染引擎。05 · 手写协同Shader Graph 与手写 Shader 的协同这是 Shader Graph 最强大的能力之一通过多个入口点你可以在可视化编辑器中调用手写的 HLSL 函数实现图形化控制 底层实现的混合架构。方法一Custom Function 节点Custom Function 节点允许你在 Shader Graph 中直接编写一小段 HLSL 代码。它是临时嵌入代码的首选方式适合一小段手写逻辑 大量节点的使用场景。// 输入端口In (float), Sharpness (float) // 输出端口Out (float) void CustomFunction ( In.float In, In.float Sharpness, Out.float Out ) { // Smoothstep 的边缘增强版本 float t saturate(In); Out lerp(0.0, 1.0, pow(t, Sharpness)); }方法二引用外部 .hlsl 文件当手写代码较长或需要在多个 Shader Graph 中复用时将代码写入单独的.hlsl文件通过 Custom Function 的File模式引用。// ──────────────────────────────────────────── // 文件MyCustomFunction.hlsl // 说明自定义 UV 扰动与菲涅尔叠加函数 // ──────────────────────────────────────────── #ifndef MY_CUSTOM_FUNCTION_INCLUDED #define MY_CUSTOM_FUNCTION_INCLUDED // 菲涅尔方程Fresnel-Schlick 近似 float FresnelSchlick ( float cosTheta, float F0 ) { return F0 (1.0 - F0) * pow(1.0 - saturate(cosTheta), 5.0); } // 带法线扰动的 UV 扰动函数 void UVDistortion ( In.float2 UV, In.float Strength, In.float Speed, Out.float2 OutUV ) { float time _Time.x * Speed; float2 offset float2( sin(UV.y * 6.28 time) * 0.03, cos(UV.x * 6.28 time * 0.7) * 0.03 ); OutUV UV offset * Strength; } #endif // MY_CUSTOM_FUNCTION_INCLUDED方法三Sub Graph子图作为中间层Sub Graph 是一种可嵌套的 Shader Graph 资源。它有自己的输入/输出端口定义类似于一个自定义节点库。你可以在 Sub Graph 中组合多个节点并嵌入 Custom Function然后将这个 Sub Graph 作为黑盒在其他 Shader Graph 中使用。06 · 实战示例从零构建一个程序化水面 Shader以下示例展示如何用 Shader Graph 构建一个支持法线扰动、菲涅尔反射、深度着色的程序化水面并混合手写 HLSL 实现波浪运动方程。示例环境URP 14 · Shader Graph 14 · Unity 2022.3 LTS。本示例同时适用于 HDRP仅需替换 Master Node。Step 1基础 Setup创建新 Shader GraphURP → PBR Graph设置Surface Type Transparent启用Two Sided为水面开启透明度排序。// ── 图表设置 ────────────────────────────── Surface Type : Transparent // 水面需要透明度 Blend Mode : Alpha // Alpha 混合模式 Render Face : Both // 双面渲染水底也要可见 Pipeline : Universal // URP // ── 新增 PropertyShader 属性面板───────── _WaterColor : Color (HDR) #0D47A1 // 水体基础色 _WaveSpeed : Float 1.0 // 波浪速度 _WaveStrength : Float 0.05 // 扰动强度 _FresnelPower : Float 3.0 // 菲涅尔指数 _NormalMap : Texture2D // 法线贴图可选Step 2节点网络结构整体节点网络分为四层水色层、法线扰动层、菲涅尔层、最终输出层。Step 3手写波浪方程Custom Function节点化方法适合简单波纹但真实水面需要 Gerstner Wave 等物理模型。将以下代码嵌入 Custom Function/ ────────────────────────────────────────────────── // Gerstner Wave — 真实感水面模拟 // 输入uv, amplitude, wavelength, speed, direction, time // 输出displacement (float3), normal (float3) // ────────────────────────────────────────────────── struct GerstnerOutput { float3 displacement; float3 normal; }; GerstnerOutput GerstnerWave ( In.float2 uv, In.float amplitude, In.float wavelength, In.float speed, In.float2 direction, In.float time ) { GerstnerOutput output; float k 2.0 * 3.14159265 / wavelength; // 波数角频率 float c sqrt(9.8 / k); // 相速度深水波近似 float2 d normalize(direction); float f k * (dot(d, uv) - c * time * speed); // Gerstner 位移公式 output.displacement float3( d.x * (amplitude * cos(f)), // X 位移 amplitude * sin(f), // Y 高度法线方向 d.y * (amplitude * cos(f)) // Z 位移 ); // 法线计算从波面梯度推导 float3 n float3( -d.x * k * amplitude * sin(f), 1.0 - k * amplitude * cos(f), -d.y * k * amplitude * sin(f) output.normal normalize(n); return output; }Step 4最终组装到 Shader Graph将 GerstnerWave 的输出连接到 PBR Master Node 的对应端口。注意 Vertex 端口需要在 Fragment 之前处理——Shader Graph 会自动处理依赖顺序。效果预览完成后在场景中创建一个 Plane 或 Mesh将材质应用到其上。Gerstner Wave 会驱动几何体的顶点位移菲涅尔项会在掠射角处产生高光反射配合环境立方体贴图实现真实水面效果。通过调整 Shader 属性面板中的参数艺术家可以实时控制波浪强度、速度与菲涅尔指数无需修改代码。07 · 最佳实践Shader Graph 与手写代码的协作原则经过多个项目的验证以下原则可以帮你建立健康的 Shader 工作流URP vs HDRP 能力对照渲染能力 URP HDRP Custom Function 调用手写光照 需覆盖整个 Forward Pass 支持 Layered Lit 覆盖 Pass Decal System 集成 Shader Graph 支持 Decal 贴图 完整 Decal Graph 支持 顶点位移Vertex Displacement URP 14 Vertex Stage HDRP 12 分立 Vertex Master Ray Tracing 节点 不支持 Raytracing Shader Graph 节点 Lit Shader光照着色器 PBR Master Node 分立 Lit/Unlit/Graph Master 导出完整 HLSL 右键 → Copy Generated Code 同上

更多文章