天天看點

UE4 編寫着色器以及各種宏的了解

參考連結:如何為 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指針是用來操作做為整體的子產品本身的,比如說子產品的加載、初始化和解除安裝,以及通路子產品内的一些全局變量(向下轉成具體的子產品類型後)

UE4 編寫着色器以及各種宏的了解

外部擷取這個指針,隻有一個辦法,就是通過FModuleManager上的LoadModule/GetModule。

而FModuleManager去哪裡找需要的子產品呢?

1、在動态連結情況下,根據名字直接找對應的dll就行了,做為合法ue4子產品的dll,必定要導出一些約定的函數,來傳回自身IModuleInterface指針。

2、在靜态連結時,去一個叫StaticallyLinkedModuleInitializers的Map裡找,這就要求所有子產品已把自己注冊到這個Map裡。

以上2點基本就是FModuleManager::LoadModule的内容。

繼續閱讀