UGUI 列表边缘羽化

刚刚发现这玩意unity 的Rect Mask 2D已经内置了,真难受。
在这里插入图片描述
使用Rect Mask2D不需要一个image组件,性能更好。

在这里插入图片描述
不过TextMeshPro不受rectMask2d的soft影响,效果不好。
在这里插入图片描述
其实就是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);
                    }
                }
            }
        }
    }

@ 关注

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: Unity UGUI 列表是一种常见的 UI 控件,用于展示类别、选项或者数据。它通常由一个滚动视图组成,包含一个或多个列表项,每个列表项包含显示内容、图标和按钮。 在 Unity 中,实现列表通常需要以下步骤: 1. 创建一个滚动区域并设置相关参数,如大小、位置、滚动方向等等。 2. 在滚动区域内创建列表项,通常使用一个 prefab 来实现。 3. 让列表项拥有响应鼠标事件的组件,通常是按钮或 Toggle 组件。 4. 定义列表项的数据结构,如包含名称、描述、图标等属性。 5. 将数据与列表项绑定,使得列表项能够根据数据源的变化自动更新。 6. 定义列表项的样式,如字体、颜色、对齐方式等等。 7. 编写列表项的逻辑代码,处理用户点击触发的事件。 总之,Unity UGUI 列表是一种非常常见和实用的 UI 控件,可以用于许多不同的场景,如游戏菜单、设置界面、排行榜等等。有了列表的支持,用户可以更加便捷地浏览和操作大量的信息。 ### 回答2: Unity UGUI列表是一个UI组件,它允许开发者在游戏设计中创建各种不同类型的列表。在列表中,开发者可以显示一系列项目,用于展示各种信息和元素,例如角色列表、任务列表、排行榜等。 这个组件提供了一些控制选项,例如滚动条、滑动速度、自动布局等。开发者可以使用这些选项来控制列表的行为,使其更接近预期的效果。列表还可以支持不同的布局方式,例如网格布局、表格布局、平铺布局等,以便显示不同格式的项目。 Unity UGUI列表还允许开发者自定义项目的外观和交互。每个项目都可以选择不同的背景图片、字体、颜色和图标等。开发者还可以在每个项目上定义按钮事件或其他交互事件,例如打开一个菜单、播放动态内容等。 总的来说,Unity UGUI列表是一个很有用的UI组件,它可以简化游戏设计中的列表创建过程,并提供了灵活的控制和交互选项。开发者可以利用它来创建丰富的游戏UI,为玩家提供更好的交互和用户体验。 ### 回答3: Unity UGUI 列表是 Unity 引擎中的一个 UI 元素,用于显示和控制列表中的项目。列表通常用于显示大量的数据,如图像、文本或按钮。Unity UGUI 中的列表组件支持选择、滚动和无限滚动功能。列表组件可以通过在游戏对象中添加 Scroll View、Viewport 和 Content 三个组件来实现。Scroll View 是列表的外壳,Viewport 是显示列表的区域,Content 是列表中的项目。在 Content 中,通过使用 Layout Group 和 Content Size Fitter 来控制列表中的项目排列和大小。 Unity UGUI 列表可以和数据绑定一起使用,通过数据绑定可以动态地更新列表中的项目。例如,在游戏中选择一种角色后,可以通过数据绑定将角色属性动态地绑定到列表中的项目,从而更新列表中的显示内容。列表组件还支持使用导航组件来快速地在列表中导航。在导航组件中,可以使用键盘或鼠标来快速地选择列表中的项目。 Unity UGUI 列表是游戏开发中非常重要的一个元素,它可以用来创建各种类型的列表,如任务列表、道具列表等。在使用列表组件时,需要仔细地考虑列表的设计和布局,以便用户可以轻松地使用列表。使用 Unity UGUI 列表可以使游戏界面变得更加直观和易于操作,增强游戏的可玩性和用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JustEasyCode

谢谢您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值