UE4:Shader Permutation & Compile

如需转载本文,请声明作者及出处。


新增Shader时,通常需要用到以下的宏

DECLARE_SHADER_TYPE(FMobileXXXVS, MeshMaterial);
DECLARE_SHADER_TYPE(FMobileXXXPS, MeshMaterial);
IMPLEMENT_MATERIAL_SHADER_TYPE(, FMobileXXXVS, TEXT("/Engine/Private/XXXPassShader.usf"), TEXT("MainVS"), SF_Vertex);
IMPLEMENT_MATERIAL_SHADER_TYPE(, FMobileXXXPS, TEXT("/Engine/Private/XXXPassShader.usf"), TEXT("MainPS"), SF_Pixel);
IMPLEMENT_VERTEX_FACTORY_TYPE(FXXXVertexFactory, "/Engine/Private/XXXPassShader.usf", true, false, false, false, false);


才能实现c++类与Shader的绑定,才能在MeshPipeline中,AddMeshBatch时取到相应的shader的。
但在ue4中,是如何做到的呢?


Shader Permutation

1.几个关键宏的展开

先来看看DECLARE_SHADER_TYPE的展开

#define DECLARE_EXPORTED_SHADER_TYPE(ShaderClass,ShaderMetaTypeShortcut,RequiredAPI, ...) \
    public: \
    using FPermutationDomain = FShaderPermutationNone; \
    using ShaderMetaType = F##ShaderMetaTypeShortcut##ShaderType; \
    \
    static RequiredAPI ShaderMetaType StaticType; \
    \
    static FShader* ConstructSerializedInstance() { return new ShaderClass(); } \
    static FShader* ConstructCompiledInstance(const ShaderMetaType::CompiledShaderInitializerType& Initializer) \
    { return new ShaderClass(Initializer); } \
    \
    virtual uint32 GetTypeSize() const override { return sizeof(*this); }

以TMobileBasePassPS为例

template< typename LightMapPolicyType, EOutputFormat OutputFormat, bool bEnableSkyLight, bool bRenderRuntimeProceduralTexture, int32 NumMovablePointLights>
class TMobileBasePassPS : public TMobileBasePassPSBaseType<LightMapPolicyType>
{
    DECLARE_SHADER_TYPE(TMobileBasePassPS,MeshMaterial);
}

会被展开为:

class TMobileBasePassPS : public TMobileBasePassPSBaseType<LightMapPolicyType>
{
using ShaderMetaType = FMeshMaterialShaderType;
static RequiredAPI ShaderMetaType StaticType;
}

如此,TMobileBasePassPS便有了ShaderMetaType 和 ShaderMetaType

而FShaderType是模板类的实例化类的静态成员,FShaderType构造函数里面会把自己注册到全局链表FShaderType::GetTypeList()里:

TLinkedList<FShaderType*>*& FShaderType::GetTypeList()
{
    return GShaderTypeList;
}

FShaderType::FShaderType(...)
{
    GlobalListLink.LinkHead(GetTypeList());
}


现在再来看看IMPLEMENT_MATERIAL_SHADER_TYPE的展开

#define IMPLEMENT_MATERIAL_SHADER_TYPE(TemplatePrefix,ShaderClass,SourceFilename,FunctionName,Frequency) \
    IMPLEMENT_SHADER_TYPE( \
        TemplatePrefix, \
        ShaderClass, \
        SourceFilename, \
        FunctionName, \
        Frequency \
        );

#define IMPLEMENT_SHADER_TYPE(TemplatePrefix,ShaderClass,SourceFilename,FunctionName,Frequency) \
    TemplatePrefix \
    ShaderClass::ShaderMetaType ShaderClass::StaticType( \
        TEXT(#ShaderClass), \
        SourceFilename, \
        FunctionName, \
        Frequency, \
        1, \
        ShaderClass::ConstructSerializedInstance, \
        ShaderClass::ConstructCompiledInstance, \
        ShaderClass::ModifyCompilationEnvironment, \
        ShaderClass::ShouldCompilePermutation, \
        ShaderClass::ValidateCompiledResult \
        );

所以,

IMPLEMENT_MATERIAL_SHADER_TYPE(, FMobileXXXPS, TEXT("/Engine/Private/XXXPassShader.usf"), TEXT("MainPS"), SF_Pixel);

将会被展开为:

FMobileXXXPS::ShaderMetaType FMobileXXXPS::StaticType("XXXPassShader.usf", "MainPS", SF_Pixel);

其中,FMobileXXXPS::ShaderMetaType FMobileXXXPS::StaticType 在DECLARE_SHADER_TYPE 展开时,已经指定。

所以,这也是为什么使用定制自己的shader时要先

class FMobileXXXPS : public FMeshMaterialShader
{
    DECLARE_SHADER_TYPE(FMobileXXXPS, MeshMaterial);
public:
    ...
}

IMPLEMENT_MATERIAL_SHADER_TYPE(, FMobileXXXPS, TEXT("/Engine/Private/XXXPassShader.usf"), TEXT("MainPS"), SF_Pixel);

2.Shader Permutation

但以上只是讨论了几个宏的展开,没有涉及shader的变体,在ue4中,Shader Permutation又是如何运行的呢?
同样以TMobileBasePassPS 为例:

template< typename LightMapPolicyType, EOutputFormat OutputFormat, bool bEnableSkyLight, bool bRenderRuntimeProceduralTexture, int32 NumMovablePointLights>
class TMobileBasePassPS : public TMobileBasePassPSBaseType<LightMapPolicyType>
{
    ...
}


可以看到TMobileBasePassPS是一个模板类,有四个模板参数:
LightMapPolicyType,各种PolicyType在LightMapRendering.h中定义,如light map和shadow等的渲染,
引擎中Indirect Light Cache、VLM、Distance Field Shadow都有对应的LightMapPolicy类
OutputFormat,PS的输出是gamma的还是linear
bEnableSkyLight,是否开启SkyLight
NumMovablePointLights,PS里要处理的动态点光源的数目这些参数在GetUniformMobileBasePassShaders中使用

template <ELightMapPolicyType Policy, int32 NumMovablePointLights>
void GetUniformMobileBasePassShaders(
    const FMaterial& Material,
    FVertexFactoryType* VertexFactoryType,
    bool bEnableSkyLight,
    bool bRenderRuntimeProceduralTexture,
    TMobileBasePassVSPolicyParamType<FUniformLightMapPolicy>*& VertexShader,
    TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>*& PixelShader
    )
{
    if (IsMobileHDR())
    {
        VertexShader = (TMobileBasePassVSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader<TMobileBasePassVS<TUniformLightMapPolicy<Policy>, HDR_LINEAR_64> >(VertexFactoryType);

        if (bEnableSkyLight)
        {
            if (bRenderRuntimeProceduralTexture)
            {
                PixelShader = (TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader< TMobileBasePassPS<TUniformLightMapPolicy<Policy>, HDR_LINEAR_64, true, true, NumMovablePointLights> >(VertexFactoryType);
            }
            else
            {
                PixelShader = (TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader< TMobileBasePassPS<TUniformLightMapPolicy<Policy>, HDR_LINEAR_64, true, false, NumMovablePointLights> >(VertexFactoryType);
            }
        }
        else
        {
            if (bRenderRuntimeProceduralTexture)
            {
                PixelShader = (TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader< TMobileBasePassPS<TUniformLightMapPolicy<Policy>, HDR_LINEAR_64, false, true, NumMovablePointLights> >(VertexFactoryType);
            }
            else
            {
                PixelShader = (TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader< TMobileBasePassPS<TUniformLightMapPolicy<Policy>, HDR_LINEAR_64, false, false, NumMovablePointLights> >(VertexFactoryType);
            }
        }
    }
    else
    {
        VertexShader = (TMobileBasePassVSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader<TMobileBasePassVS<TUniformLightMapPolicy<Policy>, LDR_GAMMA_32> >(VertexFactoryType);

        if (bEnableSkyLight)
        {
            if (bRenderRuntimeProceduralTexture)
            {
                PixelShader = (TMobileBasePassPSPolicyParamType<FUniformLightMapPolicy>*)Material.GetShader< TMobileBasePassPS<TUniformLightMapPolicy<Policy>, LDR_GAMMA_32, true, true, NumM
  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值