参考链接:如何为 UE4 添加全局着色器(Global Shaders) - Unreal Enginehttps://docs.unrealengine.com/5.1/zh-CN/adding-global-shaders-to-unreal-engine/如何为 UE4 添加全局着色器(Global Shaders) - Unreal Engine
参考链接:虚幻4渲染管线入门 - 知乎
参考链接:https://www.cnblogs.com/wellbye/p/5837108.html
编译失败可以参考文章:【UE·Editor篇】UE编辑器开发的常见编译失败原因总结_水曜日鸡的博客-CSDN博客_implement_module
1,如何让ue4读取并编译着色器
// This can go on a header or cpp file class FMyTestVS : public FGlobalShader { DECLARE_EXPORTED_SHADER_TYPE(FMyTestVS, Global, /*MYMODULE_API*/); FMyTestVS() { } FMyTestVS(const ShaderMetaType::CompiledShaderInitializerType& Initializer) : FGlobalShader(Initializer) { } static bool ShouldCache(EShaderPlatform Platform) { return true; } };
1,继承于FGlobalShader类
2,用 DECLARE_EXPORTED_SHADER_TYPE() 这个宏可以生成导出信息,对序列化该 shader 类型是必须的。在需要的时候,第三个参数是代码模块的外部链接类型,该 shader 模块位于这个代码模块中
3,两个构造函数,分别是默认构造和用于序列化。
4,ShouldCache() 函数需要用来判定该 Shader 是否需要在特定情形下进行编译(比如,我们应该并不希望在一个没有计算 Shader 能力的 RHI 上编译一个需要计算能力的 Shader)。
class FBlurLightShaftsPixelShader : public FGlobalShader { public: DECLARE_GLOBAL_SHADER(FBlurLightShaftsPixelShader); SHADER_USE_PARAMETER_STRUCT(FBlurLightShaftsPixelShader, FGlobalShader); BEGIN_SHADER_PARAMETER_STRUCT(FParameters, ) SHADER_PARAMETER_STRUCT_INCLUDE(FLightShaftPixelShaderParameters, LightShafts) SHADER_PARAMETER_RDG_TEXTURE(Texture2D, SourceTexture) SHADER_PARAMETER(FVector4, RadialBlurParameters) RENDER_TARGET_BINDING_SLOTS() END_SHADER_PARAMETER_STRUCT() static bool ShouldCompilePermutation(const FGlobalShaderPermutationParameters& Parameters) { return IsFeatureLevelSupported(Parameters.Platform, ERHIFeatureLevel::SM5); } static void ModifyCompilationEnvironment(const FGlobalShaderPermutationParameters& Parameters, FShaderCompilerEnvironment& OutEnvironment) { OutEnvironment.SetDefine(TEXT("NUM_SAMPLES"), GLightShaftBlurNumSamples); } }; IMPLEMENT_GLOBAL_SHADER(FBlurLightShaftsPixelShader, "/Engine/Private/LightShaftShader.usf", "BlurLightShaftsMain", SF_Pixel);
其中,DECLARE_GLOBAL_SHADER(...)会设置一些默认的成员变量及函数SHADER_USE_PARAMETER_STRUCT(...)宏的用于将声明的FParameters结构体与shader中的字段进行绑定。
使用下面宏来声明FParameters结构体,此处的FParameters为固定用法,不能写成其他的名字
BEGIN_SHADER_PARAMETER_STRUCT(FParameters,)
....//与Shader中的参数对应.....
RENDER_TARGET_BINDING_SLOTS()
END_SHADER_PARAMETER_STRUCT()
通过这种方式来声明参数结构体,将C++代码与shader中的参数对应,C++中参数可少写,即只会更新结构体中的参数。其中的RENDER_TARGET_BINDING_SLOTS()会添加RenderTarget接口。(看不懂)
这种声明方式与GraphBuilder相结合,可使开发得到极大的简化。若使用RenderPass的方式,可使用另外的方式来设置参数。
在声明了shader类后,使用IMPLEMENT_GLOBAL_SHADER(...)来将shader类与shader文件中的实现进行对应,即对shader进行实现。参数分别为IMPLEMENT_GLOBAL_SHADER(类名,shader文件路径,shader文件中的方法名,shader类型)
该结构体和实现可写在类的外面甚至另外的文件中,方便访问即可。
shader内容可以参考LigthShaftShader.usf,注意在写自己的shader时需包含#include "Common.ush"
2,IMPLEMENT_SHADER_TYPE
这个宏将类型 (FMyTestVS) 映射到 .usf 文件 (MyTest.usf) 上,该 Shader 的入口 (MainVS),以及 frequency/shader stage (SF_Vertex)。并且它也使得该 Shader
在 ShouldCache() 方法返回 true 时,能够加入到编译列表中
3,IMPLEMENT_MODULE
ue4的代码是模块的形式来组织。
在源码层面,一个包含*.build.cs的目录就是一个模块。
这个目录里的文件在编译后都会被链接在一起,比如一个静态库lib,或者一个动态库dll。
不管是哪种形式,都需要提供一个给外部操作的接口,也就是一个IModuleInterface指针。
*注意这里并不是说调用模块内任何函数(或类)都要通过该指针来进行,实际上外部代码只要include了相应的头文件,就能直接调用对应的功能了(比如new一个类,调一个全局函数等),因为实现代码要么做为lib被链接进exe,或是做为dll被动态加载了。
这个IModuleInterface指针是用来操作做为整体的模块本身的,比如说模块的加载、初始化和卸载,以及访问模块内的一些全局变量(向下转成具体的模块类型后)
外部获取这个指针,只有一个办法,就是通过FModuleManager上的LoadModule/GetModule。
而FModuleManager去哪里找需要的模块呢?
1、在动态链接情况下,根据名字直接找对应的dll就行了,做为合法ue4模块的dll,必定要导出一些约定的函数,来返回自身IModuleInterface指针。
2、在静态链接时,去一个叫StaticallyLinkedModuleInitializers的Map里找,这就要求所有模块已把自己注册到这个Map里。
以上2点基本就是FModuleManager::LoadModule的内容。