0
点赞
收藏
分享

微信扫一扫

Unity ListView 中滑动特效无法剪切问题

云上笔记 2021-10-15 阅读 89
Unity

C#脚本 (挂载到list下面)

作用:替换特效中使用的shader,将Scroll滑动范围传入Shader中。
缺陷:特效中使用的是特殊定制的shader,替换之后会导致特效损坏。

using System;
using UnityEngine;

namespace ParticleSytem
{
    [RequireComponent(typeof(UIPanel))]
    public class ParticleSystemClipper : MonoBehaviour
    {
        //自命名的Shader名(下文)
        const string ShaderName = "Mobile/Particles/Clip Blended";
        const float ClipInterval = 0.5f;

        UIPanel m_targetPanel; //滑动Scroll 上的目标Panel
        Shader m_shader;

        void Start()
        {
            // find panel
            m_targetPanel = GetComponent<UIPanel>();

            if (m_targetPanel == null)
                throw new ArgumentNullException("Cann't find the right UIPanel");
            if (m_targetPanel.clipping != UIDrawCall.Clipping.SoftClip)
                throw new InvalidOperationException("Don't need to clip");
            //获取Shader
            m_shader = Shader.Find(ShaderName);

            if (!IsInvoking("Clip"))
                InvokeRepeating("Clip", 0, ClipInterval);
        }

        Vector4 CalcClipArea()
        {
            var clipRegion = m_targetPanel.finalClipRegion;
            Vector4 nguiArea = new Vector4()
            {
                x = clipRegion.x - clipRegion.z / 2,
                y = clipRegion.y - clipRegion.w / 2,
                z = clipRegion.x + clipRegion.z / 2,
                w = clipRegion.y + clipRegion.w / 2
            };
            // 获取游戏根节点 (使用自己项目的根节点)
            var uiRoot = GameObject.Find("loadingRoot").GetComponent<UIRoot>();
            var pos = m_targetPanel.transform.position - uiRoot.transform.position;
            float h = 2;
            float temp = h / uiRoot.manualHeight;

            return new Vector4()
            {
                x = pos.x + nguiArea.x * temp,
                y = pos.y + nguiArea.y * temp,
                z = pos.x + nguiArea.z * temp,
                w = pos.y + nguiArea.w * temp
            };
        }

        void Clip()
        {
            Vector4 clipArea = CalcClipArea();
            var particleSystems = this.GetComponentsInChildren<ParticleSystem>();

            for (int i = 0; i < particleSystems.Length; i++)
            {
                var ps = particleSystems[i];
                var mat = ps.GetComponent<Renderer>().material;
                 //替换Shader
                if (mat.shader.name != ShaderName)
                    mat.shader = m_shader;

                mat.SetVector("_Area", clipArea);
            }
        }

        void OnDestroy()
        {
            CancelInvoke("Clip");
        }
    }
}

Shader 文件

原理:根据传入的范围,内部正常显示,范围外则不显示。

Shader "Mobile/Particles/Clip Blended" {
Properties
    {
        _Color("Color",Color)= (1,1,1,1)
        _MainTex ("Particle Texture", 2D) = "white" {}
        _Area ("Area", Vector) = (0,0,1,1)
    }

    Category
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
        Blend SrcAlpha OneMinusSrcAlpha
        //AlphaTest Greater .01
        //ColorMask RGB
        Cull Off
        Lighting Off
        ZWrite Off
        Fog { Color (0,0,0,0) }
        
        SubShader 
        {
            Pass
            {
                
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma multi_compile_particles

                #include "UnityCG.cginc"
                
        
                sampler2D _MainTex;
                float4 _Area;
                
                struct appdata_t
                {
                    float4 vertex : POSITION;
                    fixed4 color : COLOR;
                    float2 texcoord : TEXCOORD0;
                };

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

                v2f vert (appdata_t v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);
                    o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
                    o.color = v.color;
                    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
                    return o;
                }

                fixed4 frag (v2f i) : SV_Target
                {
                    bool inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w;
                    clip(inArea ? 1 : -1);
                    return i.color * tex2D(_MainTex, i.texcoord);
                }
                
                ENDCG 
            }
        }    
    }
}

总结:暂时可以实现普通方式特效的滑动裁切。局限性也很明显,需要有更好的方案改进。

举报

相关推荐

0 条评论