86 lines
5.6 KiB
Markdown
86 lines
5.6 KiB
Markdown
|
之前有看过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为Value,DefineValue为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
|