BlueRose
文章97
标签28
分类7
UE4 材质编辑器 CustomNode使用技巧

UE4 材质编辑器 CustomNode使用技巧

之前有看过MeshDraw的流程,发现MeshDraw部分还是和材质编辑器帮得死死的。(不过应该可以通过自定义MeshDrawPass、图元类、定点工厂来直接使用VS与PS Shader。不过这样就无法使用材质编辑器进行简单的Shader编写与使用Material Instance来调节参数,只能使用c++进行参数传递非常得不方便)在使用材质编辑器的情况,使用CustomNode可以更多的自由度,比如使用一些UE在ush定义的函数以及循环等;更好的可读性以及方便项目升级与后续项目使用等。

这里我总结了一些CustomNode使用方法。使用CustomNode时最好将ConsoleVariables.ini中的 r.ShaderDevelopmentMode设置为1。这样可以看到更多的Shader错误信息,但老实说UE4的Shader错误提示真心不能与U3D比……

采用CustomNode+Include usf文件的方式,使用Ctrl+Shift+.不会真正的更新代码,必须手动断开节点连接再连接上,才会触发重新编译。

IncludeFilePaths

给Material添加ush与usf文件包含,只支持以上2个后缀名。CustomNode会在生成的CustomExpressionX()之前加上

#include "你填入的文件路径"

这样你就可以在插件中的模块c++的StartupModule()中定义Shader映射目录,之后将Shader函数代码写在插件里。映射操作大致如下:

void FXXXModule::StartupModule()
{
    // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
    FString PluginShaderDir=FPaths::Combine(IPluginManager::Get().FindPlugin(TEXT("XXX"))->GetBaseDir(),TEXT("Shaders"));
    AddShaderSourceDirectoryMapping(TEXT("/Plugin/YYY"),PluginShaderDir);
}

Additional Defines

用来定义宏,假设DefineName为Value,DefineValue为1。那么Custom将会在生成的CustomExpressionX()之前加上:

#ifndef Value
#define Value 1
#endif//Value

Additional Outputs

设置完OutputName与OutputType后就会在生成的函数的形参利添加对应类型的引用:

CustomExpression0(FMaterialPixelParameters Parameters, inout MaterialFloat Ret1)

之后就可以CustomNode节点中给这个形参赋值,最后从CustomNode节点生成的输出节点中去到数值。

在CustomNode中使用节点代码

前几年刚接触CustomNode的时候一直都在思考如果使用一些带有Parameters参数的函数,比如AbsoluteWorldPosition:GetWorldPosition(Parameters)。这几天在回过头看了一下,只需要在函数中添加一个FMaterialPixelParameters Parameters或者FMaterialVertexParameters Parameters形参,之后就可以在函数利使用这些函数了。

常用节点HlSL代码

  • AbsoluteWorldPosition:GetWorldPosition(Parameters)
  • AbsoluteWorldPosition(ExcludingMaterialOffsets):GetPrevWorldPosition(Parameters)
  • VertexNormalPosition:Parameters.TangentToWorld[2];
  • PixelNormalWS:Parameters.WorldNormal
  • ObjectPosition:GetObjectWorldPosition(Parameters)
  • CameraPosition:ResolvedView.WorldCameraOrigin
  • LightVector:Parameters.LightVector
  • ResolvedView.DirectionalLightDirection
  • ResolvedView.DirectionalLightColor.rgb
  • ResolvedView.SkyLightColor.rgb;
  • ResolvedView.PreExposure
  • EyeAdaptation:EyeAdaptationLookup() 位于EyeAdaptationCommon.ush

需要开启大气雾:

  • SkyAtmosphereLightColor:·.AtmosphereLightColor[LightIndex].rgb
  • SkyAtmosphereLightDirection:ResolvedView.AtmosphereLightDirection[LightIndex].xyz

节点代码中的ParametersFMaterialPixelParameters Parameters或者FMaterialVertexParameters Parameters结构体,两者都可以在MaterialTemplate.ush中找到成员定义。
其他一些节点中会使用View.XXX来获取变量,这里的View等于ResolvedView。具体的变量可以通过查看FViewUniformShaderParameters(c++)。

剩下的一些节点代码可以通过材质编辑器的Window-ShaderCode-HLSL来找到。具体的方式是将所需节点连到对应引脚上,之后将生成过得代码复制出来再进行寻找。当然也可以直接在FHLSLMaterialTranslator中来寻找对应节点的代码。

一些常用shader函数都可以在Common.ush找到。

Texture

在CustomNode里使用Texture,只需要给CustomNode连上TextureObject节点,之后材质编辑器会自动生成对应的Sampler。例如:Pin名称为XXX,那就会生成XXXSampler,之后向函数传递这2个参数即可。
函数中的形参类型为Texture2D与SamplerState。

TextureCoord虽然可以通过代码调用,但会出现错误,可能是因为材质编辑器没有检测到TextureCoord节点,以至于没有添加对应代码所致。所以TextureCoord节点还是需要连接到CustomNode的pin上,无法通过代码省略。

默认贴图

所以一些控制类的贴图可以使用引擎里的资源,这些资源在Engine Content中,需要勾选显示Engine Content选项后才会显示:
Texture2D’/Engine/EngineResources/WhiteSquareTexture.WhiteSquareTexture’
Texture2D’/Engine/EngineResources/Black.Black’

HLSL分支控制关键字

一些if与for语句会产生变体,所以在CustomNode里可以通过添加以下关键字来进行控制变体产生。

if语句

  • branch:添加了branch标签的if语句shader会根据判断语句只执行当前情况的代码,这样会产生跳转指令。
  • flatten:添加了flatten标签的if语句shader会执行全部情况的分支代码,然后根据判断语句来决定使用哪个结果。

for语句

  • unroll:添加了unroll标签的for循环是可以展开的,直到循环条件终止,代价是产生更多机器码
  • loop:添加了loop标签的for循环不能展开,流式控制每次的循环迭代,for默认是loop