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函数之前。

猜你喜欢

转载自blog.csdn.net/jfy307596479/article/details/84852381