Unity粒子特效裁剪(基于NGUI的shader裁剪实现)

这几天总结一下之前遇到的有意思的问题,之前遇到的时候没时间总结,现在就总结一下。
首先说一下关于特效的裁剪应用的场景主要是scrollview中,当scrollview中的物体超出UIPannel的范围NGUI会对超出的部分的UI进行裁切,其原理是将UIPannel的裁剪区域传递给其自带裁剪shader对超出区域的像素透明度设为完全透明,但是并不会作用于粒子特效,所以会出现拖拽UI控件至超出边界的时候UI被裁减但是特效依然存在。具体大概是这样:
在这里插入图片描述
(新的电脑没有装NGUI,就先用UGUI搭一下。。。)可以看到当UI超出边界的时候挂在UI下的粒子特效并没有是随着UI裁剪。
那么就说一下解决思路把,首先在脚本中拿到当前的Pannel的裁剪区域,通过裁剪区域算出上下左右四个边界值,再乘以分辨率的缩放传递给shader处理。在shader中的处理就很简单了,顶点着色器就是变换顶点至世界坐标,在片元处理器中比较顶点位置是否在裁剪区域,如果不再就不渲染。
c#代码如下 :

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

[RequireComponent(typeof(UIPanel))]
public class ParticleSystemClipper : MonoBehaviour
{
    UIPanel m_targetPanel=null;
    private UIRoot _uiRoot=null;
    bool inited = false;
    Vector4 _clipArea;
    void Init()
    {
        if(inited)
        {           
            return;
        }

        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");
        _uiRoot = NGUITools.FindInParents<UIRoot>(gameObject);
        if (_uiRoot == null)
            _uiRoot = DlgMgr.Instance.uiRoot;
    }
    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
        };


        Vector3 worldClipXY = m_targetPanel.transform.TransformPoint(nguiArea.x, nguiArea.y, 0);
        Vector3 worldClipZW = m_targetPanel.transform.TransformPoint(nguiArea.z, nguiArea.w, 0);

        return new Vector4()
        {
            x = worldClipXY.x ,
            y = worldClipXY.y ,
            z = worldClipZW.x ,
            w = worldClipZW.y
        };
    }

    ParticleSystem[] _particleAry = null;
    public void ExecuteClip(bool reCaulClipRegion=false)
    {
        Init();
        _particleAry = this.GetComponentsInChildren<ParticleSystem>();
        if (_particleAry == null || _particleAry.Length == 0)
        {
            return;
        }

        if (!inited)
        {
            //控制粒子的缩放
            float designWidth = 1280;//开发时分辨率宽
            float designHeight = 720;//开发时分辨率高
            float designScale = designWidth / designHeight;
            float scaleRate = (float)Screen.width / (float)Screen.height;
            float scaleFactor = scaleRate / designScale;
            for (int i = 0; i < _particleAry.Length; i++)
            {
                ParticleSystem ps = _particleAry[i];
                ps.transform.localScale *= scaleFactor;
            }
        }

        if (!inited || reCaulClipRegion)//在初始化或者需要时刻更新的的时候计算裁剪区
        {
            _clipArea = CalcClipArea();
        }

        inited = true;

        for (int i = 0; i < _particleAry.Length; i++)
        {
            ParticleSystem ps = _particleAry[i];

            Material mat = ps.GetComponent<Renderer>().material;
            if (!mat.shader.name.Contains("Clip"))
            {
                string name = mat.shader.name + "Clip";
                mat.shader = ShaderMgr.Instance.Find(name);
            }
            mat.SetVector("_Clip", _clipArea);
        }
    }
}

shader代码如下:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Miyoo/Particles/AdditiveClip" {
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
    _Clip ("Clip", Vector) = (0,0,1,1)
    //Curved World
	[CurvedWorldLabel] V_CW_Label_UnityDefaults("Curved World Optionals", float) = 0

	[Toggle] V_CW_PARTICLE_SYSTEM ("Use With Particle System", Float) = 0	
}

Category {
	Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"  "Reflection" = "RenderReflectionTransparentBlend" "CurvedWorldTag"="Particles/Additive" "CurvedWorldNoneRemoveableKeywords"="" "CurvedWorldAvailableOptions"=" " "PreviewType"="Plane"}
	Blend SrcAlpha One
	ColorMask RGB
	Cull Off Lighting Off ZWrite Off
	
	SubShader {
		Pass {
		
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 2.0
			#pragma multi_compile_particles

			#include "UnityCG.cginc"

			#pragma multi_compile V_CW_PARTICLE_SYSTEM_OFF V_CW_PARTICLE_SYSTEM_ON
			#include "../../VacuumShaders/Curved World/Shaders/cginc/CurvedWorld_Base.cginc"			
			
			sampler2D _MainTex;
			fixed4 _TintColor;
			fixed4 _Clip;
			struct appdata_t {
				float4 vertex : POSITION;
				fixed4 color : COLOR;
				float2 texcoord : TEXCOORD0;
			};

			struct v2f {
				float4 vertex : SV_POSITION;
				fixed4 color : COLOR;
				float2 texcoord : TEXCOORD0;
                half2 worldPos : TEXCOORD1;
				#ifdef SOFTPARTICLES_ON
				float4 projPos : TEXCOORD2;
				#endif
			};
			
			float4 _MainTex_ST;

			v2f vert (appdata_t v)
			{
				v2f o;
				
				UNITY_INITIALIZE_OUTPUT(v2f,o); 


				V_CW_TransformPoint(v.vertex);		
				
				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);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex).xy;
				return o;
			}

			sampler2D_float _CameraDepthTexture;
			float _InvFade;
			
			fixed4 frag (v2f i) : SV_Target
			{
                bool inArea = i.worldPos.x >= _Clip.x && i.worldPos.x <= _Clip.z && i.worldPos.y >= _Clip.y && i.worldPos.y <= _Clip.w;
                if(!inArea)
                {
                    return fixed4(0,0,0,0);
                }
                
				#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);
				return col;
			}
			ENDCG 
		}
	}	
}
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值