UE4·Custom Shader

UE的材质节点支持直接使用代码编写shader,但是节点中的代码编辑区域过于窄小,不方便直接书写大段代码。可以在custom节点中include相关shader文件进行材质制作。

生成shader文件

UE shader有两种后缀,.usf.ush,分别表示shader文件和shader头文件,两者区别不大,除了头文件可以包含一些共享定义,一般只用usf就足够了。在Engine/Shaders路径下可以看到引擎的shader文件。

通常创建UE项目后,在项目根目录下是看不到shader文件的,需要在ConsoleVariables.ini添加下述代码:

[SystemSettings]
; Uncomment to get detailed logs on shader compiles and the opportunity to retry on errors
r.ShaderDevelopmentMode=1
; Uncomment to dump shaders in the Saved folder
; Warning: leaving this on for a while will fill your hard drive with many small files and folders
r.DumpShaderDebugInfo=1
#; When this is enabled, when dumping shaders an additional file to use with ShaderCompilerWorker -direct mode will be generated
r.DumpShaderDebugWorkerCommandLine=1
; Uncomment when running with a graphical debugger (but not when profiling)
r.Shaders.Optimize=0
r.Shaders.KeepDebugInfo=1

添加完毕后,所有项目中使用的材质会生成shader文件,文件位于根目录/Saved/ShaderDebugInfo/[ShaderTarget],ShaderTarget可能是PCD3D_SM5

关于custom节点

当在custom节点中输入代码,实际上输入的代码会被加到以下函数中:

MaterialFloat3 CustomExpression0(FMaterialPixelParameters Parameters)
{
    //your code
}

即custom节点就像是一个空函数,可以在里面填写需要的shader内容。其他的一些用法可以参照这篇文章

在外部文件编辑shader会比较方便。直接在custom节点includeshader文件的绝对路径即可,但是每次编辑外部shader后,保存文件后需要在UE4材质中apply一下才会生效。

但是要以根目录为基础设置相对路径,则需要插件的帮助。

通过插件设置shader文件路径

首先创建一个blank插件,此处插件命名为MyShaderDevPlugin。在MyShaderDevPlugin.Build.cs中添加RenderCoreProjects模块。

// Public module source dependencies.
PublicDependencyModuleNames.AddRange(new string[] {
	"Core",
	"RenderCore", // Needed for AddShaderSourceDirectoryMapping & ResetAllShaderSourceDirectoryMappings
	"Projects" // Needed for IPluginManager
});

MyShaderDevPlugin.cpp中编辑路径映射代码:

// Copyright Epic Games, Inc. All Rights Reserved.

#include "MyShaderDevPlugin.h"
#include "Interfaces/IPluginManager.h"

#define LOCTEXT_NAMESPACE "FMyShaderDevPluginModule"

void FMyShaderDevPluginModule::StartupModule()
{
	FString ShaderDirectory = FPaths::Combine(FPaths::ProjectDir(), TEXT("Shaders"));
	AddShaderSourceDirectoryMapping("/Project", ShaderDirectory);   //"/Project"是我设置的虚拟路径
}

void FMyShaderDevPluginModule::ShutdownModule()
{
	// Cleanup the virtual source directory mapping.
	ResetAllShaderSourceDirectoryMappings();
}

#undef LOCTEXT_NAMESPACE
	
IMPLEMENT_PRIMARY_GAME_MODULE(FMyShaderDevPluginModule, MyShaderDevPlugin,"MyShaderDevPlugin")

至此路径映射的插件就写完了,在引擎中启用插件,即可使用自定义的虚拟路径来包含shader文件了。如上方我设置”/Project”为虚拟路径,则可在custom节点中填写

#include "/Project/MyShader.usf"
return 1;

则可读取到MyShader.usf的shader代码。当然如果有输入变量还是要手动在custom中进行输入。

参考

  1. Custom shader code in Unreal Engine — Part 1: Setup and Configuration
  2. Custom Shader Code in Unreal Engine — Part 2: Modularization
  3. Create a New Global Shader as a Plugin
  4. Fast Custom Shader Iteration Tips#