Unity中溶解shader的總結


   轉載請標明出處http://www.cnblogs.com/zblade/ 

    在實際的游戲工程中,經常美術和策划會提出溶解的表現要求。比如子彈在飛行的時候,彈道不斷的消融;角色受到大型炮彈的攻擊,在擊飛的時候不斷的消融等等諸如此類的表現。一般的消融都是結合粒子系統來實現,通過給粒子Render組件添加material來實現表現。

  通過總結我在項目中用到的消融shader,以及在網上查找到的部分消融shader,我做一個基本的shader歸類,便於今后的思路查找,其中有任何錯誤請指出,大家一起學習進步。

  實現溶解效果,基本方法是用一個基本紋理貼圖+無序圖來實現溶解的效果,基本紋理貼圖用來表示正常的效果,無序圖則表示消融的參考值。通常對消融圖是讓美術做一張層級圖,其中rgba四個通道任意選一個通道作為溶解的無序通道。

  下面我先列出參考的一些shader的實現:

  1、基本的實現單次溶解的vert/frag shader

Shader "Esfog/Dissolve" 
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _NoiseTex ("NoiseTex (R)",2D) = "white"{}
        _DissolveSpeed ("DissolveSpeed (Second)",Float) = 1
        _EdgeWidth("EdgeWidth",Range(0,0.5)) = 0.1
        _EdgeColor("EdgeColor",Color) =  (1,1,1,1)
    }
    SubShader 
    {
        Tags { "RenderType"="Opaque" }
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert_img
            #pragma fragment frag
            #include "UnityCG.cginc"
             
            uniform sampler2D _MainTex;
            uniform sampler2D _NoiseTex;
            uniform float _DissolveSpeed;
            uniform float _EdgeWidth;
            uniform float4 _EdgeColor;
            
            float4 frag(v2f_img i):COLOR
            {
                float DissolveFactor = saturate(_Time.y / _DissolveSpeed);
                float noiseValue = tex2D(_NoiseTex,i.uv).r;            
                if(noiseValue <= DissolveFactor)
                {
                    discard;
                }
                
                float4 texColor = tex2D(_MainTex,i.uv);
                float EdgeFactor = saturate((noiseValue - DissolveFactor)/(_EdgeWidth*DissolveFactor));
                float4 BlendColor = texColor * _EdgeColor;
                                
                return lerp(texColor,BlendColor,1 - EdgeFactor);
            }
            
            ENDCG
        }
    } 
    
    FallBack Off
}

  這篇shader來自於Esfog溶解shader,具體的代碼解釋可以參看原文作者的解釋,比較詳細,網上很多的相似shader大概都是來自於此。

  我只說一下大概的思路,基本就是采樣無序圖,然后通過其中的某個通道(此處為r)的值,與當前的溶解系數對比,如果當前的通道值小於溶解系數,則說明當前片元需要被剔除。如果不被剔除,則判斷當前值距離消融的比例來設置消融的邊緣顏色混合。

  2、根據外部觸發的消融vert/frag shader

  上面的shader在開始觸發的時候就會不斷的消融,在某些時候,我們希望通過外部的時間來控制消融的觸發與否,則可以在shader中提供一個外部參數,通過在代碼中查找到該material,通過設置material的值來用作觸發消融。我們可以在上面的shader的基礎上做進一步的改進,改進后的代碼如下:

