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
							 |