[Unity]UGUI ScrollView ui特效遮挡的问题

当使用滚动列表的时候,例如商城,好友列表。我们要在每个列表Item上添加UI特效的时候(Particle System或Mesh Renender等)会发现特效并不能根据父控件的大小而裁减掉,如图:


注:UGUI和NGUI都存在这个问题,NGUI则是在UIPanel Clipping 为Soft Clip时。

我们要实现的效果是超框的部分也应该和其他UI一样被裁减掉。现在的思路是修改特效的shader,给shader传一个值,记录scrollview四个边在世界坐标的位置,然后在显示的时候判断是否在框内,若不在则隐藏。

首先先处理shader这块,为了不影响其他的特效。可以把需要修改的shader都复制一份重命名。(我这边的处理是 a.shader 复制成 a 1.shader )下面的代码是在原本shader的基础上进行的修改,修改处注释已标出。

Shader:

Shader "PJ Particles/PJ Additive 1" {
	Properties {
		_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
		_MainTex ("Particle Texture (A = Transparency)", 2D) = "white" {}
		_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
		
		//新增 记录裁剪框的四个边界的值
		_Area ("Area", Vector) = (0,0,1,1)
		//----end----
	}

	Category {
		Tags { "Queue"="Transparent+300" "IgnoreProjector"="True" "RenderType"="Transparent" }
		Blend SrcAlpha One
		AlphaTest Greater .01
		ColorMask RGB
		Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }
		BindChannels {
			Bind "Color", color
			Bind "Vertex", vertex
			Bind "TexCoord", texcoord
		}
		
		SubShader {
			Pass {
			
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#pragma fragmentoption ARB_precision_hint_fastest
				#pragma multi_compile_particles
	
				#include "UnityCG.cginc"
	
				sampler2D _MainTex;
				fixed4 _TintColor;
	
				//新增,对应上面的_Area
				float4 _Area;
				//----end----
				
				struct appdata_t {
					float4 vertex : POSITION;
					fixed4 color : COLOR;
					float2 texcoord : TEXCOORD0;
				};
	
				struct v2f {
					float4 vertex : POSITION;
					fixed4 color : COLOR;
					float2 texcoord : TEXCOORD0;
					//新增,记录顶点的世界坐标
					float2 worldPos : TEXCOORD1;
					//----end----
				};
				
				float4 _MainTex_ST;
	
				v2f vert (appdata_t v)
				{
					v2f o;
					o.vertex = UnityObjectToClipPos(v.vertex);
					o.color = v.color;
					o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
					//新增,计算顶点的世界坐标
					o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
					//----end----
					return o;
				}
	
				sampler2D _CameraDepthTexture;
				float _InvFade;
				
				fixed4 frag (v2f i) : COLOR
				{
					//新增,判断顶点坐标是否在裁剪框内
					bool inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w;
					//----end----

					//如果在裁剪框内return原本的效果,否则即隐藏
	                return inArea? 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord) : fixed4(0,0,0,0);
				}
				ENDCG 
			}
		} 
	}
}

shader处理好后,接下来要做的就是将UI特效里面所有的shader都替换成新的。可以写一个脚本,挂在UI特效上,然后再Start里面替换好shader然后计算出裁剪框(UGUI的ScrollView或NGUI的UIPanel,等)的四个边界的世界坐标。最后将这个值传给新的shader即可。代码如下,用的UGUI的ScrollView。当然NGUI的思路也是一样样的:

Unity:

using System.Collections.Generic;
using UnityEngine;

namespace UI {

	public class EffectClip : MonoBehaviour {

        [SerializeField] RectTransform m_rectTrans;//遮挡容器,即ScrollView

        List<Material> m_materialList = new List<Material>();//存放需要修改Shader的Material
        Transform m_canvas;//UI的根,Canvas
        float m_halfWidth, m_halfHeight, m_canvasScale;

        void Start () {
            m_canvas = GameObject.Find("Canvas").transform;

            //获取所有需要修改shader的material,并替换shader
            var particleSystems = GetComponentsInChildren<ParticleSystem>();
            for(int i = 0, j = particleSystems.Length; i < j ; i++) {
                var ps = particleSystems[i];
                var mat = ps.GetComponent<Renderer>().material;
                m_materialList.Add(mat);
                mat.shader = Shader.Find(mat.shader.name + " 1");
            }

            var renders = GetComponentsInChildren<MeshRenderer>();
            for(int i = 0, j = renders.Length; i < j; i++) {
                var ps = renders[i];
                var mat = ps.material;
                m_materialList.Add(mat);
                mat.shader = Shader.Find(mat.shader.name + " 1");
            }

            //获取UI的scale,容器的宽高的一半的值
            m_canvasScale = m_canvas.localScale.x;
            m_halfWidth = m_rectTrans.sizeDelta.x * 0.5f * m_canvasScale;
            m_halfHeight = m_rectTrans.sizeDelta.y * 0.5f * m_canvasScale;

            //给shader的容器坐标变量_Area赋值
            Vector4 area = CalculateArea(m_rectTrans.position);
            for(int i = 0, len = m_materialList.Count; i < len; i++) {
                m_materialList[i].SetVector("_Area", area);
            }
        }

        //计算容器在世界坐标的Vector4,xz为左右边界的值,yw为下上边界值
        Vector4 CalculateArea(Vector3 position) {
            return new Vector4() {
                x = position.x - m_halfWidth,
                y = position.y - m_halfHeight,
                z = position.x + m_halfWidth,
                w = position.y + m_halfHeight
            };
        }
    }
}

最后将脚本挂上所有的UI特效上后:运行看到如下的效果,多余的已被裁剪:


  • 4
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要实现Unity UGUI中的ScrollView滑动居中放大,其他的缩小,可以按照以下步骤进行操作: 1. 创建一个ScrollView,用于显示内容,并设置合适的大小和位置。 2. 在ScrollView中创建一个Content对象,用于放置所有需要显示的子对象,并设置Layout Group组件,以确保内容按照一定的布局排列。 3. 在每个子对象上添加一个自定义的脚本,用于控制子对象的缩放和位置。脚本中需要包含以下几个要点: a. 监听ScrollView的滑动事件,获取当前的滑动位置。 b. 根据当前滑动位置,计算每个子对象在滑动过程中应该设置的缩放比例。例如,距离居中的子对象应该更大,而距离边缘的子对象应该更小。 c. 根据计算得到的缩放比例,分别对每个子对象进行缩放设置。可以使用RectTransform的scale属性来实现缩放功能。 d. 根据子对象的缩放比例和位置信息,将子对象移动到ScrollView的合适位置。可以使用RectTransform的anchoredPosition属性来实现位置调整。 e. 可以根据需要,在脚本中添加其他的功能,例如点击子对象时的反应等。 4. 将自定义的脚本添加到所有的子对象上,确保每个子对象都能根据滑动进行缩放和位置调整。 通过以上步骤,我们可以实现在Unity UGUI中的ScrollView滑动过程中,距离居中的子对象放大,而距离边缘的子对象缩小的效果。具体的缩放比例和位置调整可以根据实际需求进行调整。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值