UGUI(ScrollView)范围内隐藏特效



示例:

这是一个ScrollView上的特效矩形遮挡,实现原理是修改特效的shader。

判断渲染的顶点坐标是否在可渲染的矩形范围呢,可以则在片元返回颜色透明度为0,不是则返回应有颜色。

这里不一定是矩形范围 ,圆形也行,需要自行编辑区域范围和判断顶点位置。先来讲讲矩形范围的UI上的特效遮挡的实现。







首先编辑特效:

如果是unity自带shader,可以网上copy源码,然后加入以下代码段,这里使用的shader是Additive,然后我们需要自己加入自己代码段。

先附上Additive源码:

Shader "Particles/Additive" {
 
Properties {
 
_TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
 
_MainTex ("Particle Texture", 2D) = "white" {}
 
_InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0
 
}
 
 
 
Category {
 
Tags { "Queue"="Transparent" "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
 
}
 
 
 
// ---- Fragment program cards
 
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;
 
 
 
struct appdata_t {
 
float4 vertex : POSITION;
 
fixed4 color : COLOR;
 
float2 texcoord : TEXCOORD0;
 
};
 
 
 
struct v2f {
 
float4 vertex : POSITION;
 
fixed4 color : COLOR;
 
float2 texcoord : TEXCOORD0;
 
#ifdef SOFTPARTICLES_ON
 
float4 projPos : TEXCOORD1;
 
#endif
 
};
 
 
 
float4 _MainTex_ST;
 
 
 
v2f vert (appdata_t v)
 
{
 
v2f o;
 
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
 
#ifdef SOFTPARTICLES_ON
 
o.projPos = ComputeScreenPos (o.vertex);
 
COMPUTE_EYEDEPTH(o.projPos.z);
 
#endif
 
o.color = v.color;
 
o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
 
return o;
 
}
 
 
 
sampler2D _CameraDepthTexture;
 
float _InvFade;
 
 
 
fixed4 frag (v2f i) : COLOR
{
 
#ifdef SOFTPARTICLES_ON
 
float sceneZ = LinearEyeDepth (UNITY_SAMPLE_DEPTH(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos))));
 
float partZ = i.projPos.z;
 
float fade = saturate (_InvFade * (sceneZ-partZ));
 
i.color.a *= fade;
 
#endif
 
 
 
return 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);
 
}
 
ENDCG
 
}
 
}
 
 
 
// ---- Dual texture cards
 
SubShader {
 
Pass {
 
SetTexture [_MainTex] {
 
constantColor [_TintColor]
 
combine constant * primary
 
}
 
SetTexture [_MainTex] {
 
combine texture * previous DOUBLE
 
}
 
}
 
}
 
 
 
// ---- Single texture cards (does not do color tint)
 
SubShader {
 
Pass {
 
SetTexture [_MainTex] {
 
combine texture * primary
 
}
 
}
 
}
 
}
 
}

然后我们创建一个新的shader在原有名字末尾加上Mask =》 AdditiveMask

在属性里加入框选的代码,这段代码是用于矩形区域判断的(也可以自己编辑圆的范围)

在片元着色阶段编辑修改成框选代码

 用于判断是否在矩形范围内,是则使用本身颜色,不是则透明化。

下面是完整代码。

// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)

Shader "Legacy Shaders/Particles/AdditiveMask" {
Properties {
    _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
    _MainTex ("Particle Texture", 2D) = "white" {}
    _InvFade ("Soft Particles Factor", Range(0.01,3.0)) = 1.0

    // add 记录裁剪框的四个边界的值
	_Area ("Area", Vector) = (0,0,1,1)
	//----end----

   //MASK SUPPORT ADD
    _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
    //MASK SUPPORT END

}

Category {
    Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" "PreviewType"="Plane" }
    Blend SrcAlpha One
    ColorMask RGB
    Cull Off Lighting Off ZWrite Off

    SubShader {

        //MASK SUPPORT ADD

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

        //MASK SUPPORT END

        Pass {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma target 2.0
            #pragma multi_compile_particles
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            sampler2D _MainTex;
            fixed4 _TintColor;

            //新增,对应上面的_Area
			float4 _Area;
			//----end----

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

            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                UNITY_FOG_COORDS(1)
                #ifdef SOFTPARTICLES_ON
                float4 projPos : TEXCOORD2;
                #endif
                UNITY_VERTEX_OUTPUT_STEREO

                //新增,记录顶点的世界坐标
				float2 worldPos : TEXCOORD3;
				//----end----
            };

            float4 _MainTex_ST;

            v2f vert (appdata_t v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.vertex = UnityObjectToClipPos(v.vertex);
                #ifdef SOFTPARTICLES_ON
                o.projPos = ComputeScreenPos (o.vertex);
                COMPUTE_EYEDEPTH(o.projPos.z);
                #endif
                o.color = v.color;
                o.texcoord = TRANSFORM_TEX(v.texcoord,_MainTex);
                UNITY_TRANSFER_FOG(o,o.vertex);

	            //新增,计算顶点的世界坐标
				o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
				//----end----

                return o;
            }

            UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);
            float _InvFade;

            fixed4 frag (v2f i) : SV_Target
            {
                #ifdef SOFTPARTICLES_ON
                float sceneZ = LinearEyeDepth (SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)));
                float partZ = i.projPos.z;
                float fade = saturate (_InvFade * (sceneZ-partZ));
                i.color.a *= fade;
                #endif

                fixed4 col = 2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);
                col.a = saturate(col.a); // alpha should not have double-brightness applied to it, but we can't fix that legacy behavior without breaking everyone's effects, so instead clamp the output to get sensible HDR behavior (case 967476)

                UNITY_APPLY_FOG_COLOR(i.fogCoord, col, fixed4(0,0,0,0)); // fog towards black due to our blend mode

                //新增,判断顶点坐标是否在裁剪框内
				bool inArea = i.worldPos.x >= _Area.x && i.worldPos.x <= _Area.z && i.worldPos.y >= _Area.y && i.worldPos.y <= _Area.w;
				//----end----

                return inArea ? col : fixed4(0,0,0,0);
            }
            ENDCG
        }
    }
}
}

