【游戏】UI层粒子特效存在的问题及解决方案

2021-04-02
2598
0

一,UI层粒子特效存在的问题

 

1.粒子特效的裁剪问题。某种滑动出滚动列表后被裁剪

 

2.粒子特效与UI元素之间的层级问题。能够被某些UI元素遮盖,或夹在某些UI元素之间

 

3.粒子特效的适应问题。在不同分辨率下粒子特效不能像UI一样自动适应

 

这些问题所有人都遇到过,解决方案也是多种多样,本博客提出一个统一的解决方案,能够同时解决以上3个问题。

二,解决方案

自己实现一套UI层的粒子系统,即粒子系统发射的每个粒子都是一个UI元素,这样就可以不用做任何事情,以上问题就可以迎刃而解。

废话不多说,直接上代码:

使用UnityEngine; 
使用UnityEngine.UI;

/// <summary> 
///由ggr在2018/07/30添加
//// UI层的粒子特效,能解决的问题:
/// 1,粒子特效在滚动列表区外裁剪
//// 2,粒子特效层级调整,即可以在夹在任意两个UI元素之间
/// 3,不同分辨率的适应
/// /使用:
///主要是特效的美术人员使用。/// 
1,在粒子系统的物体上挂上这个脚本
/// 2,此时会替换和清空粒子系统的渲染器模块
/// 3,把材质球拖到脚本上的材质顶部上
/// </ summary> 
[ExecuteInEditMode ]

