Use HLSL in UE5 by C++ Plugin
Why
For everyone used to use code based shader like hlsl or glsl or shaderlab, it could be painful to use the node based material editor especially when using complex calculation, nodes are hard to read and organize. Moreover some method is not able to use in material editor such as for loop and array index. I am working on a texture array shader and I need to pair index of UV region to each corresponding UV tilling parameters, I really need a for loop instead of using many if
nodes to make that work like…↓
In addition, a global shader (shaders that are not created using the Material Editor, operate on fixed geometry) can have more advanced functionality like post-processing effects or a custom shader pass, etc. And it’s able to created in a plugin which makes it easy to implement in other projects.
In this post I’am using a rather easy way to include the shader file in custom node in the Material Editor to use the function in the shader file. This could be a good start to get to know how to setup full global shader later.
How to
Create Your Plugin
First I created a plugin from the engine.
Unreal will create a directory for you with a directory comes with C++ files.
Create a Shader Folder
Afterwards, create a shader folder named Shaders
. Then your directory structure will looks like this ↓
Virtual Directory Mapping
The source files of any new shaders created need to be stored in the Engine/Shaders
folder. If a shader is part of a plugin, it should be stored in the Plugin/Shaders
folder instead.
Unreal actually sets the directory where you need to save your sourece shader files.
In this case there is a function named AddShaderSourceDirectoryMapping
:
This function maps a real shader directory existing on disk to a virtual shader directory
If I search this function, it is defined in ShaderCore.h
:
ShaderCore.h
is a headerfile from RenderCore
module, therefore to use it we need to append a module in the .Build.cs
file in your plugin folder.
I added the RenderCore
module as well as the Projects
module which we need for the IPluginManager
class, where we can use IPluginManager::FindPlugin
and use IPlugin::GetBaseDir
to get the plugin dir, therefore get the Shaders
folder.
In YourPluginFolder/Sourece/Private/YourPluginName.cpp
, adding codes like below:
At this point if you can have a successful build then can create the shader file.
Create a usf and ush file
In your Shaders
folder, created a text file and rename the extension to .usf
.
If you want have syntax highlight and hlsl extension option in Visual Studio, what I did is to download an extension:
I’m using this usf file as a custom node in the material editor, so that I can use for loop, but I wanna create a lib for my shader functions for future use, it won’t work if I write the function directly in the usf and include it in the custom node, because this will be a function inside another function that HLSL not allows:
Therefore I nested the function inside a struct in a ush
header file:
Afterwards it’s good to go for the usf
file, call that function:
Notice that the #include
hearder file path is the virtual path.
Include it in a custom node
Finally, press F5 to build and open the project, in custom node I included the usf
file and give corresponding input parameters:
Then it just works perfectly, and free to add more HLSL functions into the header file.
Tips
Enable r.ShaderDevelopmentMode
by setting it to 1. The easiest way is to edit ConsoleVariables.ini
(in YourEngineFolder/Engine/Config) so it is done every time you load. This will enable retry-on-error and shader development related logs and warnings.
I also recommend r.DumpShaderDebugInfo = 1
, this will save temp combined shader files to YourProject\Saved\ShaderDebugInfo\...