Shader實例:NGUI圖集中的UISprite正確使用Shader的方法


效果:

變灰,過濾,流光 都是UI上常用效果。
比如:
1.按鈕禁用時,變灰。
2.一張Icon要應付圓形背景框,又要應付矩形背景框。就要使用過濾的方式來裁剪。
避免了美術提供兩張icon的麻煩,又節省了內存。
3.流光,呃……,策划就是要,你能怎么辦。

實踐:
NGUI把要用到的圖片做成了圖集,它會記錄每一張小圖的信息。
包括:每一張小圖在這張圖集里面的位置,長,寬,padding,border。等等。
使用時只是采樣這張小圖所在區域,然后顯示在UI的mesh上。
如果我們用這張小圖的texcoord,去采樣另外一張圖,采樣到的就只是部分,就不是我們所希望那樣(采樣完整的圖)。
那么,只要把小圖texcoord按照相應比例擴大,得到正確的texcoord即可。

看一下t_sheyaonan在圖集中的位置,Position(0,26) ,width:102,height:111

0,26

再看下圖集,哦,原來圖集的左上角為0,0點。

分析:

要得到正確的texcoord坐標?
只需將小圖A的texcoord坐標,減去偏移,再按規定的比例擴大。

so:
final_uv.x = (小圖A的texcoord.x – x/W ) * (W/w)
final_uv.y = (小圖A的texcoord.y – (H-y-h)/H) * (H/h)

用final_uv去采樣就OK了。

shader代碼:改寫自Unlit – Transparent Colored
//–add– 部分就是我添加的。

Shader "Custom/Unlit/Transparent Colored Grey Mask Flow"
{
 Properties
 {
  _MainTex ("Base (RGB), Alpha (A)", 2D) = "black" {}
 
  //---add---------------------------------
  _MaskTex ("Mask Alpha (A)", 2D) = "white" {}
  _IfMask("Open mask if larger than 0.5", Range(0,1)) = 0
  _WidthRate ("Sprite.width/Atlas.width", float) = 1
  _HeightRate ("Sprite.height/Atlas.height", float) = 1
  _XOffset("offsetX/Atlas.width", float) = 0
  _YOffset("offsetY/Atlas.height", float) = 0
  _FlowTex("flow tex",2D) = ""{}
  //--------------------------------------
 }
 SubShader
 {
  LOD 100
 
  Tags
  {
   "Queue" = "Transparent"
   "IgnoreProjector" = "True"
   "RenderType" = "Transparent"
  }
 
  Cull Off
  Lighting Off
  ZWrite Off
  Fog { Mode Off }
  Offset -1, -1
  Blend SrcAlpha OneMinusSrcAlpha
 
  Pass
  {
   CGPROGRAM
   #pragma vertex vert
   #pragma fragment frag
 
   #include "UnityCG.cginc"
   struct appdata_t
   {
    float4 vertex : POSITION;
    float2 texcoord : TEXCOORD0;
    fixed4 color : COLOR;
   };
   struct v2f
   {
    float4 vertex : SV_POSITION;
    half2 texcoord : TEXCOORD0;
    fixed4 color : COLOR;
   };
   sampler2D _MainTex;
   float4 _MainTex_ST;
 
   //---add-------
   sampler2D _MaskTex;
   float _IfMask; 
   float _WidthRate;
   float _HeightRate;
   float _XOffset; 
   float _YOffset; 
   sampler2D _FlowTex;
   //--------------
 
   v2f vert (appdata_t v)
   {
    v2f o;
    o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    o.texcoord = v.texcoord;
    o.color = v.color;
    return o;
   }
 
   fixed4 frag (v2f i) : COLOR
   {
       fixed4 col;
       col = tex2D(_MainTex, i.texcoord);
 
       //---------add---------------------------------
       //過濾
    if(_IfMask>0.5)
    {
     col.a = col.a * tex2D(_MaskTex, float2((i.texcoord.x-_XOffset)/_WidthRate, (i.texcoord.y-_YOffset)/_HeightRate)).a; 
    }  
    //變灰
    if(i.color.r<=0.1)
    {
     float grey = dot(col.rgb, float3(0.299, 0.587, 0.114));  
     col.rgb = float3(grey, grey, grey);  
    }
    //流光
    if(i.color.g<=0.1)
    {
     float2 flow_uv = float2((i.texcoord.x-_XOffset)/_WidthRate, (i.texcoord.y-_YOffset)/_HeightRate);
     flow_uv.x/=2;
     flow_uv.x-= _Time.y *2;
     half flow = tex2D(_FlowTex,flow_uv).a; 
     col.rgb+= half3(flow,flow,flow);
    }
    //-----------------------------------------------
    return col;
   }
   ENDCG
  }
 }
 
 SubShader
 {
  LOD 100
 
  Tags
  {
   "Queue" = "Transparent"
   "IgnoreProjector" = "True"
   "RenderType" = "Transparent"
  }
 
  Pass
  {
   Cull Off
   Lighting Off
   ZWrite Off
   Fog { Mode Off }
   Offset -1, -1
   ColorMask RGB
   AlphaTest Greater .01
   Blend SrcAlpha OneMinusSrcAlpha
   ColorMaterial AmbientAndDiffuse
 
   SetTexture [_MainTex]
   {
    Combine Texture * Primary
   }
  }
 }
}