Shader "Esfog/Dissolve" 
{
    Properties 
    {
        _MainTex ("Base (RGB)", 2D) = "white" {}
        _NoiseTex ("NoiseTex (R)",2D) = "white"{}
        _DissolveSpeed ("DissolveSpeed (Second)",Float) = 1
        _EdgeWidth("EdgeWidth",Range(0,0.5)) = 0.1
        _EdgeColor("EdgeColor",Color) =  (1,1,1,1)
     _DissolveStartTime("DissolveStartTime",float)=0 } SubShader { Tags {
"RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" uniform sampler2D _MainTex; uniform sampler2D _NoiseTex; uniform float _DissolveSpeed; uniform float _EdgeWidth; uniform float4 _EdgeColor;        uniform float _DissolveStartTime; 
float4 frag(v2f_img i):COLOR {
          bool isNormal = true;
          float c = 1;
float4 texColor = tex2D(_MainTex,i.uv);
          if(_DissolveStartTime > 0 )
          {
           
float DissolveFactor = saturate((_Time.y-_DissolveStartTime) * _DissolveSpeed);
           float noiseValue = tex2D(_NoiseTex,i.uv).r;
           if(noiseValue <= DissolveFactor)
           {
              discard;
           }
   float EdgeFactor = saturate((noiseValue - DissolveFactor)/(_EdgeWidth*DissolveFactor));   float4 BlendColor = texColor * _EdgeColor;
            texColor = lerp(texColor,BlendColor,1 - EdgeFactor);
}
return texColor;
 } ENDCG } } FallBack Off }

  通過外部的設置material中的_DissolveStartTime,我們可以控制消融的開始與否,這兒在對消融系數求解的時候,我改為相乘,這樣消融的速度就是正確的表明速度。

     3、用透明通道來實現的消融

  以上兩種shader都是基於一張無序圖來判定是否消融,如果我們需要做一種透明度逐漸消散的效果,直接采用discard會顯得很生硬,不能實現不透明,半透明,透明這樣的逐漸消散的效果。如果我們需要用透明的方式來實現消融。這兒我給出一種用透明度實現的消融shader的實現,主要也是通過兩張貼圖的采用和某些通道值得對比來控制混合的alpha通道。

  代碼如下:

Shader"Z/DissolveWithBlend"
{
    Propertise{  
        _Color("Color&Alpha",Color)=(1,1,1,1)
        _MainTex("MainTex",2D)="white"{}
        _Mask("Mask",2D)="white"{}       
        _AlphaFactor("AlphaFactor",Float)=0.0
       }  
      Subshader{
          Tags{"Queue"="Transparent" "IgnoreProjector"="True""RenderType"="Transparent"}
           Pass{
                 Tags{"LigthMode"="ForwardBase"}
                  Blend SrcAlpha OneMinusAlpha
                  Cull Front
                  ZWrite off
                 CGPROGRAM
                 #include "UnigytCG.cginc"
                 #pragma vertex vert
                 #pragma fragment frag
                   sampler2D _MainTex;
                   float4 _MainTex_ST;
                   sampler2D _Mask;
                   float4 _Mask_ST;
                 struct a2v{
                     float4 vertex:POSITION;
                     float2 texcoord:TEXCOORD0;
                 }
                 struct v2f{
                      float4 pos:SV_POSITION;
                      float2 uv0:TEXCOORD0;
                      float2 uv1:TEXCOORD1;
                  }

                 v2f vert(a2v i){
                       v2f o;
                       o.pos = mul(UNITY_MATRIX_MVP,i.vertex);
                       o.uv0 = TRANSFORM_TEX(i.texcoord,_MainTex);
                       o.uv1 = TRANSFORM_TEX(i.texcoord,_Mask);
                  }
                  fixed4 frag(v2f i):Color{
                       float4 _mainVar = tex2D(_MainTex,i.uv0);
                       float4 _maskVar = tex2D(_Mask,i.uv1);
                       float3  emissive = _Color.rgb * _mainVar.rgb;
                       return fixed4(emissive,_Color.a * _mainVar.a * step(maskVar.r,_AlphaFactor));

                 }
          ENDCG
           }
      }
    FallBack"Diffuse" }

  基本的操作就是通過設置顏色的alpha通道的透明度,來實現一種用透明度控制的消融效果。當然,這樣的shader對於時間的控制,是需要這個特效外部的particle組件來控制的,這里沒有設置對時間的操作。

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM