1. 程式人生 > >Shader 三種方法實現玻璃效果

Shader 三種方法實現玻璃效果

一、使用Cubemap,做一個假反射
shader程式碼如下:
Shader “Custom/glassShader” {
Properties {
_MainColor(“Main Color”,Color)=(1,1,1,1)
_MainTex (“Base (RGB)”, 2D) = “white” {}
_Cube(“Cube”,CUBE)=”“{}
}
SubShader {
Tags {“RenderType”=”Opaque”}
LOD 200

    //cull off  

    CGPROGRAM  
    #pragma surface surf Lambert alpha  

    fixed4 _MainColor;  
    sampler2D _MainTex;  
    samplerCUBE _Cube;  

    struct Input {  
        float2 uv_MainTex;  
        float3 worldRefl;  
    };  

    void surf (Input IN, inout SurfaceOutput o) {  
        half4 c = tex2D (_MainTex, IN.uv_MainTex);  
        o.Albedo = c.rgb*_MainColor.rgb;  
        o.Emission=texCUBE(_Cube,IN.worldRefl).rgb;  
        o.Alpha = c.a*_MainColor.a;  
    }  
    ENDCG  
}   

FallBack "Diffuse"  

}

二、使用GrabPass,抓取螢幕紋理,實現實時反射
shader程式碼如下:
Shader “Unlit/GrabGlass”
{
Properties
{
_Color(“Main Color”,Color)=(1,1,1,1)
_MainTex (“Texture”, 2D) = “white” {}
}
SubShader
{

    Tags {"Queue"="Transparent" "RenderType"="Opaque" }//Opaque  
    LOD 100  

    //繪製半透明物體 關閉深度快取  
    ZWrite Off  
    //透明混合  
    Blend SrcAlpha OneMinusSrcAlpha  

    //如果沒有命名,則可以用_GrabTexture來讀取,不過開銷很大,應用到特殊效果時才去應用  
    GrabPass  
    {  
            "_GrabTex"  
    }  

    Pass  
    {  
        CGPROGRAM  
        #pragma vertex vert  
        #pragma fragment frag  
        // make fog work  
        #pragma multi_compile_fog  

        #include "UnityCG.cginc"  

        struct appdata  
        {  
            float4 vertex : POSITION;  
            float2 uv : TEXCOORD0;  
        };  

        struct v2f  
        {  
            float2 uv : TEXCOORD0;  
            UNITY_FOG_COORDS(1)  
            float4 vertex : SV_POSITION;  
        };  

        sampler2D _MainTex;  
        float4 _MainTex_ST;  
        fixed4 _Color;  
        sampler2D _GrabTex;  

        v2f vert (appdata v)  
        {  
            v2f o;  
            o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);  
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);  
            UNITY_TRANSFER_FOG(o,o.vertex);  
            return o;  
        }  

        fixed4 frag (v2f i) : SV_Target  
        {  
            // sample the texture  
            fixed4 col = tex2D(_MainTex, i.uv)*_Color;  

            // apply fog  
            UNITY_APPLY_FOG(i.fogCoord, col);   
            //調整一下uv  
            float2 uv=i.uv;      
            uv.x=1-uv.x;  
            return col*tex2D(_GrabTex,uv);  
        }  
        ENDCG  
    }  
}  

}

三、使用攝像機實現實時反射
因為GrabPass,相對來說消耗較大,只建議用於一些特殊效果,於是這裡就藉助輔助攝像機,來實現實時反射效果,當然這需要多寫一個指令碼,同時需要在輔助攝像機中遮蔽玻璃本身
shader程式碼如下:
Shader “Unlit/CameraGlass”
{
Properties
{
_MainTex (“Texture”, 2D) = “white” {}
}
SubShader
{
Tags { “RenderType”=”Opaque” }
LOD 100

    Pass  
    {  
        CGPROGRAM  
        #pragma vertex vert  
        #pragma fragment frag  
        // make fog work  
        #pragma multi_compile_fog  

        #include "UnityCG.cginc"  

        struct appdata  
        {  
            float4 vertex : POSITION;  
            float2 uv : TEXCOORD0;  
        };  

        struct v2f  
        {  
            float2 uv : TEXCOORD0;  
            UNITY_FOG_COORDS(1)  
            float4 vertex : SV_POSITION;  
        };  

        sampler2D _MainTex;  
        float4 _MainTex_ST;  

        v2f vert (appdata v)  
        {  
            v2f o;  
            o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);  
            o.uv = TRANSFORM_TEX(v.uv, _MainTex);  
            UNITY_TRANSFER_FOG(o,o.vertex);  
            return o;  
        }  

        fixed4 frag (v2f i) : SV_Target  
        {  
            // sample the texture  需要調整一下uv  
            fixed4 col = tex2D(_MainTex, 1-i.uv);  
            // apply fog  
            UNITY_APPLY_FOG(i.fogCoord, col);               
            return col;  
        }  
        ENDCG  
    }  
}  

}
指令碼程式碼如下:
using UnityEngine;
using System.Collections;

public class RenderGlassTexture : MonoBehaviour {

/// <summary>  
/// 輔助攝像機   
/// 原理:就是將輔助攝像機所看到的內容渲染到玻璃物體上,所以就實現了實時反射的鏡面效果  
/// 因為玻璃也是場景中的物體,所以輔助攝像機也會看見他  
/// 所以最好能將玻璃物體單獨放在一個層級中,讓輔助攝像機不去渲染他  
/// </summary>  
public Camera cam;  
private RenderTexture renderTex;  
/// <summary>  
/// 玻璃shader  
/// </summary>  
public Shader glassShader;  
/// <summary>  
/// 玻璃材質  
/// </summary>  
private Material m_GlassMaterial;  
protected Material GlassMaterial  
{  
    get  
    {  
        if (m_GlassMaterial == null)  
        {  
            m_GlassMaterial = new Material(glassShader);  
        }  
        return m_GlassMaterial;  
    }  
}  

// Use this for initialization  
void Start () {  
    renderTex = new RenderTexture(Screen.width, Screen.height, 16);  
    cam.targetTexture = renderTex;  
}  

//在攝像機開始裁剪場景之前呼叫  
void OnPreCull()  
{  
    GlassMaterial.SetTexture("_MainTex", renderTex);  
}  

//在相機完成場景渲染後呼叫  
void OnPostRender()  
{  
    GlassMaterial.SetTexture("_MainTex", null);  
}  

}