C#腳本:掛在UISprite上

using UnityEngine;
using System.Collections;
 
public class ScaleTexcoord : MonoBehaviour
{
    private float widthRate;
    private float heightRate;
    private float xOffsetRate;
    private float yOffsetRate;
    private UISprite sprite;
 
    void Awake()
    {
        sprite = GetComponent<UISprite>();
        widthRate = sprite.GetAtlasSprite().width * 1.0f / sprite.atlas.spriteMaterial.mainTexture.width;
  heightRate = sprite.GetAtlasSprite().height * 1.0f / sprite.atlas.spriteMaterial.mainTexture.height;
        xOffsetRate = sprite.GetAtlasSprite().x * 1.0f / sprite.atlas.spriteMaterial.mainTexture.width;
  yOffsetRate = (sprite.atlas.spriteMaterial.mainTexture.height-(sprite.GetAtlasSprite().y + sprite.GetAtlasSprite().height)) * 1.0f / sprite.atlas.spriteMaterial.mainTexture.height;
    }
 
    private void Start()
    {
        sprite.atlas.spriteMaterial.SetFloat("_WidthRate", widthRate);
        sprite.atlas.spriteMaterial.SetFloat("_HeightRate", heightRate);
        sprite.atlas.spriteMaterial.SetFloat("_XOffset", xOffsetRate);
        sprite.atlas.spriteMaterial.SetFloat("_YOffset", yOffsetRate);
    }
}

 

測試一下:掛在主相機上

using UnityEngine;
using System.Collections;
 
public class test : MonoBehaviour
{
 public UISprite sprite1;
 public UISprite sprite2;
 public UISprite sprite3;
 
    public Material default_mat;
 public Material mask1_mat;
 public Material mask2_mat;
 
 void OnGUI()
 {
  if(GUI.Button( new Rect(0,100,100,50),"過濾圖1"))
  {
   sprite1.atlas.spriteMaterial = mask1_mat;
  }
 
  if(GUI.Button( new Rect(110,100,100,50),"過濾圖2"))
  {
   sprite1.atlas.spriteMaterial = mask2_mat;
  }
 
  if(GUI.Button( new Rect(0,160,100,50),"變灰"))
  {
   sprite2.color = new Color(0,1,1);
  }
 
  if(GUI.Button( new Rect(110,160,100,50),"流光"))
  {
   sprite3.color = new Color(1,0,1);
  }
 }
 
    void OnDestroy()
    {
        sprite1.atlas.spriteMaterial = default_mat;
    }
}

學習的腳步不能停~~~~~~~~~~~~~~~~~

需要我的測試工程,請留言。嘻嘻!


免責聲明!

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



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