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);
}
}