zoukankan      html  css  js  c++  java
  • 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组件来控制的,这里没有设置对时间的操作。

      

  • 相关阅读:
    增强MyEclipse提示功能
    Mysql安装配置,修改初试密码。
    在我的电脑里面创建图标
    popup non topmost
    多线程下载或上传数据限速
    SynchronizationContext
    linux运维笔记——常用命令详解diff
    linux运维笔记——curl
    linux下mysql的源码安装
    shell编程——变量的数值计算
  • 原文地址:https://www.cnblogs.com/zblade/p/6558447.html
Copyright © 2011-2022 走看看