Shaderlab Notizen 7-1 Standard Shader

一、Unity5中的Standard Shader

Unity5中重點推出了一套基于物理的著色(Physically Based Shading,PBS)的多功能Shader,叫做標準著色器(Standard Shader)。這套Shader的設(shè)計初衷是化繁為簡。想用這樣的一個多功能Shader,來代替之前多種多樣的Shader各司其職,對于不同的材質(zhì)效果,需要不同的Shader的局面。
Unity 5中目前有兩個標準著色器,一個名為Standard,我們稱它為標準著色器的標準版,另一個名為Standard(Specular Setup),我們稱它為標準著色器的高光版,它們共同組成了一個完整的PBS光照明模型,且非常易于使用。其實這兩個Shader基本差不多,只是有細微的屬性參數(shù)上的區(qū)別。標準版這邊的_Metallic(金屬性)、_MetallicGlossMap(金屬光澤貼圖),被高光版的_SpecColor(高光顏色)、_SpecGlossMap(高光顏色法線貼圖)所代替。
標準著色器主要是針對硬質(zhì)表面(也就是建筑材質(zhì))而設(shè)計的,可以處理大多數(shù)現(xiàn)實世界的材質(zhì),例如石頭、陶瓷、銅器、銀器或橡膠等。同時,它也可以非常出色地處理一些非硬質(zhì)表面的材質(zhì),例如皮膚、頭發(fā)或布料等。

Unity5 Standard Shader的演示Demo
http://www.iqiyi.com/w_19rquxac31.html

1.1 Physically Based Shading(基于物理的著色)
基于物理的著色(Physically Based Shading,簡稱PBS)就是以某種方式模擬現(xiàn)實中材質(zhì)和光照的相互作用的一種著色方法。這種方法在需要光照和材質(zhì)更加直觀和逼真地協(xié)同工作的場合下優(yōu)勢非常明顯?;谖锢淼闹M了光線在現(xiàn)實中的行為,實現(xiàn)了在不同的光照條件下的逼真效果。為實現(xiàn)這種效果需要遵循各種物理原理,包括能量守恒(也就是物體反射出去的光量不可能超過所接收的光量),F(xiàn)resnel反射(所有表面反射在掠射角(grazing angles)處更加強烈),以及物體表面是如何自我遮擋等原理。

ps:另一篇筆記

1.2 如何使用標準著色器
可以在Unity5中任意材質(zhì)的Shader選項中的最前面看到兩個Standard Shader字樣的選項。其中第一個是普通版,第二個帶Specularsetup是高光版。

標準著色器標準版材質(zhì)界面:

Paste_Image.png

標準著色器的高光版材質(zhì)界面:

Paste_Image.png

Unity官方文檔:
http://docs.unity3d.com/Manual/shader-StandardShader.html

以及這里Unity5 Standard Shader的官方文檔論壇翻譯版:
http://forum.china.unity3d.com/thread-897-1-1.html

1.3 標準著色器的組成

Unity5中標準著色器的組成概括如下:

  • 兩個Shader源文件
  • 七個CG頭文件
  • 一個腳本文件(用于自定義材質(zhì)編輯器UI)

1.3.1 兩個Shader源文件
Stardard.shader著色器源文件 - 標準著色器的標準版
StardardSpecular.shader著色器源文件 - 標準著色器的高光版

1.3.2 七個CG頭文件

  • UnityStandardBRDF.cginc頭文件-用于存放標準著色器處理BRDF材質(zhì)屬性相關(guān)的函數(shù)與宏
  • UnityStandardConfig.cginc頭文件-用于存放標準著色器配置相關(guān)的代碼(其實里面就幾個宏)
  • UnityStandardCore.cginc頭文件-用于存放標準著色器的主要代碼(如頂點著色函數(shù)、片段著色函數(shù)等相關(guān)函數(shù))
  • UnityStandardInput.cginc頭文件-用于存放標準著色器輸入結(jié)構(gòu)相關(guān)的工具函數(shù)與宏
  • UnityStandardMeta.cginc頭文件-用于存放標準著色器meta通道中會用到的工具函數(shù)與宏
  • UnityStandardShadow.cginc頭文件-用于存放標準著色器陰影貼圖采樣相關(guān)的工具函數(shù)與宏
  • UnityStandardUtils.cginc頭文件-用于存放標準著色器共用的一些工具函數(shù)