所有需要被遮挡的shader都需要被重新编辑。






编辑修改特效shader的脚本:

需要添加获取整体替换特效中shader的脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ParticleMask : MonoBehaviour
{
    [SerializeField] RectTransform m_rectTrans;//遮挡容器,即ScrollView

    List<Material> m_materialList = new List<Material>();//存放需要修改Shader的Material

    public bool isStart = false;
    public bool isEnable = false;
    public bool isDelay = false;
    public float delayTime = 0.5f;

    

    void Start()
    {
        if (!isEnable)
        {
            if (isDelay)
            {
                Invoke(nameof(Delay), delayTime);
                if (isStart)
                {
                    InitParticleMask(gameObject);
                }
            }
            else
            {
                InitParticleMask(gameObject);
            }
        }

        
    }

    private void OnEnable()
    {
        if (isEnable)
        {
            if (isDelay)
            {
                Invoke(nameof(Delay), delayTime);
            }
            else
            {
                InitParticleMask(gameObject);
            }
          
        }
    }

    private void Delay()
    {
        InitParticleMask(gameObject);
    }

    /// <summary>
    /// 添加新的item
    /// </summary>
    /// <param name="obj"></param>
    public void AddNewItem(GameObject obj)
    {
        InitParticleMask(obj);
    }

    private void InitParticleMask(GameObject parent)
    {
        //获取所有需要修改shader的material,并替换shader
        var particleSystems = parent.GetComponentsInChildren<ParticleSystem>(true);
        for (int i = 0, j = particleSystems.Length; i < j; i++)
        {
            var ps = particleSystems[i];
            var mat = ps.GetComponent<Renderer>().material;
            if (mat.shader.name.Contains("Mask"))
                continue;

            if (!m_materialList.Contains(mat))
                m_materialList.Add(mat);
            if (!mat.shader.name.Contains("Mask"))
                mat.shader = Shader.Find(mat.shader.name + "Mask");

            TrailRenderer tRender = ps.GetComponent<TrailRenderer>();
            if (tRender != null)
            {
                var tmat = tRender.material;
                if (tmat != null)
                {
                    if (!m_materialList.Contains(mat))
                        m_materialList.Add(mat);
                    if (!mat.shader.name.Contains("Mask"))
                        mat.shader = Shader.Find(mat.shader.name + "Mask");
                }
            }
        }

        var renders = parent.GetComponentsInChildren<MeshRenderer>(true);
        for (int i = 0, j = renders.Length; i < j; i++)
        {
            var ps = renders[i];
            var mat = ps.material;

            if(!m_materialList.Contains(mat))
                m_materialList.Add(mat);
            if (!mat.shader.name.Contains("Mask"))
                mat.shader = Shader.Find(mat.shader.name + "Mask");
        }

        var canvasMasks = parent.GetComponentsInChildren<CanvasMask>(true);
        for (int i = 0, j = canvasMasks.Length; i < j; i++)
        {
            var ps = canvasMasks[i];
            var mat = ps.mat;
            if (mat == null)
            {
                ps.Init();
            }
            if (mat == null)
                continue;
            if (!m_materialList.Contains(mat))
                m_materialList.Add(mat);
            if (!mat.shader.name.Contains("Mask"))
                mat.shader = Shader.Find(mat.shader.name + "Mask");
        }

        Vector3[] corners = new Vector3[4];
        m_rectTrans.GetWorldCorners(corners);
        Vector4 area = new Vector4(corners[0].x, corners[0].y, corners[2].x, corners[2].y);

        for (int i = 0, len = m_materialList.Count; i < len; i++)
        {
            m_materialList[i].SetVector("_Area", area);
        }
    }
}

将这个脚本挂载在 需要遮挡的特效的父物体上 

我这里将他挂在同时遮挡ui的UI上。它会将自己的世界位置的四个顶点传入shader中。

这样就可以实现同时遮挡UI和遮挡3d物体的功能了。


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

bubblingo0

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值