1. 程式人生 > >UnityShader之遮擋透明

UnityShader之遮擋透明

fixed pen per src 參數 執行 lba off unity

  好久沒寫博客了,最近在學shader,不得不說,shader真的非常美妙,我沈迷其中無法自拔= =

  之前做過一個遮擋透明的功能,當物體遮擋住主角時,該物體會變成半透明顯示出主角。這次同樣是遮擋透明的功能,不過,變透明的剛剛相反,是主角變成半透明,更嚴謹的說是主角被遮擋的那一部分變成半透明。

  先放出結果圖:

技術分享

  當被遮擋時,遮擋部分透明處理,那麽需要涉及渲染深度的知識。引擎是如何判斷哪個物體在前面哪個物體在後面呢?

  深度:每個像素有自己的深度值,離攝像機近的深度小,遠的深度大

  深度緩沖區:存儲每個像素的深度

  顏色緩沖區:存儲每個像素的顏色

  過程:首先比較像素的深度與深度緩沖區同一位置的深度,如果前者小於後者,則未通過深度測試;否則,通過深度測試,將前者寫入後者,將該像素的顏色寫入到顏色緩沖區。將顏色緩沖區像素顏色顯示到屏幕上。

  通過這個過程即可把深度小的像素剔除掉,將深度大的顯示到屏幕上,從而實現物體的前後順序。

  UnityShader提供了ZWrite 和 ZTest對應深度寫入和深度測試。

技術分享

  調整ZWrite可以控制是否將深度寫入到深度緩沖區,當然,前提是深度測試通過,如果沒通過測試,那麽肯定是無法寫入的

技術分享

  調整ZTest可以定義上述中前者與後者的比較關系,默認為LEqual即小於等於時通過測試

  那麽可以得到一種實現思路,用兩個PASS:

  第一個PASS:ZTest 為 Greater,ZWrite 為 Off,當該像素被遮擋即深度大於深度緩沖區對應位置深度時執行該PASS,那麽就可以在該PASS中實現被遮擋像素的效果。

  第二個PASS:ZTest為LEqual,ZWrite 為 On,這個PASS與上述PASS是互斥的,在這個PASS中實現未被遮擋像素的效果。

  設置ZWrite 是為了防止兩個PASS都執行,如果第一個PASS的ZWrite為On,某一像素未被遮擋時,執行第一個PASS,將像素深度寫入深度緩沖區,然後輪到第二個PASS進行深度測試時也會通過,因為小於等於嘛。

  

  被遮擋像素透明實現用了邊緣光使得更炫酷。邊緣光公式大概如下:

  fixed rim=1-saturate(dot(worldNormalDir,worldViewDir));

  fixed3 finalCol=_RimColor.xyz*pow(rim,_RimPower)*_RimIntensity

  通過第一個式子可以得到一個參數rim,頂點法線方向與視角方向契合度越高則rim越小,否則rim越大,即越靠近邊緣rim越大

  第二個式子中pow是為了提高邊緣光硬度

  代碼:

技術分享
  1 // Upgrade NOTE: replaced ‘_Object2World‘ with ‘unity_ObjectToWorld‘
  2 
  3 Shader "MyShader/Rim/RimShader" {
  4     Properties{
  5         _RimColor("Rim Color",Color)=(1.0,1.0,1.0,1.0)//邊緣光顏色
  6         _RimPower("Rim Power",Range(0.1,10))=3.0//Pow參數
  7         _RimIntensity("Rim Intensity",Range(0,100))=10//邊緣光強度
  8 
  9         _MainTex("Base (RGB)",2D)="white"{}
 10     }
 11     SubShader{
 12         //當所有不透明物體渲染後開始渲染此物體
 13         Tags{"Queue"="Geometry+50" "RenderType"="Opaque"}
 14 
 15         Pass{
 16             Blend SrcAlpha OneMinusSrcAlpha
 17             Cull Off
 18             ZWrite Off
 19             ZTest Greater
 20 
 21             CGPROGRAM
 22             #pragma vertex vert
 23             #pragma fragment frag
 24             #include "UnityCG.cginc"
 25 
 26                 fixed4 _RimColor;
 27                 float _RimPower;
 28                 float _RimIntensity;
 29 
 30                 struct a2v{
 31                     float4 vertex:POSITION;
 32                     float3 normal:NORMAL;
 33                 };
 34 
 35                 struct v2f{
 36                     float4 pos:SV_POSITION;
 37                     float4 worldPos:TEXCOORD0;
 38                     float3 worldNormal:TEXCOORD1;
 39                 };
 40 
 41                 v2f vert(a2v v){
 42                     v2f o;
 43                     o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
 44                     o.worldPos=mul(unity_ObjectToWorld,v.vertex);
 45                     o.worldNormal=UnityObjectToWorldNormal(v.normal);
 46                     return o;
 47                 }
 48 
 49                 fixed4 frag(v2f i):SV_TARGET{
 50                     fixed3 worldNormalDir=normalize(i.worldNormal);
 51                     fixed3 worldViewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
 52                     fixed rim=1-saturate(dot(worldNormalDir,worldViewDir));
 53 
 54                     fixed3 col=_RimColor.xyz*pow(rim,_RimPower)*_RimIntensity;
 55                     return fixed4(col,0.3);
 56                 }
 57             ENDCG
 58         }
 59 
 60         Pass{
 61             Tags{"LightMode"="ForwardBase"}
 62             ZWrite On
 63             ZTest LEqual
 64             CGPROGRAM
 65             #pragma vertex vert
 66             #pragma fragment frag
 67             #include "UnityCG.cginc"
 68             #include "Lighting.cginc"
 69             #include "AutoLight.cginc"
 70 
 71                 sampler2D _MainTex;
 72                 float4 _MainTex_ST;
 73 
 74 
 75                 struct a2v{
 76                     float4 vertex:POSITION;
 77                     float2 texcoord:TEXCOORD0;
 78                 };
 79 
 80                 struct v2f{
 81                     float4 pos:SV_POSITION;
 82                     float2 uv:TEXCOORD0;
 83                 };
 84 
 85                 v2f vert(a2v v){
 86                     v2f o;
 87                     o.pos=mul(UNITY_MATRIX_MVP,v.vertex);
 88                     o.uv=v.texcoord*_MainTex_ST.xy+_MainTex_ST.zw;
 89                     return o;
 90                 }
 91 
 92                 fixed4 frag(v2f i):SV_TARGET{
 93                     fixed3 col=tex2D(_MainTex,i.uv).rgb;
 94 
 95                     return fixed4(col,1);
 96                 }
 97 
 98             ENDCG
 99         }
100 
101 
102     }
103     FallBack "Diffuse"
104 }
View Code

UnityShader之遮擋透明