【UnityShader】设置Image组件图片透明四个方向透明渐变(Sprite原理相同)

由于对Shader比较感兴趣,虽然这不是公司的需求,但还是自己利用工作时间之余完成了这个效果,这个功能对于2D游戏来说以后可能会有需求

先展示一下效果

先上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
		}
	}
}
Shader 的原理就是用阈值和uv来计算透明程度,再使用lerp控制改变透明度的范围,避免进行条件判断。为了不用每个图片创建一个材质放着,可以使用C#脚本动态创建Material给Shader赋值,也更好用更人性化,更方便制作动画。

首先上个基类代码,这个代码是我从《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文件被我删了。原理都大致相同,参照做出来即可。



©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页