[RequireComponent(typeof(CanvasRenderer),typeof(ParticleSystem))]公共类UIParticleSystem:MaskableGraphic {[Tooltip(“勾上这个,会把粒子系统放在LateUpdate里运行”)] public bool fixedTime = true; [Range(1,60)] public int maxParticleCount = 15;

    private Transform _transform; 
    专用ParticleSystem pSystem;
    私有ParticleSystem.Particle []粒子;
    私有UIVertex [] _quad =新的UIVertex [4]; 
    私有Vector4 imageUV = Vector4.zero; 
    私有ParticleSystem.TextureSheetAnimationModule textureSheetAnimation; 
    私人诠释textureSheetAnimationFrames; 
    私有Vector2 textureSheetAnimationFrameSize; 
    专用的ParticleSystemRenderer pRenderer;

    私人物质当前材料;

    private Texture currentTexture;

    私有ParticleSystem.MainModule mainModule;

    公共重写Texture mainTexture { 
        get { 
            return currentTexture; 
        } 
    }

    受保护的布尔Initialize(){

        如果(_transform == null){_ 
            transform =变换;
        } 
        if(pSystem == null){ 
            pSystem = GetComponent <ParticleSystem>();

            if(pSystem == null){
                返回false; 
            }

            mainModule = pSystem.main;

            如果(pSystem.main.maxParticles> maxParticleCount){ 
                mainModule.maxParticles = maxParticleCount; 
            }

            pRenderer = pSystem.GetComponent <ParticleSystemRenderer>(); 
            如果(pRenderer!= null){ 
                pRenderer.material = null; 
                pRenderer.enabled = false; 
            }

            currentMaterial =材料;
            如果(currentMaterial && currentMaterial.HasProperty(“ _ MainTex”)){ 
                currentTexture = currentMaterial.mainTexture; 
                如果(currentTexture == null)currentTexture = Texture2D.whiteTexture; 
            } 
            material = currentMaterial;

            mainModule.scalingMode = ParticleSystemScalingMode.Hierarchy;

            粒子= null; 
        }
        如果(粒子==空)粒子=新的ParticleSystem.Particle [pSystem.main.maxParticles];

        imageUV =新的Vector4(0,0,1,1);

        textureSheetAnimation = pSystem.textureSheetAnimation; 
        textureSheetAnimationFrames = 0; 
        textureSheetAnimationFrameSize = Vector2.zero; 
        如果(textureSheetAnimation.enabled){ 
            textureSheetAnimationFrames = textureSheetAnimation.numTilesX * textureSheetAnimation.numTilesY; 
            textureSheetAnimationFrameSize = new Vector2(1f / textureSheetAnimation.numTilesX,1f / textureSheetAnimation.numTilesY); 
        }

        返回true;
    }

    受保护的重写void Awake(){ 
        base.Awake(); 
        如果(!Initialize())enabled = false;

        raycastTarget = false; 
    }

    受保护的重写void OnPopulateMesh(VertexHelper vh){#
        如果为UNITY_EDITOR,
        如果(!Application.isPlaying){
            如果(!Initialize()){
                返回;
            } 
        } #ENDIF

        vh.Clear();

        如果(!gameObject.activeInHierarchy){
            返回; 
        }

        Vector2 temp = Vector2.zero; 
        Vector2 corner1 = Vector2.zero; 
        Vector2 corner2 = Vector2.zero;

        int count = pSystem.GetParticles(particles);

        for(int i = 0; i <count; i){
            粒子系统。粒子粒子=粒子[i];

            Vector2位置=(mainModule.simulationSpace == ParticleSystemSimulationSpace.Local?Particle.position:_transform.InverseTransformPoint(particle.position)); 
            浮点旋转= -particle.rotation * Mathf.Deg2Rad; 
            浮点旋转90 =旋转Mathf.PI / 2; 
            Color32 color =粒子.GetCurrentColor(pSystem); 
            浮点尺寸=粒子.GetCurrentSize(pSystem)* 0.5f;

            如果(mainModule.scalingMode == ParticleSystemScalingMode.Shape)position / = canvas.scaleFactor;

            Vector4粒子UV =图像UV; 
            如果(textureSheetAnimation.enabled){ 
                float frameProgress = 1-(particle.remainingLifetime / particle.startLifetime);

                如果(textureSheetAnimation.frameOverTime.curveMin!= null){ 
                    frameProgress = textureSheetAnimation.frameOverTime.curveMin.Evaluate(1-(particle.remainingLifetime / particle.startLifetime)); 
                }否则if(textureSheetAnimation.frameOverTime.curve!= null){ 
                    frameProgress = textureSheetAnimation.frameOverTime.curve.Evaluate(1-(particle.remainingLifetime / particle.startLifetime));; 
                }否则if(textureSheetAnimation.frameOverTime.constant> 0){ 
                    frameProgress = textureSheetAnimation.frameOverTime.constant-(particle.remainingLifetime / particle.startLifetime); 
                }

                frameProgress = Mathf.Repeat(frameProgress * textureSheetAnimation.cycleCount,1); 
                int帧= 0;

                开关(textureSheetAnimation.animation){

                案例ParticleSystemAnimationType.WholeSheet:
                    frame = Mathf.FloorToInt(frameProgress * textureSheetAnimationFrames); 
                    休息;

                案例ParticleSystemAnimationType.SingleRow:
                    frame = Mathf.FloorToInt(frameProgress * textureSheetAnimation.numTilesX);

                    int row = textureSheetAnimation.rowIndex; 
                    框架=行* textureSheetAnimation.numTilesX; 
                    休息;

                }

                框架%= textureSheetAnimationFrames;

                particleUV.x =(帧%textureSheetAnimation.numTilesX)* textureSheetAnimationFrameSize.x; 
                particleUV.y = Mathf.FloorToInt(frame / textureSheetAnimation.numTilesX)* textureSheetAnimationFrameSize.y; 
                particleUV.z =粒子UV.x textureSheetAnimationFrameSize.x; 
                particleUV.w =粒子UV.y textureSheetAnimationFrameSize.y; 
            }

            temp.x =粒子UV.x; 
            temp.y =粒子UV.y;

            _quad [0] = UIVertex.simpleVert; 
            _quad [0] .color =颜色;
            _quad [0] .uv0 = temp;

            temp.x =粒子UV.x; 
            temp.y =粒子UV.w; 
            _quad [1] = UIVertex.simpleVert; 
            _quad [1] .color =颜色;
            _quad [1] .uv0 = temp;

            temp.x =粒子UV.z; 
            temp.y =粒子UV.w; 
            _quad [2] = UIVertex.simpleVert; 
            _quad [2] .color =颜色;
            _quad [2] .uv0 = temp;

            temp.x =粒子UV.z; 
            temp.y =粒子UV.y; 
            _quad [3] = UIVertex.simpleVert; 
            _quad [3] .color =颜色;
            _quad [3] .uv0 = temp;

            if(rotation == 0){

                corner1.x = position.x-大小;
                corner1.y = position.y-大小;
                corner2.x = position.x大小;
                corner2.y = position.y大小;

                temp.x = corner1.x; 
                temp.y = corner1.y; 
                _quad [0] .position = temp; 
                temp.x = corner1.x; 
                temp.y = corner2.y; 
                _quad [1] .position = temp; 
                temp.x = corner2.x; 
                temp.y = corner2.y; 
                _quad [2] .position = temp; 
                temp.x = corner2.x; 
                temp.y = corner1.y; 
                _quad [3] .position = temp; 
            } 别的 {

                右边的Vector2 =新的Vector2(Mathf.Cos(旋转),Mathf.Sin(旋转))*大小; 
                Vector2 up =新Vector2(Mathf.Cos(rotation90),Mathf.Sin(rotation90))*大小;

                _quad [0] .position =位置-右-上;
                _quad [1] .position =位置-右上;
                _quad [2] .position =右上角的位置;
                _quad [3] .position =位置右-向上;
            }

            vh.AddUIVertexQuad(_quad); 
        } 
    }

    void Update(){ 
        if(!fixedTime && Application.isPlaying){ 
            pSystem.Simulate(Time.unscaledDeltaTime,false,false,true); 
            SetAllDirty();

            if(((currentMaterial!= null && currentTexture!= currentMaterial.mainTexture)||(material!= null && currentMaterial!= null && material.shader!= currentMaterial.shader)){ 
                pSystem = null; 
                初始化(); 
            } 
        } 
    }

    void LateUpdate(){
        如果(!Application.isPlaying){ 
            SetAllDirty(); 
        } else { 
            if(fixedTime){ 
                pSystem.Simulate(Time.unscaledDeltaTime,false,false,true); 
                SetAllDirty(); 
                if(((currentMaterial!= null && currentTexture!= currentMaterial.mainTexture)||(material!= null && currentMaterial!= null && material.shader!= currentMaterial.shader)){ 
                    pSystem = null; 
                    初始化(); 
                } 
            } 
        }
        如果(材料== currentMaterial)回报; 
        pSystem = null; 
        初始化(); 
    }
}

 

还需要一个shader,这里我就直接拿的UI Default的shader,只是混合公式我改变成Blend SrcAlpha one,即粒子的重叠模式

 

代码:

 

着色器“ 17zuoye / UI粒子添加剂” {
    属性{ 
        _MainTex(“ Sprite Texture”,2D)=“ white” {} 
        _Color(“ Tint”,Color)=(0.5,0.5,0.5,0.5)

        _StencilComp(“模板比较”,浮点数)= 8 _Stencil(“模板ID”,浮点数)= 0 _StencilOp(“模板操作”,浮点数)= 0 _StencilWriteMask(“模板写屏蔽”,浮点数)= 255 _StencilReadMask(“ S掩码”,浮点数)= 255

        _ColorMask(“ Color Mask”,Float)= 15

        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip(“使用Alpha剪辑”,浮动)= 0 
    }

    SubShader {
        标签{ 
            “ Queue” =“ Transparent”“ IgnoreProjector” =“ True”“ RenderType” =“ Transparent”“ PreviewType” =“平面”“ CanUseSpriteAtlas” =“ True” 
        }

        模具{ 
            Ref [_Stencil] Comp [_StencilComp] Pass [_StencilOp] ReadMask [_StencilReadMask] WriteMask [_StencilWriteMask] 
        }

        取消照明关闭ZWrite Off ZTest [unity_GUIZTestMode]混合SrcAlpha一种ColorMask [_ColorMask]

        传递{
            名称“默认” CGPROGRAM#pragma顶点vert#pragma片段frag#pragma目标2.0

            #include“ UnityCG.cginc” #include“ UnityUI.cginc” // 2D Mask剪裁。
            #pragma multi_compile __ UNITY_UI_CLIP_RECT#pragma multi_compile __ UNITY_UI_ALPHACLIP

            struct appdata_t { 
                float4顶点:POSITION float4颜色:COLOR float2 texcoord:TEXCOORD0 UNITY_VERTEX_INPUT_INSTANCE_ID 
            }

            struct v2f { 
                float4顶点:SV_POSITION fixed4颜色:COLOR float2 texcoord:TEXCOORD0 float4 worldPosition:TEXCOORD1 UNITY_VERTEX_OUTPUT_STEREO 
            }

            fixed4 _Color fixed4 _TextureSampleAdd float4 _ClipRect

            v2f vert(appdata_t v){ 
                v2f OUT UNITY_SETUP_INSTANCE_ID(v)UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT)OUT.worldPosition = v.vertex OUT.vertex = UnityObjectToClipPos(OUT.worldPosition)

                OUT.texcoord = v.texcoord

                OUT.color = v.color 
                return OUT 
            }

            sampler2D _MainTex

            fixed4 frag(v2f IN):SV_Target { 
                fixed4 albedo = tex2D(_MainTex,IN.texcoord)

                fixed4 color = 2.0f * IN.color * _Color * albedo#ifdef UNITY_UI_CLIP_RECT color.a * = UnityGet2DClipping(IN.worldPosition.xy,_ClipRect)#endif

                #ifdef UNITY_UI_ALPHACLIP剪辑(color.a-0.001)#endif

                返回颜色
            }

            ENDCG 
        } 
    } 
}

 

 

三,验证


1,裁剪

 

2,层级

 

3,适应

 

四,使用

 

 

转载声明:本文涉及网络,不作任何商业用途。

免责声明:本文内部分内容来自网络,所涉绘画作品及文字版权与著作权归原作者,若有侵权或异议请联系我们处理。
收藏

全部评论

您还没登录

暂无留言,赶紧抢占沙发
绘学霸是国内专业的CG数字艺术设计线上线下学习平台,在绘学霸有2D绘画、3D模型、影视后期、动画、特效等数字艺术培训课程,也有学习资源下载,还有行业社区交流。学习、交流,来绘学霸就对了。
绘学霸iOS端二维码

IOS下载

绘学霸安卓端二维码

安卓下载

绘学霸微信小程序二维码

小程序

版权声明
本网站所有产品设计、功能及展示形式,均已受版权或产权保护,任何公司及个人不得以任何方式复制部分或全部,违者将依法追究责任,特此声明。
热线电话
18026259035
咨询时间:9:00~21:00
在线客服
联系网站客服
客服微信:18026259035
公司地址
中国·广州
广州市海珠区晓港中马路130号之19
绘学霸客户端(权限暂无,用于CG资源与教程交流分享)
开发者:广州王氏软件科技有限公司 | 应用版本:Android:6.0,IOS:5.1 | App隐私政策> | 应用权限 | 更新时间:2020.1.6