[Unreal教程] 如何将全局着色器添加到UE4
如何将全局着色器添加到UE4


在虚幻引擎4中,全局着色器是可以从C ++方面使用的渲染后处理效果,调度计算着色器,清除屏幕等的着色器(即,不对材质或网格进行操作的着色器)。 有时,需要更高级的功能来实现

所需的外观,并且需要定制着色器传递。 这样做比较简单,我将在这里解释一下。
UE4从引擎/着色器文件夹中读取.usf文件(虚幻着色器文件)。 任何新的着色器都需要将源文件放在这里。 从4.17开始,着色器也可以从插件(插件/着色器)读取。 我建议在您的ConsoleVariables.ini文件中启用r.ShaderDevelopmentMode = 1以便于开发。 查看文档了解更多信息。

我们先从您的引擎/着色器文件夹中添加一个新的.usf文件。 我们称它为MyTest.usf。 然后添加一个简单的直通顶点着色器和一个返回自定义颜色的像素着色器:

[mw_shl_code=cpp,true]// MyTest.usf

// Simple pass-through vertex shader

void MainVS(
        in float4 InPosition : ATTRIBUTE0,
        out float4 Output : SV_POSITION
)
{
        Output = InPosition;
}

// Simple solid color pixel shader
float4 MyColor;
float4 MainPS() : SV_Target0
{
        return MyColor;
}[/mw_shl_code]


现在,为了让UE4拿起着色器并开始编译,我们需要声明一个C ++类。 我们从顶点着色器开始:



这里有一些要求:



  • 这是FGlobalShader的子类。 因此,它将最终在全球着色器地图(这意味着我们不需要材料找到它)。
  • DECLARE_EXPORTED_SHADER_TYPE()宏的使用将生成着色器类型的序列化所需的导出等。第三个参数是一个外部链接的类型,用于代码模块的外部链接,如果需要,着色器模块将生存(例如C ++代码, t住在渲染器模块中)。
  • 两个构造函数,默认和序列化。
  • 需要决定是否在特定情况下编译这个着色器的ShouldCache()函数(例如,我们可能不希望在具有非计算着色器的RHI上编译计算着色器)。



随着类声明,我们现在可以将着色器类型注册到UE4的列表中:

[mw_shl_code=cpp,true]// This needs to go on a cpp file
IMPLEMENT_SHADER_TYPE(, FMyTestVS, TEXT("MyTest"), TEXT("MainVS"), SF_Vertex);[/mw_shl_code]


该宏将类型(FMyTestVS)映射到.usf文件(MyTest.usf),着色器入口点(MainVS)和频率/着色器阶段(SF_Vertex)。 只要它的ShouldCache()方法返回true,它也会使着色器被添加到编译列表中。

注意:无论您将FGlobalShader添加到实际引擎启动前必须加载的模块,或者您将得到一个assert,如“引擎初始化之后加载着色器类型,在模块上使用ELoadingPhase :: PostConfigInit以使其早期加载 “我们目前不允许在游戏或编辑器启动后加载自己的着色器类型的动态模块。



现在我们来宣布更有趣的Pixel Shader:

[mw_shl_code=cpp,true]class FMyTestPS : public FGlobalShader
{
        DECLARE_EXPORTED_SHADER_TYPE(FMyTestPS, Global, /*MYMODULE_API*/);

        FShaderParameter MyColorParameter;

        FMyTestPS() { }
        FMyTestPS(const ShaderMetaType::CompiledShaderInitializerType& Initializer)
                : FGlobalShader(Initializer)
        {
                MyColorParameter.Bind(Initializer.ParameterMap, TEXT("MyColor"), SPF_Mandatory);
        }

        static void ModifyCompilationEnvironment(EShaderPlatform Platform, FShaderCompilerEnvironment& OutEnvironment)
        {
                FGlobalShader::ModifyCompilationEnvironment(Platform, OutEnvironment);
                // Add your own defines for the shader code
                OutEnvironment.SetDefine(TEXT("MY_DEFINE"), 1);
        }

        static bool ShouldCache(EShaderPlatform Platform)
        {
                // Could skip compiling for Platform == SP_METAL for example
                return true;
        }

        // FShader interface.
        virtual bool Serialize(FArchive& Ar) override
        {
                bool bShaderHasOutdatedParameters = FGlobalShader::Serialize(Ar);
                Ar << MyColorParameter;
                return bShaderHasOutdatedParameters;
        }

        void SetColor(FRHICommandList& RHICmdList, const FLinearColor& Color)
        {
                SetShaderValue(RHICmdList, GetPixelShader(), MyColorParameter, Color);
        }
};

// Same source file as before, different entry point
IMPLEMENT_SHADER_TYPE(, FMyTestPS, TEXT("MyTest"), TEXT("MainPS"), SF_Pixel);[/mw_shl_code]


在这个类中,我们现在正在从.usf文件中显示着色器参数MyColor:


  • FShaderParameter MyColorParameter成员被添加到类中,该类将保存运行时的信息,以便能够找到绑定,允许在运行时设置参数的值。
  • 在序列化构造函数中,我们通过名称将参数绑定到ParameterMap,这必须匹配.usf文件的名称。
  • 当相同的C ++类定义不同的行为并且能够在着色器中设置#define值时,将使用新的ModifyCompilationEnvironment()函数。
  • Serialize()方法是必需的。 这是从着色器的绑定(在序列化构造函数中匹配)的编译/烹饪时间信息在运行时被加载和存储的地方。
  • 最后,我们有一个自定义的SetColor()方法,它显示了如何在运行时使用指定的值设置MyColor参数。




现在,我们用一个简单的函数来绘制一个使用这些着色器类型的全屏四边形:

[mw_shl_code=cpp,true]void RenderMyTest(FRHICommandList& RHICmdList, ERHIFeatureLevel::Type FeatureLevel, const FLinearColor& Color)
{
        // Get the collection of Global Shaders
        auto ShaderMap = GetGlobalShaderMap(FeatureLevel);

        // Get the actual shader instances off the ShaderMap
        TShaderMapRef MyVS(ShaderMap);
        TShaderMapRef MyPS(ShaderMap);

        // Declare a bound shader state using those shaders and apply it to the command list
        static FGlobalBoundShaderState MyTestBoundShaderState;
        SetGlobalBoundShaderState(RHICmdList, FeatureLevel, MyTestBoundShaderState, GetVertexDeclarationFVector4(), *MyVS, *MyPS);

        // Call our function to set up parameters
        MyPS->SetColor(RHICmdList, Color);

        // Setup the GPU in prep for drawing a solid quad
        RHICmdList.SetRasterizerState(TStaticRasterizerState::GetRHI());
        RHICmdList.SetBlendState(TStaticBlendState<>::GetRHI());
        RHICmdList.SetDepthStencilState(TStaticDepthStencilState::GetRHI(), 0);

        // Setup the vertices
        FVector4 Vertices[4];
        Vertices[0].Set(-1.0f, 1.0f, 0, 1.0f);
        Vertices[1].Set(1.0f, 1.0f, 0, 1.0f);
        Vertices[2].Set(-1.0f, -1.0f, 0, 1.0f);
        Vertices[3].Set(1.0f, -1.0f, 0, 1.0f);

        // Draw the quad
        DrawPrimitiveUP(RHICmdList, PT_TriangleStrip, 2, Vertices, sizeof(Vertices[0]));
}[/mw_shl_code]


如果你想在你的代码库中测试这个,你可以尝试声明一个控制台变量,这样它就可以像运行时那样切换:

[mw_shl_code=cpp,true]static TAutoConsoleVariable CVarMyTest(
        TEXT("r.MyTest"),
        0,
        TEXT("Test My Global Shader, set it to 0 to disable, or to 1, 2 or 3 for fun!"),
        ECVF_RenderThreadSafe
);

void FDeferredShadingSceneRenderer::RenderFinish(FRHICommandListImmediate& RHICmdList)
{
        [...]
        // ***
        // Inserted code, just before finishing rendering, so we can overwrite the screen’s contents!
        int32 MyTestValue = CVarMyTest.GetValueOnAnyThread();
        if (MyTestValue != 0)
        {
                FLinearColor Color(MyTestValue == 1, MyTestValue == 2, MyTestValue == 3, 1);
                RenderMyTest(RHICmdList, FeatureLevel, Color);
        }
        // End Inserted code
        // ***
        FSceneRenderer::RenderFinish(RHICmdList);
        [...]
}[/mw_shl_code]


在这一点上,您应该可以测试我们的新的全球着色器! 运行您的项目,然后使用波浪号(〜)拉起控制台并输入r.MyTest 1.然后键入r.MyTest 2和/或r.MyTest 3来更改颜色。 使用r.MyTest 0禁用通行证。


调试生成的源代码
看看博客文章调试着色器编译过程,如果你想能够调试.usf文件的编译和/或看到处理的文件。


总结
您可以在一个未用的游戏/编辑器运行时修改.usf文件,然后按Ctrl + Shift +。 (期间)或类型重编译器在控制台中更改,以拾取并重建您的着色器以进行快速迭代!






原文标题:How to Add Global Shaders to UE4


谢谢分享
666666666厉害了
  • 地板 gforcex
  • 2017-9-30 09:53:31
感谢分享
感谢分享
在虚幻引擎4中,全局着色器是可以从C ++方面使用的渲染后处理效果,调度计算着色器,清除屏幕等的着色器(即,不对材质或网格进行操作的着色器)。 有时,需要更高级的功能来实现

所需的外观,并且需要定制着色器传递。 这样做比较简单,我将在这里解释一下。
UE4从引擎/着色器文件夹中读取.usf文件(虚幻着色器文件)。 任何新的着色器都需要将源文件放在这里。 从4.17开始,着色器也可以从插件(插件/着色器)读取。 我建议在您的ConsoleVariables.ini文件中启用r.ShaderDevelopmentMode = 1以便于开发。 查看文档了解更多信息。
好帖留名
  • 8# hc026
  • 2017-10-6 06:36:15 来自Mobile---
感谢分享
  • 9# 苏洛
  • 2017-10-9 09:26:07
学习了 收藏了
666666666666

如何将全局着色器添加到UE4


在虚幻引擎4中,全局着色器是可以从C ++方面使用的渲染后处理效果,调度计算着色器,清除屏幕等的着色器(即,不对材质或网格进行操作的着色器)。 有时,需要更高级的功能来实现

所需的外观,并且需要定制着色器传递。 这样做比较简单,我将在这里解释一下。
UE4从引擎/着色器文件夹中读取.usf文件(虚幻着色器文件)。 任何新的着色器都需要将源文件放在这里。 从4.17开始,着色器也可以从插件(插件/着色器)读取。 我建议在您的ConsoleVariables.ini文件中启用r.ShaderDevelopmentMode = 1以便于开发。 查看文档了解更多信息
这种东西是用来做PostProcess后处理的吧,叫全局不是太贴切。暂时还不懂。这类着色器不要传递什么参数,确实用用其他插件做也可以
感谢分享
这种东西是用来做PostProcess后处理的吧,叫全局不是太贴切。暂时还不懂。这类着色器不要传递什么参数,确实用用其他插件做也可以
66666666666666666666666666
12下一页