美文网首页
Standard.shader学习笔记

Standard.shader学习笔记

作者: waempty | 来源:发表于2019-11-06 20:17 被阅读0次

    最近因工作需要研究了Unity自带的Standard.shader。标注一下,整个Unity内嵌的shader及库文件(cginc文件)都可以在官网下到。这里整理下之前没学到的知识,方便以后查看。

    1.shader的构成

    整体的Unity Shader结构如下:

    Shader "ShaderName"
    {
        Properties{}
        SubShader{
            Tags {}
            Pass
            {
                Tags { "LightMode" = "ForwardBase"}
                CGPROGRAM
                #pragma shader_feature _NORMALMAP
                vertOutput vert()
                color frag()
                ENDCG
          }
          Pass ....
      }
      SubShader...
    }
    

    其中一个Shader文件可能包含多个SubShader,这是根据硬件支持适配用的。实际执行时,只执行一个SubShader。
    但是一个SubShader中的多个Pass是会依次执行的。

    2.LightMode

    第一部分中Pass块里Tags的LightMode是用来申明当前Pass渲染在光照模型中充当的角色。通常有一下几种:
    1.Always:肯定会被执行,但是不渲染任何光源。
    2.ForwardBase:渲染环境光(ambient light),主光源,顶点光源及Spherical Harmonics (SH),
    3.ForwardAdd: 按照逐像素渲染light,每个光执行一次该Pass
    4.Deferred:延迟渲染,用到了g-buffer
    5.ShadowCaster:将深度或者阴影信息渲染到shadowmap或者深度纹理中

    3.前向渲染(Forward Rendering)

    前向渲染中,最亮的光源会按照逐像素渲染,至多有4个点光源按照逐顶点渲染,剩下其他的按照SH方式进行渲染(渲染效果 逐像素>逐顶点>SH,消耗亦然)。有以下几个原则决定光源按照何种方式渲染:
    1.Light设置为Not Important肯定会按照逐顶点或者SH渲染
    2 . 最亮的Light肯定是按照逐像素渲染的
    3 . Light设置为Important按照逐像素渲染
    4 .Quanlity Setting中的Pixel Light Count可以规定逐像素光源的上限
    SH的优点及缺点:
    优点:性能低消耗,没有任何GPU消耗
    缺点:由于是在Vertex上进行计算,所以无法应用LIght Cookies和Normal Map。不合适应用在Surface很近的场景(显示会不正常)
    一般来说,SH适合用在离光源较远的小物件上。

    4.shader中的宏控制

    可以通过#pragma multi_compile或者#progma shader_feature来声明宏开关。
    使用类似于

    #pragma multi_compile FANCY_STUFF_OFF FANCY_STUFF_ON
    

    上面的语句会产生两个shader变体,一个定义了FANCY_STUFF_OFF,另一个定义了FANCY_STUFF_ON。只实际运行的时候,Unity会根据材质或keywords激活并使用其中的一个(如果两个keyword都没有Enable,则默认会使用第一个,即FACY_STUFF_OFF)。另外可以通过”__"的方式定义无宏开关的版本,例如:

    #pragma multi_compile __ FOO_ON
    

    执行上,shader_feature和multi_compile会有不同,具体表现在当宏是通过shader_feature定义的时候,如果宏没有被使用过,那么这个shader的变体不会包含在最后的build中。所以一般来说,通过Material设置的宏开关通过shader_feature定义,而通过Code控制的宏开关使用multi_compile来定义
    有几点需要注意的地方:
    1 .当有多行定义多个宏开关的时候,会产生爆发式数量的shader变体,例如:

    #pragma multi_compile A B C
    #pragma multi_compile D E
    

    上面的语句总共会产生6个shader变体(A+D, B+D,C+D,A+E,B+E,C+E)
    2 .宏开关的数量Unity是有限制的,其中全局256个,local 64个。可以使用shader_feature_loca及multi_compile_local定义local keywords。
    3.常见的Unity自带的宏定义
    multi_compile_fwdbase:编译所有会在PassType.ForwardBase
    中用到的变量。
    multi_compile_fwdadd:编译所有会在 PassType.ForwardAdd
    中使用的变量。
    #pragma skip_variants:用来跳过编译一些已知不会用到的变量,例如:

    #pragma multi_compile_fwdadd
    #pragma skip_variants POINT POINT_COOKIE
    

    5.StandardShaderGUI

    可以在Unity Shader的末尾声明以下语句来自定义Shader在Inspector上的显示

    CustomEditor "BumpSpecularGUI"
    

    BumpSpecularGUI继承自ShaderGUI,下面列举下自定义类的声明及一些关键函数

    namespace UnityEditor
    {
        internal class BumpSpecularGUI : ShaderGUI
        {
            public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] props)
            {
                //这里执行自定义Inspector的逻辑
                //另外一些材质宏开关也可以在这里控制,例如targetMat.EnableKeyword("REDIFY_ON");
            }
    
            public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader)
            {
                  // 这个函数在赋予材质新的Shader时调用
                  //重写这个函数时,务必调用基类实现
                  base.AssignNewShaderToMaterial(material, oldShader, newShader);
            }
        }
    }

    相关文章

      网友评论

          本文标题:Standard.shader学习笔记

          本文链接:https://www.haomeiwen.com/subject/gavebctx.html