• 深入URP之Shader篇5: SimpleLit Shader分析(1)


    SimpleLit.shader

    本篇开始分析simple lit shader。我们通过分析unlit shader了解了URP shader的结构,以及一些基础功能。而simple lit shader包含了更多的内容。本篇开始,就不会特别仔细的逐行去分析shader文件了,只会针对pass的功能中比较有意思且之前没看到过的内容进行分析。

    ForwardLit

    名字为ForwardLit的pass,它的Tags为:

    Tags { "LightMode" = "UniversalForward" }
    
    • 1

    根据URP的文档:

    UniversalForward : The Pass renders object geometry and evaluates all light contributions. URP uses this tag value in the Forward Rendering Path.

    说明这是一个前向渲染路径的pass,虽然URP(至少是10.8.1版本)还没有正式支持Deferred Rendering,但URP已经为它打了很多基础,所以会特意标明这个pass是前向渲染还是延迟渲染,如果是延迟渲染则会使用LightModeUniversalGBuffer,SimpleLit shader也有这个pass,但是暂时不会研究它。

    支持的关键字

    看一下ForwardLit支持的关键字,就可以大概看出实现了哪些功能,当然本身的功能就是光照不必说。

                // -------------------------------------
                // Material Keywords
                #pragma shader_feature_local_fragment _ALPHATEST_ON
                #pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON
                #pragma shader_feature_local_fragment _ _SPECGLOSSMAP _SPECULAR_COLOR
                #pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
                #pragma shader_feature_local _NORMALMAP
                #pragma shader_feature_local_fragment _EMISSION
                #pragma shader_feature_local _RECEIVE_SHADOWS_OFF
    
                // -------------------------------------
                // Universal Pipeline keywords
                #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
                #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
                #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
                #pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
                #pragma multi_compile_fragment _ _SHADOWS_SOFT
                #pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
                #pragma multi_compile _ SHADOWS_SHADOWMASK
                #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
    
                // -------------------------------------
                // Unity defined keywords
                #pragma multi_compile _ DIRLIGHTMAP_COMBINED
                #pragma multi_compile _ LIGHTMAP_ON
                #pragma multi_compile_fog
    
                //--------------------------------------
                // GPU Instancing
                #pragma multi_compile_instancing
                #pragma multi_compile _ DOTS_INSTANCING_ON
    
    • 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

    可以看到,这些关键字分了几类。比如Material Keywords都是使用shader feature定义的,这些是材质上可以开关选择的关键字,比如我们之前看到过的alpha test, alpha premultiply;而simpeLit增加的有Specular GlossMap/Specular Color, Normalmap, Emission以及ReceiveShadowsOff,除了最后一个,都是和计算光照相关的选项,涉及到高光,法线贴图和自发光,我们会在shader里面看到它们的实现。
    Universal Pipeline keywords这一组则是URP的一些全局设置相关的,这里的全局只是相对于材质来说,也不是local/global keywords那个全局。比如_MAIN_LIGHT_SHADOWS决定了是否使用主光阴影,_MAIN_LIGHT_SHADOWS_CASCADE是是否主光阴影使用级联阴影。Additional Lights相关的关键字是控制附加灯相关的光照和阴影。Lightmap shadow mixing和shadow mask是Unity的混合光照相关。
    Unity defined keywords这一组顾名思义就是Unity定义的关键字了,比如lightmap开关和深度雾。
    此外还有GPU Instancing这组。

    引用的HLSL

    #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
    #include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitForwardPass.hlsl"
    
    • 1
    • 2

    这也是URP的惯例了,一个Pass自身的hlsl代码分为Input和Pass两部分。

    SimpleLitInput.hlsl

    在分析unlit shader时,我没有太关注unlit input,但是这次我打算详细的分析一下了。
    SimpleLit input hlsl包含了shader使用的uniform的定义,uniform可能是以CBuffer的形式定义,也可能是shader全局变量的形式。使用CBUffer形式的往往是为了兼容SRPBatcher或者Instancing,打包进CBuffer的uniform往往是要经常变化的,比如随材质变化或者随instance变化;而全局变量的uniform就是全局改变的。
    有几个内容需要关注:

    • SRP Batcher相关的CBuffer
    • Instancing相关的CBuffer
    • 什么是DOTS Instancing
      相关内容篇幅会比较大,因此会分为几篇,以SimpleLit Shader为例子说明。

    SimpleLitForwardPass.hlsl

    这个文件就是SimpleLit前向渲染pass的主要代码了。首先它一开始就引用了"Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"文件,这个文件非常重要,值得好好研读。这里面几乎包含了URP光照相关的全部shader库了,在相关shader引用到里面的内容时会做说明。回到SimpleLit,定义了如下的顶点属性:

    struct Attributes
    {
        float4 positionOS    : POSITION;
        float3 normalOS      : NORMAL;
        float4 tangentOS     : TANGENT;
        float2 texcoord      : TEXCOORD0;
        float2 lightmapUV    : TEXCOORD1;
        UNITY_VERTEX_INPUT_INSTANCE_ID
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    坐标,法线,切线,两套uv,基本全了,毕竟要算光照都不能少,除了没用顶点色。再看VS的输出以及FS的输入:

    struct Varyings
    {
        float2 uv                       : TEXCOORD0;
        DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 1);
    
        float3 posWS                    : TEXCOORD2;    // xyz: posWS
    
    #ifdef _NORMALMAP
        float4 normal                   : TEXCOORD3;    // xyz: normal, w: viewDir.x
        float4 tangent                  : TEXCOORD4;    // xyz: tangent, w: viewDir.y
        float4 bitangent                : TEXCOORD5;    // xyz: bitangent, w: viewDir.z
    #else
        float3  normal                  : TEXCOORD3;
        float3 viewDir                  : TEXCOORD4;
    #endif
    
        half4 fogFactorAndVertexLight   : TEXCOORD6; // x: fogFactor, yzw: vertex light
    
    #if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
        float4 shadowCoord              : TEXCOORD7;
    #endif
    
        float4 positionCS               : SV_POSITION;
        UNITY_VERTEX_INPUT_INSTANCE_ID
        UNITY_VERTEX_OUTPUT_STEREO
    };
    
    • 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

    VS输出啥其实是看FS的计算需要啥,首先uv, 世界坐标,法线,视线方向等计算Blinn-Phong模型光照所需的经典角色一个不少;如果启用了法线贴图,还需要输出切线坐标系;另外似乎还有所谓的vertex light;当然clip sapce postition是必须的。

    本篇总结

    由于篇幅所限,本篇只是起了个头,结果挖了好几个坑。至少我们现在对SimpeLit的功能有了大体的了解,光照部分应该是使用了Blinn-Phong模型,支持法线贴图。下篇将继续分析前向渲染路径的光照。之后会有几篇介绍SRP Batcher和Instancing。然后是Shadow Caster等等。基本上一个SimpleLit就可以挖出很多东西了。

  • 相关阅读:
    嵌入式学习笔记(55)LCD简介
    AJAX——HTTP协议
    Docker实战一
    KNN学习代码理解尝试
    头歌实训答案:招聘数据分析
    QML中使用正则表达式
    MyBatis的缓存
    linux安装java环境
    Qt跨线程使用moveToThread的注意事项(Cannot move to target thread )
    ubuntu-18.04 linux-QT版 演示sqlite3增删改查
  • 原文地址:https://blog.csdn.net/n5/article/details/128183653