1. 程式人生 > >Unity ShaderLab開發實戰(三)Pass的通用指令開關

Unity ShaderLab開發實戰(三)Pass的通用指令開關

1. LOD:

       通過給SubShader設定一個整型的Level of DetaiI,即LOD數值,可以在執行時根據硬體裝置能力來決定是否使用此Shader,以及使用哪一個層級的SubShader。

用法eg:

    SubShader

    {

        LOD 600

        Pass { }

    }

        可以針對某一特定的Shader設定最大LOD,也可以在執行時設定一個全域性的LOD。

eg1:

public Shader m_Shader;

void Awake()

{

    m_Shader.maximumLOD = 800;//改變指定的

    Shader.globalMaximumLOD = 600;// 改變全域性的

       最終結果,如果上述值為全域性設為600,特定shader的設為800時,那麼Unity所有的Shader(除設定了LOD為800的shader)中LOD為600的SubShader,特定shader的設為800時,選用了LOD為800的SubShader。

測試程式碼:

Shader "Tut/Shader/Common/_SetShader" {
    Properties {
        _Color ("Main Color", Color) = (1,1,1,0.5)
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }
     SubShader {
        LOD 800
        Pass {
            Material { Diffuse (0,0,1,1)}
            Lighting On
            SetTexture [_MainTex] {Combine texture * primary double}
        }
    }
    SubShader {
        LOD 600
        Pass {
            Material { Diffuse (0,1,0,1)}
            Lighting On
            SetTexture [_MainTex] {Combine texture * primary double}
        }
    }
     SubShader {
        LOD 500
        Pass {
            Material {Diffuse (1,1,0,1)}
            Lighting On
        }
    }
    SubShader {
        LOD 400
        Pass {
           color(1,0,0,1)
        }
    }
}

using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class _SetGlobalLOD : MonoBehaviour {
    public Shader myShader;
    public GUISkin skin;
    public Rect rt;
    public Rect r1;
    public Rect r2;
    string tipStr;
    private float val=1; 
    void Update () {
        Shader.globalMaximumLOD = (int)val * 100;
        myShader.maximumLOD = 800;

    }
    void OnGUI()
    {
        GUI.skin = skin;
        val =(int) GUI.HorizontalSlider(rt, val, 1, 8);
        GUI.Label(r1, "Current Global LOD is: " + val * 100);
        GUI.Label(r2, "Current myShader LOD is: " + 800);
    }
}

測試結果如下圖,想要完整程式碼工程的留言吧。

2.渲染佇列

       渲染佇列(renderQueue)決定了Unity渲染場景物體的先後順序。

       ZTest可以取的值有Greater/GEqual/Less/LEqual/Equal/NotEqual/Always/Never/Off,預設值為LEqual,通過比較深度來更改顏色快取的值。eg:預設值LEqual的情況下,如果將要繪製的新畫素的z值小於等於深度快取中的值,則將用新畫素的顏色值更新深度快取中對應畫素的顏色值。

       renderQueue會改變物體被渲染的先後順序,但不會改變物體的空間位置,對於ZTest為LEqual的,即使改變了renderQueue,作用也無法體現在渲染輸出上;但是對於ZTest為Always就會影響最好的渲染輸出。

       unity內建的渲染佇列:有5個預設適合於Queue的值,它們是Background、Geometry、AlphaTest、Transparent和
overlay,分別對應數值1000、2000、2450、3000和4000。

3.透明

       Alpha檢測用於在fragment函式完成最終的計算之後,在即將寫入幀之前通過和—個固定的數值相比較,來決定當前fragment函式的計算結果要不要寫入幀中。AlphaTest的比較條件有Greater、GEqual、Equal、NotEqual、Less、LEqual、Always和Never這8種情況,具體比較值可以執行時確定。

eg:

Properties {
        _DstTex ("Dst Tex", 2D) = "white" {}
        _SrcTex ("Src Tex", 2D) = "white" {}
        _CutOff("_Cut Off",float)=0.5
    }

SubShader {
        Pass{
            AlphaTest Off
            SetTexture[_DstTex]  { 
                combine texture alpha 
            }
        }
        Pass{
            Blend SrcAlpha OneMinusSrcAlpha
            AlphaTest GEqual [_CutOff]
            SetTexture [_SrcTex] {
                combine texture alpha 
            }
        }
    } 

4.混合

       Alpha Blend

 用法eg:

Properties {
    _DstTex ("DstTex", 2D) ="white"{}
    _SrcTex ("SrcTex", 2D) ="white"{}
    }
    SubShader {
    Pass{
        SetTexture[_DstTex] {combine texture}
    }
    Pass {
        BlendOp Sub//Min,Max,RevSub
        Blend One One
        SetTexture [_SrcTex] { combine texture}
    }
    Pass{//output Alpha to RGB
    Blend  DstAlpha zero
    color(1,1,1,1)
    }
    }

5.通道遮罩

       ColorMask,eg: ColorMask RG 渲染輸出只寫入RG通道,沒有B通道和A通道。

使用:可以單獨在一個Pass裡產生遮罩,然後在後續Pass裡使用,防止穿透

Properties {
    _Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
    Tags {"RenderType"="Opaque" "Queue"="Transparent"}
    Pass {
        ZWrite On
        ColorMask 0
    }
    Pass {
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha
        ColorMask RGB
        Material {
            Diffuse [_Color]
        }
        Lighting On
        SetTexture[_]{
        Combine primary double
        }
    }
}

6.ZTest

       之前講過,渲染路徑:VertexLit、Forward、Deferred。

       預設情況下,只有在渲染路徑是Deferred時,輸出的_CameraDepthTexture才會有深度值。如果Z深度緩衝在當前的渲染路徑下,在當前的硬體裝置中不能直接取得,那麼Unity會通過Shader Replacement的方法,單獨在一個Pass中產生,(所謂的替代渲染),這時會用到RenderType。儘量給RenderType賦值。

       Deferred渲染路徑下,首先會渲染在Deferred模型下可渲染的材質,然後才是Forward或VertexLit渲染路徑。

7.可以干預正常的ZTest,用Offset,只是修正,不是改緩衝中的值。

8.面剔除。可以實現描邊,效果圖如下。

      左邊的Cull Front,中間的Cull Back,右邊的有兩個Pass,第一個Pass用Cull Front,然後將球沿法線往外擠一些,第二個Pass用Cull Back,正常渲染,兩個結合就有描邊啦。精英怪就是這麼實現的哦。

程式碼:

SubShader {
        Cull Front
        pass{
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"
        struct v2f{
            float4 pos:SV_POSITION;
        };
        v2f vert(appdata_base v)
        {
            v2f o;
            o.pos=v.vertex;
            o.pos.xyz+=v.normal*0.03;
            o.pos=mul(UNITY_MATRIX_MVP,o.pos);
            return o;
        }
        float4 frag(v2f i):COLOR
        {
            return (1,0,0,1);
        }
        ENDCG
        }
        pass{
            Cull Back
            Lighting On
            Material{ Diffuse(1,1,1,1) }
        }
    } 

9.抓屏

Properties {
        _MainTex ("Base (RGB)", 2D) = "white" { }
    }
    SubShader {
    GrabPass {
        "_MyGrab"    
        }
    pass{
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag
        #include "UnityCG.cginc"

        sampler2D _MyGrab;
        sampler2D _MainTex;
        float4 _MainTex_ST;

        struct v2f {
            float4 pos:SV_POSITION;
            float2 uv:TEXCOORD0;
        };
        v2f vert (appdata_full v) {
            v2f o;
            o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
            o.uv=TRANSFORM_TEX(v.texcoord,_MainTex);
            return o;
        }
        float4 frag(v2f i):COLOR
        {
            float4 c=tex2D(_MainTex,i.uv);
            c=c*tex2D(_MyGrab,i.uv);
            return c;
        }
        ENDCG
        }
    }

10.Stencil測試,在Fragment函式之前。