HLSL生成逻辑

在新建一个Custom节点并转义为HLSL后,代码是这样的:

MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters)
{
    return 1;
}

这样我们大体知道UE会默认生成一个函数体,并将我们节点内的代码放到这个函数体内。因此我们可以根据这个流程来做一些特殊处理来编写更多函数。

在名字为Global的节点内编写

    return 1;
}

float Get()
{
    return 3;

这样把节点内的代码生成到上面的函数体内,HLSL就会生成为:

MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters)
{
    return 1;
}

float Get()
{
    return 3;
}

我们就成功的多编写了一个函数。

但是其他节点无法直接使用这个名为Global节点内的Get函数,如果一个节点没有被连接则是无法编译的,所以想使用这个Get函数的其他Custom只要输入来自这个节点即可。如还有其他输入端可以通过直接相乘来解决,如图所示:

https://www.imxqy.com/imagegx/unreal/hlslhack_1.png

并且Global节点返回值为1不会影响乘法结果,仅仅是把函数体生成了过去,Using节点就可以使用Get函数了。

另外需要注意一点是CustomNode的输入端口如果没有名字的话是不会被使用的,所以这里给Using节点的输入起名为A。

表达式与函数体的两种处理方式

这里是UE将custom节点编译为HLSL时部分的代码

FStringView FunctionCode;
if (Code.Contains(TEXT("return")))
{
    FunctionCode = Code;
}
else
{
    TStringBuilder<8 * 1024> FormattedCode;
    FormattedCode.Appendf(TEXT("return %s;"), *Code);
    ...
}

可以看到,UE非常粗暴的判断了代码内是否含有return字符串,也就是说,你不可以在HLSL出现return的字样,这包括如变量is_return,注释//return等。如果代码内出现return的字样,那就会判定该节点将以函数体方式转义。如果代码内没有return字样,那么就会以表达式方式转义。

也就是说,如果输入表达式:3, 那么会生成return 3

如果输入返回值 reutnr 1,那么会生成return 1

但如果输入了表达式returned(3);  因为判定returned字符内含有return,所以会生成returned(3);  结果无返回值错误

返回欺骗

如果在节点属性上写Include,那么这个Include的文件只会生成到函数体前面,如果需要include的这个文件内只是一段代码实现,比如:return 0.5; (AAAImpl.usf),那么我们就可以用上面的return逻辑来欺骗

include "/Engine/AAAImpl.usf"
//return

只要有return字样就可以让UE把这段代码视为函数体,从而不去生成return语句。