IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> UGUI 列表边缘羽化 -> 正文阅读

[游戏开发]UGUI 列表边缘羽化

在这里插入图片描述
其实就是SoftMask里面的一个功能,不过SoftMask除了这个功能还有一堆其他的,而且Softmask的实现还非常复杂,我自己实现了一个,就几行代码,效果跟softmask差不多的。
实现原理:
以mask为终点边界假设20像素范围内,求出UI上的那个点到边界终点的距离,跟20比一下,来控制这个点或者像素的透明度,边界处和超过边界的为0.

两种实现方式:
1.不用shader,先重写unity的Image类,实现一个自己的可以增加顶点的Image类, 这里要能看懂unity image类源码的slice和simple两种方式是怎么绘制三角形把图形画出来的,比较麻烦,然后在写个BaseMeshEffect类,在重写ModifyMesh方式的时候,检测图形是否已经接触边界了,对接触边界的图形,增加他的顶点数量,非边界元素不加顶点,然后根据这个顶点离边界的距离算出一个alpha值来设置顶点的颜色。text或者textmeshpro是不会走modifyMesh的,所以这个可能要手动在lateupdate里面这种什么的调用控制。
这个代码就不公布了,非主流做法,做了别人反而会问你为什么不用shader做,用shader是比增加顶点性能要好的。
2. 使用shader,传递能把片元模型坐标转化成mask空间下坐标的矩阵过去,同理计算某个片元离边界的距离算出一个alpha值就好,我不懂shader,不过这个东西,不需要懂啥。

Shader "UI/UI-SoftMask"
{
	Properties
	{
		[PerRendererData] _MainTex("Sprite Texture", 2D) = "white" {}
		_Color("Tint", Color) = (1,1,1,1)

		_StencilComp("Stencil Comparison", Float) = 8
		_Stencil("Stencil ID", Float) = 0
		_StencilOp("Stencil Operation", Float) = 0
		_StencilWriteMask("Stencil Write Mask", Float) = 255
		_StencilReadMask("Stencil Read Mask", Float) = 255

		_ColorMask("Color Mask", Float) = 15

		[Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip("Use Alpha Clip", Float) = 0
	}

		SubShader
		{
			Tags
			{
				"Queue" = "Transparent"
				"IgnoreProjector" = "True"
				"RenderType" = "Transparent"
				"PreviewType" = "Plane"
				"CanUseSpriteAtlas" = "True"
			}

			Stencil
			{
				Ref[_Stencil]
				Comp[_StencilComp]
				Pass[_StencilOp]
				ReadMask[_StencilReadMask]
				WriteMask[_StencilWriteMask]
			}

			Cull Off
			Lighting Off
			ZWrite Off
			ZTest[unity_GUIZTestMode]
			Blend SrcAlpha OneMinusSrcAlpha
			ColorMask[_ColorMask]

			Pass
			{
				Name "Default"
			CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma target 2.0

				#include "UnityCG.cginc"
				#include "UnityUI.cginc"

				#pragma multi_compile __ UNITY_UI_CLIP_RECT
				#pragma multi_compile __ UNITY_UI_ALPHACLIP

				struct appdata_t
				{
					float4 vertex   : POSITION;
					float4 color    : COLOR;
					float2 texcoord : TEXCOORD0;
					UNITY_VERTEX_INPUT_INSTANCE_ID
				};

				struct v2f
				{
					float4 vertex   : SV_POSITION;
					fixed4 color : COLOR;
					float2 texcoord  : TEXCOORD0;
					float4 worldPosition : TEXCOORD1;
					UNITY_VERTEX_OUTPUT_STEREO
				};

				sampler2D _MainTex;
				fixed4 _Color;
				fixed4 _TextureSampleAdd;
				float4 _ClipRect;
				float4 _MainTex_ST;

				float4 _SoftMask_Rect;
				float4x4 _SoftMask_WorldToMask;
				float _Scope;

				v2f vert(appdata_t v)
				{
					v2f OUT;
					UNITY_SETUP_INSTANCE_ID(v);
					UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
					OUT.worldPosition = v.vertex;
					OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);

					OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);

					OUT.color = v.color * _Color;
					return OUT;
				}

				fixed4 frag(v2f IN) : SV_Target
				{
					half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;

					#ifdef UNITY_UI_CLIP_RECT
					color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
					#endif

					// 边缘羽化
					float2 maskPosition = mul(_SoftMask_WorldToMask, IN.worldPosition);
					if (maskPosition.y < 0)
					{
						maskPosition.y *= -1;
					}
					color.a *= lerp(0, 1, saturate((_SoftMask_Rect.w - maskPosition.y) / _Scope));
#ifdef UNITY_UI_ALPHACLIP
					clip(color.a - 0.001);
#endif	
					return color;
				}
			ENDCG
			}
		}
}

首先把image本身的shader源码复制过去,最后frag里面加一段计算就完了。

  [ExecuteInEditMode]
    [RequireComponent(typeof(RectTransform))]
    public class SoftMask : UIBehaviour
    {
        public float scope=10;
        Canvas _canvas;
        Canvas canvas
        {
            get { return _canvas ? _canvas : (_canvas = NearestEnabledCanvas()); }
        }
        Canvas NearestEnabledCanvas()
        {
            var canvases = GetComponentsInParent<Canvas>(false);
            for (int i = 0; i < canvases.Length; ++i)
                if (canvases[i].isActiveAndEnabled)
                    return canvases[i];
            return null;
        }
        protected override void OnEnable()
        {
            base.OnEnable();
            SubscribeOnWillRenderCanvases();
            UpdateMaskable(transform);
        }
        protected override void OnDisable()
        {
            base.OnDisable();
            UnsubscribeFromWillRenderCanvases();
        }
        void SubscribeOnWillRenderCanvases()
        {
            Canvas.willRenderCanvases += OnWillRenderCanvases;
        }

        void UnsubscribeFromWillRenderCanvases()
        {
            Canvas.willRenderCanvases -= OnWillRenderCanvases;
        }
        void OnWillRenderCanvases()
        {
            UpdateMaskable(transform);
        }
        private void UpdateMaskable(Transform tran)
        {
            if (transform.childCount == 0)
                return;
            for (int i = 0; i < tran.childCount; i++)
            {
                Transform child = tran.GetChild(i);
                UpdateMaskable(child);
                if (child.GetComponent<CanvasRenderer>() != null)
                {
                    Material mat = child.GetComponent<CanvasRenderer>().GetMaterial(0);
                    if (mat != null)
                    {
                        Rect rect = ((RectTransform)transform).rect;
                        mat.SetVector(Shader.PropertyToID("_SoftMask_Rect"), new Vector4(rect.x, rect.y, rect.width/2, rect.height/2));
                        mat.SetMatrix(Shader.PropertyToID("_SoftMask_WorldToMask"), ((RectTransform)transform).worldToLocalMatrix * canvas.rootCanvas.transform.localToWorldMatrix);
                        mat.SetFloat(Shader.PropertyToID("_Scope"), scope);
                    }
                }
            }
        }
    }

@ 关注

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-12-24 18:50:05  更:2021-12-24 18:51:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 20:19:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码