unity - UGUI 上使用 Particle System 带Mask功能,解决方案:绕过 Canvas.RenderSubBatch 之后 stencil buffer 被重置的问题


先是在:Unity开发从看懂到看开 文章中看到了一些 unity 的坑点

我也是忍不住发了两个吐槽点:
在这里插入图片描述

其中 unity - UGUI Canvas.RenderSubBatch 之后 stencil buffer 被重置了 的问题我也遇到了

导致部分 particle system 的 stencil 配置后的效果不对

偶然查看到另一篇博主以前写过:Unity GUI(uGUI)使用心得与性能总结,果然 cavnas batch,或是使用 Mask, RectMask2D,等等,都会再包括再最后的尾部的 UI 绘制时清理 stencil buffer 的内容

在这里插入图片描述


解决方式

用一个 SpriteRenderer 设置好 sortingOrder 保证在 CanvasRenderSubBatch 之后,particle system 之前写入 stencil buffer 1,后续的 particle system 的 mask 效果看起来才有效,但是需要将这个 SpriteRenderer 的位置、大小都要调整到与 UGUI ScrollView 对应的位置上


优化

这个方法已经应用于实际项目

但是在不同分辨率下,这个 SpriteRenderer 的方法就不好去控制对应分辨率下的大小了

所以我使用了自定义的网格组件对象(CustomQuadMesh)来替代 SpriteRenderer

该自定义的网格组件如下:

using System;
using UnityEngine;

public class CustomQuadMesh : MonoBehaviour
{
    public GetUguiRectWPos wposCom;
    private Mesh mesh;
    private Vector3[] lastVectices;
    private void Start()
    {
        lastVectices = new Vector3[4];
    }
    private void LateUpdate()
    {
        var vertices = wposCom.vectices;
        bool changed = false;
        for (int i = 0; i < 4; i++)
        {
            if (!lastVectices[i].Equals(vertices[i]))
            {
                changed = true;
                break;
            }
        }

        if (changed)
        {
            Array.Copy(vertices, lastVectices, 4);
            if (mesh == null)
            {
                // new mesh
                mesh = new Mesh();

                // vertices
                mesh.vertices = vertices;

                // indices
                mesh.triangles = new int[6]
                {
                0, 1, 2,
                0, 2, 3
                };

                mesh.UploadMeshData(false);

                var mf = GetComponent<MeshFilter>();
                mf.sharedMesh = mesh;
            }
            else
            {
                // vertices
                mesh.vertices = vertices;
            }
            mesh.UploadMeshData(false);
            gameObject.transform.position = wposCom.transform.position;
        }
    }
}

上面的自定义的网格对象中,有一个叫:GetUguiRectWPos 的组件类:

using UnityEngine;

public class GetUguiRectWPos : MonoBehaviour
{
    public Vector3[] vectices;

//#if UNITY_EDITOR
//    private GameObject[] spherePrefabs;
//    private GameObject[] sphereGos;
//#endif

    private RectTransform rt;

    private void Start()
    {
        rt = GetComponent<RectTransform>();
        vectices = new Vector3[4];

//#if UNITY_EDITOR
//        var prefabNames = new string[4] 
//        {
//            "Prefabs/SphereRed",
//            "Prefabs/SphereGreen",
//            "Prefabs/SphereBlue",
//            "Prefabs/SphereYellow"
//        };

//        spherePrefabs = new GameObject[4];
//        sphereGos = new GameObject[4];
//        for (int i = 0; i < prefabNames.Length; i++)
//        {
//            var pn = prefabNames[i];
//            spherePrefabs[i] = Resources.Load<GameObject>(pn);
//        }
//        for (int i = 0; i < spherePrefabs.Length; i++)
//        {
//            var p = spherePrefabs[i];
//            sphereGos[i] = GameObject.Instantiate(p);
//            sphereGos[i].transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
//        }
//#endif
    }
    private void LateUpdate()
    {
        rt.GetWorldCorners(vectices);
//#if UNITY_EDITOR
//        if (sphereGos != null)
//        {
//            for (int i = 0; i < vectices.Length; i++)
//            {
//                var sp = sphereGos[i];
//                if (sp == null)
//                {
//                    continue;
//                }
//                sp.transform.position = vectices[i];
//            }
//        }
//#endif
    }
}

