Mask裁切UI粒子特效或者3D模型

发表于2017-08-09
评论0 3.5k浏览
刚好前几天有人问我Mask裁切UI粒子特效或者3D模型这个问题,再加上新项目也可能用,所以这两天就研究了一下。其实如果粒子特效 和3D模型 都用RenderTexture来做的话就不会有裁切的问题,但是粒子特效用RenderTexture来做会有显示的问题,所以还是得用摄像机。废话不多说了,进入正题。

原理就是把Mask的裁切区域传给粒子特效Shader,当超出这个区域那么直接让它完全透明即可。粒子特效的源生shader大家可以去unity官网下载,我在这里把需要修改的地方标注给大家。

//add 注释中的内容就是我做修改的地方。
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
    //-------------------add----------------------
      _MinX ("Min X", Float) = -10
      _MaxX ("Max X", Float) = 10
      _MinY ("Min Y", Float) = -10
      _MaxY ("Max Y", Float) = 10
      //-------------------add----------------------
}
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) }
    SubShader {
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_particles
            #include "UnityCG.cginc"
            sampler2D _MainTex;
            fixed4 _TintColor;
            //-------------------add----------------------
            float _MinX;
            float _MaxX;
            float _MinY;
            float _MaxY;
            //-------------------add----------------------
            struct appdata_t {
                float4 vertex : POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
                fixed4 color : COLOR;
                float2 texcoord : TEXCOORD0;
                #ifdef SOFTPARTICLES_ON
                float4 projPos : TEXCOORD1;
                #endif
                //-------------------add----------------------
                float3 vpos : TEXCOORD2;
                //-------------------add----------------------
            };
            float4 _MainTex_ST;
            v2f vert (appdata_t v)
            {
                v2f o;
                //-------------------add----------------------
                o.vpos = v.vertex.xyz;
                //-------------------add----------------------
                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_float _CameraDepthTexture;
            float _InvFade;
            fixed4 frag (v2f i) : SV_Target
            {
                #ifdef SOFTPARTICLES_ON
                floatsceneZ = 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
                //-------------------add----------------------
                 fixed4 c =2.0f * i.color * _TintColor * tex2D(_MainTex, i.texcoord);
                 c.a *= (i.vpos.x >= _MinX );
                 c.a *= (i.vpos.x <= _MaxX);
                 c.a *= (i.vpos.y >= _MinY);
                 c.a *= (i.vpos.y <= _MaxY);
                 c.rgb *= c.a;
                return c;
                //-------------------add----------------------
            }
            ENDCG
        }
    }  
}
}

然后是自己写了个类继承Mask。把Mask的区域传给shader。
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class MyMask :Mask
{
    protected override void Start ()
    {
        base.Start ();
        int width = Screen.width;
        int height = Screen.height;
        int designWidth = 960;//开发时分辨率宽
        int designHeight = 640;//开发时分辨率高
        float s1 = (float)designWidth / (float)designHeight;
        float s2 = (float)width / (float)height;
        //目标分辨率小于 960X640的 需要计算缩放比例
        float contentScale =1f;
         if(s1 > s2) {
            contentScale = s1/s2;
        }
        Canvas  canvas = GameObject.Find("Canvas").GetComponent
        Vector2 pos;
        if(RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform asRectTransform, transform.position, canvas.camera, out pos)){
            ParticleSystem  [] particlesSystems  = transform.GetComponentsInChildren();
            RectTransform rectTransform = transform as RectTransform;
            float minX,minY,maxX,maxY;
            minX = rectTransform.rect.x    pos.x;
            minY = rectTransform.rect.y  pos.y;
            maxX = minX   rectTransform.rect.width ;
            maxY = minY   rectTransform.rect.height;
            //这里 100  是因为ugui默认的缩放比例是100  你也可以去改这个值,但是我觉得最好别改。
            foreach(ParticleSystem particleSystem in particlesSystems)
            {
                particleSystem.renderer.sharedMaterial.SetFloat("_MinX",minX/100/contentScale);
                particleSystem.renderer.sharedMaterial.SetFloat("_MinY",minY/100/contentScale);
                particleSystem.renderer.sharedMaterial.SetFloat("_MaxX",maxX/100/contentScale);
                particleSystem.renderer.sharedMaterial.SetFloat("_MaxY",maxY/100/contentScale);
            }
        }
    }
}

OK,把粒子特效直接挂在Mask下面, 就可以进行裁切了。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: