文章

[ShaderGraph]添加自定义Pass

[ShaderGraph]添加自定义Pass

[ShaderGraph]添加自定义Pass

00 处理

00a 自定义Pass

仿照开关内置Pass的方式, 添加一个自定义Pass, 同时添加开关.

添加Pass可以仿照ShaderGraph自身Pass的写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public static PassDescriptor CrossSection(UniversalTarget target)
{
    var result = new PassDescriptor()
    {
        // Definition
        displayName = "CrossSection",
        // 这个地方是用来做比较进行一些宏定义的, 文件在
        // Library/PackageCache/com.unity.render-pipelines.universal@12.1.10/Editor/ShaderGraph/Includes/ShaderPass.hlsl
        // 如果你写自己的, 但是又没有在文件中, 默认第一个是SHADERPASS_FORWARD, 会导致光照相关的参数没有, 会报错
        referenceName = "SHADERPASS_UNLIT",
        lightMode = "CrossSection",
        useInPreview = true,

        // Template
        passTemplatePath = UniversalTarget.kUberTemplatePath,
        sharedTemplateDirectories = UniversalTarget.kSharedTemplateDirectories,

        // Port Mask
        validVertexBlocks = CoreBlockMasks.Vertex,
        validPixelBlocks = ExternalBlockMasks.FragmentCrossSection,

        // Fields
        structs = CoreStructCollections.Default,
        fieldDependencies = CoreFieldDependencies.Default,

        // Conditional State
        renderStates = ExternalRenderState.CrossSection(target),
        pragmas = CorePragmas.Instanced,
        defines = new DefineCollection(),
        keywords = new KeywordCollection(),
        includes = ExternalLitIncludes.CrossSection,

        // Custom Interpolator Support
        customInterpolators = CoreCustomInterpDescriptors.Common
    };

    ExtendedPasses.AddAlphaClipControlToPassMultiCompile(ref result, target);

    return result;
}

需要注意的是

  • referenceName = "SHADERPASS_UNLIT", referenceName是用来定义一些宏的开关的, 此处可以选择的值在Library/PackageCache/com.unity.render-pipelines.universal@12.1.10/Editor/ShaderGraph/Includes/ShaderPass.hlsl文件中, 如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    #ifndef UNIVERSAL_SHADERPASS_INCLUDED
    #define UNIVERSAL_SHADERPASS_INCLUDED
      
    #define SHADERPASS_FORWARD (0)
    #define SHADERPASS_GBUFFER (1)
    #define SHADERPASS_DEPTHONLY (2)
    #define SHADERPASS_SHADOWCASTER (3)
    #define SHADERPASS_META (4)
    #define SHADERPASS_2D (5)
    #define SHADERPASS_UNLIT (6)
    #define SHADERPASS_SPRITELIT (7)
    #define SHADERPASS_SPRITENORMAL (8)
    #define SHADERPASS_SPRITEFORWARD (9)
    #define SHADERPASS_SPRITEUNLIT (10)
    #define SHADERPASS_DEPTHNORMALSONLY (11)
    #define SHADERPASS_DBUFFER_PROJECTOR (12)
    #define SHADERPASS_DBUFFER_MESH (13)
    #define SHADERPASS_FORWARD_EMISSIVE_PROJECTOR (14)
    #define SHADERPASS_FORWARD_EMISSIVE_MESH (15)
    #define SHADERPASS_FORWARD_PREVIEW (16)
    #define SHADERPASS_DECAL_SCREEN_SPACE_PROJECTOR (17)
    #define SHADERPASS_DECAL_SCREEN_SPACE_MESH (18)
    #define SHADERPASS_DECAL_GBUFFER_PROJECTOR (19)
    #define SHADERPASS_DECAL_GBUFFER_MESH (20)
    #define SHADERPASS_DEPTHNORMALS (21)
    #endif
    

    如果要根据你自己的定义去对Library/PackageCache/com.unity.render-pipelines.universal@12.1.10/Editor/ShaderGraph/Includes/Varyings.hlsl做一些操作, 那么才需要添加, 否则使用现有的即可. 具体这些关键字的开关, 可以在Varyings.hlsl文件中去确认.

  • lightMode = "CrossSection",这个是用来在做RendererFeature的时候用来指定LightMode的, 需要保持一致.

  • validPixelBlocks = ExternalBlockMasks.FragmentCrossSection,这里只需要传递你要用到的中间变量即可. 比如我只需要用到的是:

    1
    2
    3
    4
    5
    6
    
    public static readonly BlockFieldDescriptor[] FragmentCrossSection = new BlockFieldDescriptor[]
    {
        ExtensionBlockFields.SurfaceDescription.CrossSectionColor,
        BlockFields.SurfaceDescription.Alpha,
        BlockFields.SurfaceDescription.AlphaClipThreshold,
    };
    
  • renderStates = ExternalRenderState.CrossSection(target),, 这里是定义ZTest, ZWrite, Cull之类的, 按照需求定义即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    public static RenderStateCollection CrossSection(UniversalTarget target)
    {
        var result = new RenderStateCollection
        {
            { RenderState.ZTest(ZTest.LEqual) },
            { RenderState.ZWrite(ZWrite.On) },
            { RenderState.Cull(Cull.Front) },
        };
      
        return result;
    }
    
  • includes = ExternalLitIncludes.CrossSection,这一行用来引用外部的hlsl, 具体定义如下, 这样就可以自己去写对应的hlsl文件.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    private const string kCrossSectionPass =
               "Packages/xxxx/ShaderLibrary/CrossSectionPass.hlsl";
    public static readonly IncludeCollection CrossSection = new IncludeCollection
    {
       // Pre-graph
       { CoreIncludes.CorePregraph },
       { CoreIncludes.ShaderGraphPregraph },
      
       // Post-graph
       { CoreIncludes.CorePostgraph },
       { kCrossSectionPass, IncludeLocation.Postgraph },
    };
    

    自定义的hlsl文件可以仿照Library/PackageCache/com.unity.render-pipelines.universal@12.1.10/Editor/ShaderGraph/Includes中的hlsl文件, 例子如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    
    #ifndef SG_CROSS_SECTION_PASS_INCLUDED
    #define SG_CROSS_SECTION_PASS_INCLUDED
      
    PackedVaryings vert(Attributes input)
    {
        Varyings output = (Varyings)0;
        output = BuildVaryings(input);
        PackedVaryings packedOutput = (PackedVaryings)0;
        packedOutput = PackVaryings(output);
        return packedOutput;
    }
      
    half4 frag(PackedVaryings packedInput) : SV_TARGET
    {
        Varyings unpacked = UnpackVaryings(packedInput);
        UNITY_SETUP_INSTANCE_ID(unpacked);
        UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(unpacked);
        SurfaceDescription surfaceDescription = BuildSurfaceDescription(unpacked);
      
        #if _ALPHATEST_ON
        half alpha = surfaceDescription.Alpha;
        clip(alpha - surfaceDescription.AlphaClipThreshold);
        #else
        half alpha = 1.h;
        #endif
      
        half4 color = half4(surfaceDescription.CrossSectionColor,alpha);
      
        return 0;
    }
      
    #endif
    

00b 在SubShader中调用Pass

1
2
3
4
5
6
7
8
9
10
11
12
public static SubShaderDescriptor VehicleLitGLESSubShader(UniversalTarget target, WorkflowMode workflowMode,
            string renderType, string renderQueue, bool complexLit,
            SubShaderOptions options)
{
    ...

    if (options.crossSectionPassOn)
        result.passes.Add(SubShaderUtils.PassVariant(ExtendedPasses.CrossSection(target),
            ExtendedPragmas.ExtendedDefault));

    return result;
}

参考网页

本文由作者按照 CC BY 4.0 进行授权