【UnityShader】設定Image元件圖片透明四個方向透明漸變(Sprite原理相同)
阿新 • • 發佈:2019-02-09
由於對Shader比較感興趣,雖然這不是公司的需求,但還是自己利用工作時間之餘完成了這個效果,這個功能對於2D遊戲來說以後可能會有需求
先展示一下效果
先上Shader程式碼
Shader 的原理就是用閾值和uv來計算透明程度,再使用lerp控制改變透明度的範圍,避免進行條件判斷。為了不用每個圖片建立一個材質放著,可以使用C#指令碼動態建立Material給Shader賦值,也更好用更人性化,更方便製作動畫。Shader "Unlit/ImageAlpha" { Properties { _MainTex ("Texture", 2D) = "white" {} _AlphaLX("RangeAlphaLX",Float) = 0 _AlphaRX("RangeAlphaRX",Float) = 1 _AlphaTY("RangeAlphaTY",Float) = 1 _AlphaBY("RangeAlphaBY",Float) = 0 _AlphaPower("Power",Float) = 0 //透明度變化範圍 } SubShader { Tags { "RenderType"="Transparent" } Blend SrcAlpha OneMinusSrcAlpha Cull Back Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; float _AlphaPower; sampler2D _AlphaTex; float _AlphaLX; float _AlphaRX; float _AlphaTY; float _AlphaBY; v2f vert (appdata v) { v2f o; o.vertex = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } //此方法取自Unity預設Sprite的Shader fixed4 SampleSpriteTexture (float2 uv) { fixed4 color = tex2D (_MainTex, uv); #if ETC1_EXTERNAL_ALPHA // get the color from an external texture (usecase: Alpha support for ETC1 on android) color.a = tex2D (_AlphaTex, uv).r; #endif //ETC1_EXTERNAL_ALPHA return color; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = SampleSpriteTexture(i.uv); //利用透明度閾值和uv座標的差來計算透明的程度和是否控制其半透 //四個方向只是對座標的取值和正反方向不同,原理一致 fixed alphalx = col.a * lerp(1,_AlphaPower,(_AlphaLX-i.uv.x)); col.a = saturate(lerp(alphalx,col.a,step(_AlphaLX,i.uv.x))); fixed alpharx = col.a * lerp(1,_AlphaPower,(i.uv.x-_AlphaRX)); col.a = saturate(lerp(col.a,alpharx,step(_AlphaRX,i.uv.x))); fixed alphaby = col.a * lerp(1,_AlphaPower,(_AlphaBY-i.uv.y)); col.a = saturate(lerp(alphaby,col.a,step(_AlphaBY,i.uv.y))); fixed alphaty = col.a * lerp(1,_AlphaPower,(i.uv.y-_AlphaTY)); col.a = saturate(lerp(col.a,alphaty,step(_AlphaTY,i.uv.y))); return col; } ENDCG } } }
首先上個基類程式碼,這個程式碼是我從《Unity入門精要》螢幕特效那裡改一點點拿來用的,因為真的非常好用,感謝馮樂樂女神!
接下來繼承這個基類寫上自己的變數,動態進行賦值,一個簡單的編輯器就完成了using UnityEngine; using System.Collections; [ExecuteInEditMode] public class PostEffectsBase : MonoBehaviour { // Called when start protected void CheckResources() { bool isSupported = CheckSupport(); if (isSupported == false) { NotSupported(); }// } // Called in CheckResources to check support on this platform protected bool CheckSupport() { if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) { Debug.LogWarning("This platform does not support image effects or render textures."); return false; } return true; } // Called when the platform doesn't support this effect protected void NotSupported() { enabled = false; } protected void Start() { CheckResources(); } // Called when need to create the material used by this effect protected Material CheckShaderAndCreateMaterial(Shader shader, Material material) { if (shader == null) { return null; } if (shader.isSupported && material && material.shader == shader) return material; if (!shader.isSupported) { return null; } else { material = new Material(shader); material.hideFlags = HideFlags.DontSave; if (material) return material; else return null; } } }
using UnityEngine; using System.Collections; using UnityEngine.UI; public class SetImageAlpha : PostEffectsBase { [Range(0, 1)] public float leftX = 0; [Range(0, 1)] public float rightX = 0; [Range(0, 1)] public float topY = 0; [Range(0, 1)] public float bottomY = 0; [Range(-2, 0)] public float alphaSmooth = 0; // Use this for initialization public Shader alphaShader; private Material _materal; public Material _Material { get { _materal = CheckShaderAndCreateMaterial(alphaShader, _materal); return _materal; } } private void Awake() { alphaShader = Shader.Find("Unlit/ImageAlpha"); } // Update is called once per frame void Update() { _Material.SetFloat("_AlphaLX", leftX*2); _Material.SetFloat("_AlphaRX", ((1 - rightX) - 0.5f)*2); _Material.SetFloat("_AlphaTY", ((1 - topY) - 0.5f)*2); _Material.SetFloat("_AlphaBY", bottomY*2); _Material.SetFloat("_AlphaPower", alphaSmooth);
//變數的計算只是為了對映範圍
GetComponent<Image>().material = _Material;
}
}
這裡對變數進行的一些運算都是為了變數從把(0,1)的範圍對映到Shader的有效值範圍,只是一些簡單的數學運算,參考了一點半蘭伯特的演算法。大家想一下就可以理解最後再把SetImageAlpha指令碼掛到帶有Image元件的遊戲物體上就可以了,大家也可以自己加一些漸變強度之類的引數獲得更靈活的效果。
還有一種就是圖片到螢幕某個區域的部分進行半透,這也很簡單,在頂點著色器中把頂點座標轉換到齊次座標,然後用座標和閾值做運算判斷即可。之前我也已經實現了這個效果,只是Shader檔案被我刪了。原理都大致相同,參照做出來即可。