7.2 Custom Function:在图里写 HLSL


7.2 Custom Function:在图里写 HLSL

本节摘要:Custom Function 节点允许在图里嵌入一段手写 HLSL 函数,专治节点拼不出的数学:矩阵运算、循环迭代、引擎未暴露的接口。本节讲两种代码供给模式的取舍,给出一个可直接抄用的最小实现,并回答"图和手写着色器到底是什么关系"。

节点图的边界在哪里

节点搜索框里躺着几百个节点,但图形学的数学远不止这些。举三个真实场景:把一组 UV 坐标绕中心旋转任意角度(矩阵乘法,节点能拼但二十个起步);对噪声做三次八度叠加(同样的结构复制三遍,改起来三处同步);调用引擎内置的雾颜色接口(没有现成节点暴露)。这些场景的共同点是:逻辑清楚但节点表达笨重——恰恰是代码最擅长的事。

Custom Function 节点就是这个口子:你在节点里声明输入口与输出口,函数体用 HLSL 写,编译时函数体被原样并进生成的着色器。图的优点(连线直观、参数暴露方便)和代码的优点(表达力、紧凑)在同一张图里各得其所。

两种代码供给模式

节点检查器里的 Source 下拉有两个选项,取舍明确。

String 模式:函数体直接写在节点的文本框里。优点是所见即所得、便于分享(发一个节点截图别人就能复现);缺点是没语法高亮、改动历史没有版本管理。适合短函数(十行以内)与教学演示。

File 模式:函数体放在一个 HLSL 文本资产里,节点引用它。优点是可以用任何编辑器写(带高亮)、可以被多张图共享、能进版本管理;缺点是多一个资产要管理。适合正式项目与稍长的函数。项目实践的建议:先 String 后 File——原型期用 String 快速验证,定型了迁到 File 收进项目的着色器库目录。

图:Custom Function 两种供给模式与适用边界

图:Custom Function 两种供给模式与适用边界

最小实现:UV 旋转函数

把"UV 绕中心旋转"做成 Custom Function,这段代码可以直接抄用。节点上先定义接口:输入口 UV(Vector2)、Center(Vector2)、Angle(Vector1,弧度);输出口 RotatedUV(Vector2)。选 String 模式,函数体如下:

// 输入输出结构名固定为 NodesInterface,字段名与节点端口一致 void RotateUV_float(float2 UV, float2 Center, float Angle, out float2 RotatedUV) { // 平移到以中心为原点 float2 local = UV - Center; // 二维旋转矩阵乘法:同一个旋转角对两个分量各乘一次 float s = sin(Angle); float c = cos(Angle); float2 rotated; rotated.x = local.x * c - local.y * s; rotated.y = local.x * s + local.y * c; // 平移回原坐标系 RotatedUV = rotated + Center; }

三个写法要点。要点一:函数名后缀 _float 表示单精度版本,这是 Shader Graph 的约定,漏写后缀会报"找不到函数"。要点二:参数顺序必须与端口声明顺序一致,输出口用 out 关键字——这就是端口接线背后的函数签名。要点三:结构体名与约定写法随版本可能微调,报错时优先检查签名格式而非算法本身。

接进图里验证:UV 节点接 UV 口,Vector2 (0.5, 0.5) 接 Center,2.2 节的滑条属性接 Angle,输出接 4.3 节滚动链的 UV 输入。保存后拖角度滑条,贴图绕中心旋转——节点要拼二十步的事,八行代码完事。

图与代码的真实关系

借这个节点把认知收拢:Shader Graph 生成 HLSL(1.4 节),Custom Function 把你手写的 HLSL 并进去,Sub Graph 把常用结构抽成组件——三者是同一套语言之上的不同抽象层级。所以"学 Shader Graph 要不要学 HLSL"的答案是分阶段的:入门期不需要(本册前六章的证明);进阶期要能"读懂"(看报错、改 Custom Function);专业期的技术美术需要"能写"——那时的收获是你可以把任何图形学论文里的公式直接落进节点图。两套能力不是替代关系,是互补关系:图管组织,代码管表达。

⚠️ Custom Function 的调试与普通代码一样:编译错误在检查器窗口看报错行,运行错误靠把中间输出临时接到 Base Color 看颜色(调试输出的土办法,第 8 章还会正式介绍)。另外注意平台差异:某些 HLSL 指令在移动端 GPU 上行为不同,函数里避免依赖未定义行为。

从 String 迁移到 File 的操作

定型后的迁移三步:新建 Text Asset(项目窗口右键创建文本资产,扩展名用 hlsl),把 String 里的函数体原样粘贴进去;Custom Function 节点的 Source 切到 File 并指定该资产;保存验证预览不变。迁移后有一个易漏点:File 模式下改了文本资产内容,引用它的图不会自动重编译,需要在图里触发一次保存——"改了代码没反应"时先想到这一条。

问题:函数在编辑器里正常,真机上结果不对?

平台差异类问题,按频率查三个点。第一查精度:手机 GPU 默认用半精度浮点,函数里的大数值运算(坐标乘大系数再相减)可能丢精度,关键计算可显式声明高精度。第二查指令支持:个别 HLSL 函数在移动端有等效实现差异(如部分三角与平滑函数),输出在边界值处偏差。第三查未初始化输出:out 参数所有分支都必须赋值,桌面端可能侥幸通过,移动端必出错。三个点都排除后再怀疑逻辑本身——九成真机差异出在精度。

Custom Function 的团队规范

代码进图后,审图成本转移给了读者,规范变得重要。三条最低要求:函数头注释写清输入输出的语义与单位(角度是弧度还是度);命名与图里的属性名对齐(图里叫 Angle 代码里就别叫 rot);函数保持单一职责(一个函数做一件事,组合交给连线)。这三条的成本是每段代码多两行注释,收益是半年后任何同事打开这张图都能维护——图的可读性纪律从节点延伸到代码,标准不变。

本节要点回顾

  • 节点图有边界:矩阵、迭代、引擎接口,笨重或够不着的地方交给代码。
  • 两种供给模式:String 内联求快,File 资产求管,先 String 后 File。
  • 签名即接口:函数名后缀、参数顺序、out 输出,与端口声明严格对应。
  • 图与代码互补:图管组织与暴露,代码管表达与紧凑,分阶段补齐。

组件有了、代码口子开了,下一节处理工程化的最后一根暗礁:关键字与变体——一个 Boolean 背后的编译产物膨胀,及它的控制方法。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U