BlueRoseNote/03-UnrealEngine/Rendering/RenderingPipeline/UE4 材质编辑器 CustomNode使用技巧.md
2023-06-29 11:55:02 +08:00

86 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

之前有看过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+.不会真正的更新代码,必须手动断开节点连接再连接上,才会触发重新编译。
<!--more-->
### IncludeFilePaths
给Material添加ush与usf文件包含只支持以上2个后缀名。CustomNode会在生成的CustomExpressionX()之前加上
```c#
#include "你填入的文件路径"
```
这样你就可以在插件中的模块c++的StartupModule()中定义Shader映射目录之后将Shader函数代码写在插件里。映射操作大致如下
```c#
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为ValueDefineValue为1。那么Custom将会在生成的CustomExpressionX()之前加上:
```c#
#ifndef Value
#define Value 1
#endif//Value
```
### Additional Outputs
设置完OutputName与OutputType后就会在生成的函数的形参利添加对应类型的引用
```c#
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
节点代码中的`Parameters`为`FMaterialPixelParameters 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