该 GetUguiRectWPos 的作用只是将某个 ugui 的 quad 大小的世界坐标拿到,然后宫 CustomQuadMesh 组件类使用

接着是,CustomQuadMesh 类中的 GameObject 挂载上:MeshFilter, MeshRenderer

其中 MeshRenderer 的材质我们提前创建并设置到 MeshRenderer 中

材质的 shader 如下

// author   :   jave.lin
Shader "Game/UI/STMask/WriteMaskFromWQuad" {
    Properties {
        _Color ("Color", Color) = (1, 1, 1, 1)
    }
    SubShader {
        Tags
        {
            "Queue"="Transparent"
            "IgnoreProjector"="True"
            "RenderType"="Transparent"
            "PreviewType"="Plane"
        }
        ColorMask 0
        ZWrite Off
        Lighting Off
        Cull Off
        Stencil
        {
            Ref 1
            Comp Always
            Pass Replace
        }
        
        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            struct appdata {
                float4 vertex : POSITION;
            };
            struct v2f {
                float4 vertex : SV_POSITION;
            };
            fixed4 _Color;
            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityWorldToClipPos(v.vertex);
                return o;
            }
            fixed4 frag (v2f i) : SV_Target {
                return _Color;
            }
            ENDCG
        }
    }
}

该 shader lab 主要的作用:

  • 写入 stencil buffer
  • 不写入 color buffer

便于后续的 particle system 只绘制 stencil buffer equal 1 的像素


更好的优化方式

可以参考我后续添加的一篇 blog:Unity - RenderDoc 分析为何 UGUI ScrollView 下 Stencil 不能与 其他 3D 层的对象有交互?(Mask 组件的问题)

可以自行写一个 Stencil Write, Stencil Clear 的组件,替代 Unity Mask 组件,这样可以比较灵活的控制 UI & 3D 层的内容的 Stencil 交互

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity-UGUIUnity游戏引擎中的一个UI系统,可以用来创建和管理用户界面。它提供了丰富的功能和工具,使得开发者能够轻松地制作各种表格。 使用Unity-UGUI制作表格的步骤如下: 1. 创建Canvas对象:在Unity中,首先需要创建一个Canvas对象,作为UI渲染的容器。选择GameObject -> UI -> Canvas,即可创建一个Canvas对象。 2. 添加Table组件:选择Canvas对象,在Inspector面板中点击"Add Component"按钮,然后在搜索栏中输入"Table",选择适合的Table组件,点击添加。 3. 设置表格的行列数:在Table组件的Inspector面板中,设置表格所需的行数和列数。 4. 设置表格样式:可以在Inspector面板中设置表格的颜色、大小等属性,以满足具体需求。 5. 添加表格内容:可以通过代码或者拖拽方式,向表格中添加所需的文本或图片。可以通过操作表格的行列索引,将内容放置在特定的位置。 6. 设置表格的交互性:可以为表格中的每个单元格添加点击事件或其他交互效果,提升用户体验。 7. 调整表格布局:可以通过调整Canvas的大小、位置,或者改变组件之间的层次关系,来调整表格的布局。 8. 完善表格功能:可以根据具体需求,添加更多表格的功能,比如排序、过滤、搜索等。 9. 测试和优化:在表格制作完成后,可以进行测试,查看表格的显示效果和交互效果,并进行优化。 总之,使用Unity-UGUI制作表格,只需简单的操作和设置,就能够创建出各种样式、功能丰富的表格,满足游戏或应用程序的需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值