1.3.3 一個腳本文件
StandardShaderGUI.cs腳本文件——定義了特定的自定義編輯器UI界面
標準著色器對應(yīng)材質(zhì)的編輯器外觀不同于一般的Shader,就是因為在Shader末尾書寫了如下的代碼:
//使用特定的自定義編輯器UI界面
CustomEditor "StandardShaderGUI"

二、Unity5標準著色器源代碼剖析:架構(gòu)分析

源碼如下:

//-----------------------------------------------【Shader說明】---------------------------
//       Unity5.2.1 Built-in Standard Shader
//--------------------------------------------------------------------------------------------

Shader "Standard"
{
    //------------------------------------【屬性值】------------------------------------
    Properties
    {
        //主顏色
        _Color("Color", Color) = (1,1,1,1)
        //主紋理
        _MainTex("Albedo", 2D) = "white" {}

        //Alpha剔除值
        _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5
        //平滑、光澤度
        _Glossiness("Smoothness", Range(0.0, 1.0)) = 0.5

        //金屬性
        [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0
        //金屬光澤紋理圖
        _MetallicGlossMap("Metallic", 2D) = "white" {}

        //凹凸的尺度
        _BumpScale("Scale", Float) = 1.0
        //法線貼圖
        _BumpMap("Normal Map", 2D) = "bump" {}

        //高度縮放尺度
        _Parallax ("Height Scale", Range (0.005, 0.08)) = 0.02
        //高度紋理圖
        _ParallaxMap ("Height Map", 2D) = "black" {}

        //遮擋強度
        _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0
        //遮擋紋理圖
        _OcclusionMap("Occlusion", 2D) = "white" {}

        //自發(fā)光顏色
        _EmissionColor("Color", Color) = (0,0,0)
        //自發(fā)光紋理圖
        _EmissionMap("Emission", 2D) = "white" {}

        //細節(jié)掩膜圖
        _DetailMask("Detail Mask", 2D) = "white" {}

        //細節(jié)紋理圖
        _DetailAlbedoMap("Detail Albedo x2", 2D) = "grey" {}
        //細節(jié)法線貼圖尺度
        _DetailNormalMapScale("Scale", Float) = 1.0
        //細節(jié)法線貼圖
        _DetailNormalMap("Normal Map", 2D) = "bump" {}

        //二級紋理的UV設(shè)置
        [Enum(UV0,0,UV1,1)] _UVSec ("UV Set for secondary textures", Float) = 0

        //混合狀態(tài)的定義
        [HideInInspector] _Mode ("__mode", Float) = 0.0
        [HideInInspector] _SrcBlend ("__src", Float) = 1.0
        [HideInInspector] _DstBlend ("__dst", Float) = 0.0
        [HideInInspector] _ZWrite ("__zw", Float) = 1.0
    }

    //===========開始CG著色器語言編寫模塊===========
    CGINCLUDE
        //BRDF相關(guān)的一個宏
        #define UNITY_SETUP_BRDF_INPUT MetallicSetup
    //===========結(jié)束CG著色器語言編寫模塊===========
    ENDCG

    //------------------------------------【子著色器1】------------------------------------
    // 此子著色器用于Shader Model 3.0
    //----------------------------------------------------------------------------------------
    SubShader
    {
        //渲染類型設(shè)置:不透明
        Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }

        //細節(jié)層次設(shè)為:300
        LOD 300

        //--------------------------------通道1-------------------------------
        // 正向基礎(chǔ)渲染通道(Base forward pass)
        // 處理方向光,自發(fā)光,光照貼圖等 ...
        Pass
        {
            //設(shè)置通道名稱
            Name "FORWARD"

            //于通道標簽中設(shè)置光照模型為ForwardBase,正向渲染基礎(chǔ)通道
            Tags { "LightMode" = "ForwardBase" }

            //混合操作:源混合乘以目標混合
            Blend [_SrcBlend] [_DstBlend]
            // 根據(jù)_ZWrite參數(shù),設(shè)置深度寫入模式開關(guān)與否
            ZWrite [_ZWrite]

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM

            //著色器編譯目標:Model 3.0
            #pragma target 3.0

            //編譯指令:不使用GLES渲染器編譯
            #pragma exclude_renderers gles

            // ---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            //--------著色器編譯多樣化快捷指令------------
            //編譯指令:編譯正向渲染基礎(chǔ)通道(用于正向渲染中,應(yīng)用環(huán)境光照、主方向光照和頂點/球面調(diào)和光照)所需的所有變體。
            //這些變體用于處理不同的光照貼圖類型、主要方向光源的陰影選項的開關(guān)與否
            #pragma multi_compile_fwdbase
            //編譯指令:編譯幾個不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/)
            #pragma multi_compile_fog

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertForwardBase
            #pragma fragment fragForwardBase

            //包含輔助CG頭文件
            #include "UnityStandardCore.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }
        //--------------------------------通道2-------------------------------
        // 正向附加渲染通道(Additive forward pass)
        // 以每個光照一個通道的方式應(yīng)用附加的逐像素光照
        Pass
        {
            //設(shè)置通道名稱
            Name "FORWARD_DELTA"

            //于通道標簽中設(shè)置光照模型為ForwardAdd,正向渲染附加通道
            Tags { "LightMode" = "ForwardAdd" }

            //混合操作:源混合乘以1
            Blend [_SrcBlend] One

            //附加通道中的霧效應(yīng)該為黑色
            Fog { Color (0,0,0,0) }

            //關(guān)閉深度寫入模式
            ZWrite Off
            //設(shè)置深度測試模式:小于等于
            ZTest LEqual

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM

            //著色器編譯目標:Model 3.0
            #pragma target 3.0
            //編譯指令:不使用GLES渲染器編譯
            #pragma exclude_renderers gles

            // ---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            //--------使用Unity內(nèi)置的著色器編譯多樣化快捷指令------------
            //編譯指令:編譯正向渲染基礎(chǔ)通道所需的所有變體,但同時為上述通道的處理賦予了光照實時陰影的能力。
            #pragma multi_compile_fwdadd_fullshadows
            //編譯指令:編譯幾個不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/)
            #pragma multi_compile_fog

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertForwardAdd
            #pragma fragment fragForwardAdd

            //包含輔助CG頭文件
            #include "UnityStandardCore.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }

        // --------------------------------通道3-------------------------------
        //  陰影渲染通道(Shadow Caster pass)
        //  將將物體的深度渲染到陰影貼圖或深度紋理中
        Pass
        {
            //設(shè)置通道名稱
            Name "ShadowCaster"
            //于通道標簽中設(shè)置光照模型為ShadowCaster。
            //此光照模型代表著將物體的深度渲染到陰影貼圖或深度紋理。
            Tags { "LightMode" = "ShadowCaster" }

            //開啟深入寫入模式
            ZWrite On
            //設(shè)置深度測試模式:小于等于
            ZTest LEqual

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM

            //著色器編譯目標:Model 3.0
            #pragma target 3.0

            //編譯指令:不使用GLES渲染器編譯
            #pragma exclude_renderers gles

            // ---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON

            //--------著色器編譯多樣化快捷指令------------
            //進行陰影投射相關(guān)的多著色器變體的編譯
            #pragma multi_compile_shadowcaster

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            //包含輔助CG頭文件
            #include "UnityStandardShadow.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }

        // --------------------------------通道4-------------------------------
        //  延遲渲染通道(Deferred Render Pass)
        Pass
        {
            //設(shè)置通道名稱
            Name "DEFERRED"
            //于通道標簽中設(shè)置光照模型為Deferred,延遲渲染通道
            Tags { "LightMode" = "Deferred" }

            CGPROGRAM
            #pragma target 3.0
            // TEMPORARY: GLES2.0 temporarily disabled to prevent errors spam on devices without textureCubeLodEXT
            #pragma exclude_renderers nomrt gles

            //---------編譯指令:著色器編譯多樣化(shader_feature)--------
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            #pragma shader_feature _PARALLAXMAP

            //---------編譯指令:著色器編譯多樣化(multi_compile)--------
            #pragma multi_compile ___ UNITY_HDR_ON
            #pragma multi_compile LIGHTMAP_OFF LIGHTMAP_ON
            #pragma multi_compile DIRLIGHTMAP_OFF DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE
            #pragma multi_compile DYNAMICLIGHTMAP_OFF DYNAMICLIGHTMAP_ON

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertDeferred
            #pragma fragment fragDeferred

            //包含輔助CG頭文件
            #include "UnityStandardCore.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }

        // --------------------------------通道5-------------------------------
        //元通道(Meta Pass)
        //為全局光照(GI),光照貼圖等技術(shù)提取相關(guān)參數(shù),如(emission, albedo等參數(shù)值)
        //此通道并不在常規(guī)的渲染過程中使用
        Pass
        {
            //設(shè)置通道名稱
            Name "META"

            //于通道標簽中設(shè)置光照模型為Meta
            //(截止2015年10月22日,Unity 5.2.1的官方文檔中并沒有收錄此光照模型,應(yīng)該是Unity官方的疏漏)
            Tags { "LightMode"="Meta" }
            //關(guān)閉剔除操作
            Cull Off

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vert_meta
            #pragma fragment frag_meta

            //---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            //包含輔助CG頭文件
            #include "UnityStandardMeta.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }
    }

    //------------------------------------【子著色器2】-----------------------------------
    // 此子著色器用于Shader Model 2.0
    //----------------------------------------------------------------------------------------
    SubShader
    {
        //渲染類型設(shè)置:不透明
        Tags { "RenderType"="Opaque" "PerformanceChecks"="False" }
        //細節(jié)層次設(shè)為:150
        LOD 150

        //--------------------------------通道1-------------------------------
        // 正向基礎(chǔ)渲染通道(Base forward pass)
        // 處理方向光,自發(fā)光,光照貼圖等 ...
        Pass
        {
            //設(shè)置通道名稱
            Name "FORWARD"
            //于通道標簽中設(shè)置光照模型為ForwardBase,正向渲染基礎(chǔ)通道
            Tags { "LightMode" = "ForwardBase" }
            //混合操作:源混合乘以目標混合,即結(jié)果為兩者的混合
            Blend [_SrcBlend] [_DstBlend]
            // 根據(jù)_ZWrite參數(shù),設(shè)置深度寫入模式開關(guān)與否
            ZWrite [_ZWrite]

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM
            //著色器編譯目標:Model 2.0
            #pragma target 2.0

            // ---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP

            //跳過如下變體的編譯,簡化編譯過程
            #pragma skip_variants SHADOWS_SOFT DIRLIGHTMAP_COMBINED DIRLIGHTMAP_SEPARATE

            //--------著色器編譯多樣化快捷指令------------
            #pragma multi_compile_fwdbase
            #pragma multi_compile_fog

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertForwardBase
            #pragma fragment fragForwardBase

            //包含輔助CG頭文件
            #include "UnityStandardCore.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }

        //--------------------------------通道2-------------------------------
        // 正向附加渲染通道(Additive forward pass)
        // 以每個光照一個通道的方式應(yīng)用附加的逐像素光照
        Pass
        {
            //設(shè)置通道名稱
            Name "FORWARD_DELTA"

            //于通道標簽中設(shè)置光照模型為ForwardAdd,正向渲染附加通道
            Tags { "LightMode" = "ForwardAdd" }

            //混合操作:源混合乘以1
            Blend [_SrcBlend] One

            //附加通道中的霧效應(yīng)該為黑色
            Fog { Color (0,0,0,0) }

            //關(guān)閉深度寫入模式
            ZWrite Off

            //設(shè)置深度測試模式:小于等于
            ZTest LEqual

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM
            //著色器編譯目標:Model 2.0
            #pragma target 2.0

            // ---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _NORMALMAP
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            //跳過一些變體的編譯
            // SM2.0: NOT SUPPORTED shader_feature _PARALLAXMAP
            #pragma skip_variants SHADOWS_SOFT

            //--------使用Unity內(nèi)置的著色器編譯多樣化快捷指令------------
            //編譯指令:編譯正向渲染基礎(chǔ)通道所需的所有變體,但同時為上述通道的處理賦予了光照實時陰影的能力。
            #pragma multi_compile_fwdadd_fullshadows
            //編譯指令:編譯幾個不同變種來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù)/)
            #pragma multi_compile_fog

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertForwardAdd
            #pragma fragment fragForwardAdd

            //包含輔助CG頭文件
            #include "UnityStandardCore.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }

        // --------------------------------通道3-------------------------------
        //  陰影渲染通道(Shadow Caster pass)
        //  將將物體的深度渲染到陰影貼圖或深度紋理中
        Pass
        {
            //設(shè)置通道名稱
            Name "ShadowCaster"

            //于通道標簽中設(shè)置光照模型為ShadowCaster。
            //此光照模型代表著將物體的深度渲染到陰影貼圖或深度紋理。
            Tags { "LightMode" = "ShadowCaster" }

            //開啟深入寫入模式
            ZWrite On

            //設(shè)置深度測試模式:小于等于
            ZTest LEqual

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM
            //著色器編譯目標:Model 2.0
            #pragma target 2.0

            //---------編譯指令:著色器編譯多樣化(shader_feature)--------
            #pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON

            //編譯指令:跳過某些變體的編譯
            #pragma skip_variants SHADOWS_SOFT

            //快捷編譯指令:進行陰影投射相關(guān)的多著色器變體的編譯
            #pragma multi_compile_shadowcaster

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vertShadowCaster
            #pragma fragment fragShadowCaster

            //包含輔助CG頭文件
            #include "UnityStandardShadow.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }

        // --------------------------------通道4-------------------------------
        //元通道(Meta Pass)
        //為全局光照(GI),光照貼圖等技術(shù)提取相關(guān)參數(shù),如(emission, albedo等參數(shù)值)
        //此通道并不在常規(guī)的渲染過程中使用
        Pass
        {
            //設(shè)置通道名稱
            Name "META"

            //于通道標簽中設(shè)置光照模型為Meta
            //(截止2015年10月22日,Unity 5.2.1的官方文檔中并沒有收錄此光照模型,應(yīng)該是Unity官方的疏漏)
            Tags { "LightMode"="Meta" }
            //關(guān)閉剔除操作
            Cull Off

            //===========開啟CG著色器語言編寫模塊===========
            CGPROGRAM

            //編譯指令:告知編譯器頂點和片段著色函數(shù)的名稱
            #pragma vertex vert_meta
            #pragma fragment frag_meta

            //---------編譯指令:著色器編譯多樣化--------
            #pragma shader_feature _EMISSION
            #pragma shader_feature _METALLICGLOSSMAP
            #pragma shader_feature ___ _DETAIL_MULX2

            //包含輔助CG頭文件
            #include "UnityStandardMeta.cginc"

            //===========結(jié)束CG著色器語言編寫模塊===========
            ENDCG
        }
    }

    //回退Shader為頂點光照Shader
    FallBack "VertexLit"
    //使用特定的自定義編輯器UI界面
    CustomEditor "StandardShaderGUI"
}

標準著色器由兩個SubShader組成。第一個SubShader用于處理Shader Model 3.0,有5個通道,第二個SubShader用于處理Shader Model 2.0, 有4個通道
詳細的架構(gòu)如下圖:

Paste_Image.png

三、Deferred Render(延遲渲染)

Deferred Render和Deferred Shading有一點細微的差別。

  • Deferred Shading:將所有的Shading全部轉(zhuǎn)到Deferred階段進行。
  • Deferred Render:只是有選擇地將Lighting轉(zhuǎn)到Deferred階段進行。

Unity中默認使用的是Deferred Shading。
而延遲渲染,一言以蔽之,就是將光照/渲染的計算延遲到第二步進行,避免多次渲染同一個像素,從而減少多余的計算操作,以提高渲染效率的一種先進的渲染方式。

延遲渲染最大的優(yōu)勢是可以實現(xiàn)同屏中數(shù)量眾多的動態(tài)光源(十幾到幾十個),這在傳統(tǒng)的渲染管線中是很難實現(xiàn)的。

更多延遲渲染的細節(jié),這邊不細說,只是提供一些鏈接,以作進一步了解延遲渲染的導(dǎo)論之用:

四、著色器編譯多樣化

Unity5中使用了一種被稱為著色器編譯多樣化(Multiple shader program variants)的新技術(shù),常被稱為“megashaders”或“uber shaders”,并通過為每種情況提供不同的預(yù)處理指令來讓著色器代碼多次被編譯來實現(xiàn)。
在Unity中,這可以通過#pragmamulti_compile或者#pragma shader_feature指令來在著色器代碼段中實現(xiàn)。這種做法對表面著色器也可行。
在運行時,相應(yīng)的著色器變體是從材質(zhì)的關(guān)鍵詞中取得的(Material.EnableKeyword和 DisableKeyword),或者全局著色器關(guān)鍵詞(Shader.EnableKeyword和 DisableKeyword)。

4.1 multi_compile用法簡析
若我們定義如下指令:

#pragma multi_compile FANCY_STUFF_OFFFANCY_STUFF_ON

也就表示定義了兩個變體:FANCY_STUFF_OFF和FANCY_STUFF_ON。在運行時,其中的一個將被激活,根據(jù)材質(zhì)或者全局著色器關(guān)鍵詞(#ifdef FANCY_STUFF_OFF之類的宏命令也可以)來確定激活哪個。若兩個關(guān)鍵詞都沒有啟用,那么將默認使用前一個選項,也就是關(guān)閉(OFF)的選項FANCY_STUFF_OFF。
ps:也可以存在超過兩個關(guān)鍵字的multi_compile編譯選項
舉個栗子:如下代碼將產(chǎn)生4種著色器的變體:

#pragma multi_compile SIMPLE_SHADINGBETTER_SHADING GOOD_SHADING BEST_SHADING

當#pragma multi_compile中存在所有名字都是下劃線的一個指定段時,就表示需在沒有預(yù)處理宏的情況下產(chǎn)生一個空的著色器變種。這種做法在著色器編寫中比較常見,因為這樣可以在不影響使用的情況下,避免使用兩個關(guān)鍵詞,這樣就節(jié)省了一個變量個數(shù)的占用(下面會提到,Unity中關(guān)鍵詞個數(shù)是有129個的數(shù)量限制的)。
再舉個栗子:下面的指令將產(chǎn)生兩個著色器變體;第一個沒有定義,第二個定義為FOO_ON:

#pragma multi_compile __ FOO_ON

這樣就省去了一個本來需要定義出來的 FOO_OFF(FOO_OFF沒有定義,自然也不能使用),節(jié)省了一個關(guān)鍵詞個數(shù)的占用。
若Shader中有如上定義,則可以使用#ifdef來進行判斷:

#ifdef FOO_ON
//代碼段1
#endif

根據(jù)上面已經(jīng)定義過的FOO_ON,此#ifdef判斷的結(jié)果為真,代碼段1部分的代碼就會被執(zhí)行到。反之,若#pragma multi_compile __FOO_ON一句代碼沒有交代出來,那么代碼段1部分的代碼就不會被執(zhí)行。

4.2 shader_feature和multi_compile之間的區(qū)別

//#pragma shader_feature 和#pragma multi_compile非常相似,
//唯一的區(qū)別在于采用了#pragmashader_feature語義的shader,
//在遇到不被使用的變體的時候,就不會將其編譯到游戲中。
//所以,shader_feature中使得所有的設(shè)置到材質(zhì)中的關(guān)鍵詞都是有效的,
//而multi_compile指令將從全局代碼里設(shè)置關(guān)鍵詞。

ps:shader_feature還有一個僅僅含有一個關(guān)鍵字的快捷表達方式
舉個栗子:

#pragma shader_feature FANCY_STUFF

此為#pragma shader_feature _ FANCY_STUFF的一個簡寫形式,其擴展出了兩個著色器變體,第一種變體自然為不定此FANCY_STUFF變量(那么若在稍后的Shader代碼中進行#ifdef FANCY_STUFF的判斷,則結(jié)果為假),第二種變體為定義此FANCY_STUFF變量(此情況下#ifdef FANCY_STUFF的判斷結(jié)果為真)。

4.3 多個multi_compile連用會造成指數(shù)級增長
可以提供多個multi_compile流水線,然后著色器的結(jié)果可以被編譯為幾個流水線的排列組合
舉個栗子:

#pragma multi_compile A B C
#pragma multi_compile D E

第一行中有3種選項,第二行中有兩種選項,那么進行排列組合,總共就會有六種選項(A+D, B+D, C+D, A+E, B+E, C+E)。
容易想到,一般每以個multi_compile流水線,都控制著著色器中某一單一的特性。請注意,著色器總量的增長速度是非??斓?。
比如,10條包含兩個特性的multi_compil指令,會得到2的10次方,也就是1024種不同的著色器變體。

4.4 關(guān)于Unity中的關(guān)鍵詞限制Keyword limit
Unity中將關(guān)鍵詞的數(shù)量限制在了128個之內(nèi)(著色變量算作關(guān)鍵字),且其中有一些已經(jīng)被Unity內(nèi)置使用了,因此真正可以自定義使用關(guān)鍵詞的數(shù)量是小于128個的。同時,關(guān)鍵詞是在單個Unity項目中全局使用并計數(shù)的,所以在同一項目中存在的但沒用到Shader也要考慮在內(nèi),不要合起來在數(shù)量上超出Unity的關(guān)鍵詞數(shù)量限制。

4.5 Unity內(nèi)置的快捷multi_compile指令
如下有Unity內(nèi)置的幾個著色器變體的快捷多編譯指令,他們大多是應(yīng)對Unity中不同的光線,陰影和光照貼圖類型。詳情見rendering pipeline 。

  • multi_compile_fwdbase - 此指令表示,編譯正向基礎(chǔ)渲染通道(用于正向渲染中,應(yīng)用環(huán)境光照、主方向光照和頂點/球面調(diào)和光照(Spherical Harmonic Lighting))所需的所有變體。這些變體用于處理不同的光照貼圖類型、主要方向光源的陰影選項的開關(guān)與否。

  • multi_compile_fwdadd - 此指令表示, 編譯正向附加渲染通道(用于正向渲染中;以每個光照一個通道的方式應(yīng)用附加的逐像素光照)所需的所有變體。這些變體用于處理光源的類型(方向光源、聚光燈或者點光源),且這些變種都包含紋理cookie。

  • multi_compile_fwdadd_fullshadows – 此指令和上面的正向渲染附加通道基本一致,但同時為上述通道的處理賦予了光照實時陰影的能力。

  • multi_compile_fog - 此指令表示,編譯出幾個不同的Shader變體來處理不同類型的霧效(關(guān)閉/線性/指數(shù)/二階指數(shù))(off/linear/exp/exp2).

4.6 使用指令跳過某些變體的編譯

可以使用#pragmaskip_variants語句跳過其中一些的編譯。
舉個栗子:

#pragma multi_compile_fwdadd
// 將跳過所有使用"POINT"或 "POINT_COOKIE"的變體
#pragma skip_variants POINT POINT_COOKIE
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容