【UE5】在材质Custom写函数的方法:结构体封装法 泡芙注入法
UE材质的Custom本身会构建为函数,所以并不能在Custom定义函数,但当然还是有办法的
总结一些在custom写函数的方法
常规办法
常规办法就是使用结构体作为函数使用
以一个Lerp功能函数演示
让我们看看写法:
structVolBlendFunc//定义结构体{//在结构体中新建“结构体变量”,这里的变量名和 Custom 输入的变量无关floatA;floatB;//新建一个“函数”,这里的写法和函数基本一样floatBlend(floatPos){returnlerp(A,B,Pos);}};VolBlendFunc VolSample;//为结构体"起名“//使用:VolSample.A=A;//将“参数A”设置到“结构体变量A”VolSample.B=B;returnVolSample.Blend(x);//和使用函数的方式基本一样,这里的x是custom输入的x,设置到了Pos根据用法还有很多写法,这是另一种写法
structBaseNumFunc//定义一个结构体。{floata;float2 b;float3 c;float4 d;BaseNumFuncNum()//定义一个函数块。{BaseNumFunc l;//将结构体命名为l方便后续调用结构体中的变量;l.a=1;l.b=float2(0.5,0.1);l.c=float3(1,1,0);l.d=float4(1,0,1,1);returnl;}}BaseNum;//返回结构体的名字。a=BaseNum.Num().a;b=BaseNum.Num().b;d=BaseNum.Num().d;returnBaseNum.Num().c;//调用结构体中的函数里设置的数据。学会了吗?很难用,别学。
直接看下面的泡芙注入↓
泡芙注入
原理
这是一种利用Custom特性,用作弊手法将任何东西写入HLSL的实现。
先看看原理,例如你写了一个:
floatC=lerp(A,B,X);returnC;它会被编译为一个函数CustomExpression+Index
正常来说,后续你可以通过
CustomExpression0来调用这个函数,但在编译时是无法控制编译器会将哪个Custom编译到什么index,导致风险相当大
但如果我们这么写呢?
return0;}floatBlend(floatPos){returnlerp(A,B,Pos);会发现他是原样写在了这里
但你会注意到,Custom自动生成的CustomExpression0看上去被我们直接结束了,而下面的内容刚好构成了新的函数
这种作弊方法正是利用了这个特性,把任何东西写入HLSL,包括函数写入
只需要先写上return 0;},后面随便写任何HLSL的东西
最后,记得编译器在生成CustomExpression时会补一个"}“,因此最后一个”}"不写
return0;}//先手一个大比斗将其扇懵floatFA(floatPos)//写了一个函数{returnlerp(A,B,Pos);}floatFB(floatPos)//又写一个函数{returnlerp(A,B,Pos);//最后一个“}”不写,等编译器自动补使用
连法1:“+0法”
那么实际使用时就是这样
“加法”是为了在编译时会带着这个custom,这个custom输出0(大比兜的值)
一个+0的操作没有性能损耗,如果不连接这个Custom,会作为无用节点被优化掉的
return0;}//先手一个大比斗将其扇懵,然后对HLSL进行疯狂的注入/**接下来你可以在HLSL里写任何东西,不限于函数 //例如你可以写: #if !MATERIAL_LWC_ENABLED #define UE_DF_FORCE_FP32_OPS 1 #endif //也可以加include #include "/Engine/Private/xxxx.ush" **///用注释画画都行,把hlsl疯狂注入成泡芙floatMyFLerp(floatX,floatY,floatPos)//写多少函数都行{returnlerp(X,Y,Pos);//总之切记,最后一个“}”不写,编译器需要补一个连法2:“引脚法”
还有一种方式,在使用函数的CustomB,开放一个没用的函数输入(引脚名无所谓),将泡芙CustomA连上,也是可以防止CustomA被优化掉:
相比+0的方法,优点是减少了一次+0。缺点是让Custom节点之间,有了某种实际上不存在的因果关系。
取决于你的喜好了。
如果注入的并不是函数
如果你注入的内容不包括函数,需要对结尾进行设计,因为Custom必补一个"}"
我喜欢用"
void(){"收尾
例如想在这画个画,Custom效果如下::
编译结果:
其他玩法
切换函数
因为Switch是静态切换(在实际编译前),所以能做到这样的事。
啊,为啥叫泡芙注入啊?
Shader:
这是泡芙↓