【UnityShader】设置Image组件图片透明四个方向透明渐变(Sprite原理相同)
程序员文章站
2022-04-03 22:19:00
...
由于对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文件被我删了。原理都大致相同,参照做出来即可。
上一篇: 百度指数大改版:全新界面,全新体验
下一篇: 三大公用DNS服务器访问速度比较分析