Unity之3D粒子在ScrollView下的裁剪

效果如图

直接上代码和shader

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

public class ParticleClippingController : MonoBehaviour
{
    public RectMask2D rectMask;
    
    private List<Material> rtlist = new List<Material>();
    
    

    void Start()
    {
        var  list = transform.GetComponentsInChildren<ParticleSystemRenderer>();
        foreach (var renderer in list)
        {
            rtlist.Add(renderer.material);
        }
    }

    void LateUpdate()
    {
        // 获取RectMask2D的世界空间裁剪区域
        Vector3[] corners = new Vector3[4];
        rectMask.rectTransform.GetWorldCorners(corners);
        Vector4 clipRect = new Vector4(corners[0].x, corners[0].y, corners[2].x, corners[2].y);

        // 将裁剪区域传递给材质
        foreach (var mat in rtlist)
        {
            mat.SetVector("_ClipRect", clipRect);
        }
    }
}
// 定义一个名为 "Custom/ParticleClipping" 的着色器
Shader "Custom/ParticleClipping" {
    // 定义着色器的属性,这些属性可以在材质面板中进行调整
    Properties {
        // _MainTex 是一个2D纹理属性,用于指定粒子的纹理
        // "Particle Texture" 是该属性在材质面板中显示的名称
        // "white" 是默认纹理,当没有指定纹理时使用白色纹理
        _MainTex ("Particle Texture", 2D) = "white" {}
        // _ClipRect 是一个四维向量属性,用于指定裁剪区域
        // "Clip Rect" 是该属性在材质面板中显示的名称
        // (0,0,1,1) 是默认的裁剪区域
        _ClipRect ("Clip Rect", Vector) = (0,0,1,1)
    }
    // 子着色器,Unity会根据硬件和渲染需求选择合适的子着色器进行渲染
    SubShader {
        // 标签,用于指定渲染类型和渲染队列
        // "RenderType"="Transparent" 表示这是一个透明渲染类型的着色器
        // "Queue"="Transparent" 表示该着色器在透明渲染队列中进行渲染
        Tags { "RenderType"="Transparent" "Queue"="Transparent" }
        // 细节级别,用于控制在不同硬件上的渲染质量
        LOD 100

        // 渲染通道,一个子着色器可以包含多个渲染通道
        Pass {
            // 混合模式,SrcAlpha 表示源颜色的透明度,OneMinusSrcAlpha 表示目标颜色的反透明度
            // 这种混合模式用于实现透明效果
            Blend SrcAlpha OneMinusSrcAlpha
            // 关闭深度写入,因为透明物体通常不需要进行深度写入
            ZWrite Off

            // 开始CG编程块,用于编写顶点和片段着色器代码
            CGPROGRAM
            // 声明顶点着色器函数名为 vert
            #pragma vertex vert
            // 声明片段着色器函数名为 frag
            #pragma fragment frag

            // 包含Unity的常用CG库,提供了一些常用的函数和变量
            #include "UnityCG.cginc"

            // 定义输入结构体 appdata,用于存储从模型顶点数据传递过来的信息
            struct appdata {
                // POSITION 语义表示顶点的位置信息
                float4 vertex : POSITION;
                // TEXCOORD0 语义表示第一组纹理坐标
                float2 uv : TEXCOORD0;
            };

            // 定义顶点到片段着色器的传递结构体 v2f,用于在顶点和片段着色器之间传递数据
            struct v2f {
                // 传递纹理坐标
                float2 uv : TEXCOORD0;
                // SV_POSITION 语义表示裁剪空间中的顶点位置
                float4 vertex : SV_POSITION;
                // 传递顶点的世界空间位置
                float4 worldPos : TEXCOORD1;
            };

            // 声明纹理采样器,用于采样 _MainTex 纹理
            sampler2D _MainTex;
            // 纹理的缩放和平移参数
            float4 _MainTex_ST;
            // 裁剪区域的四维向量
            float4 _ClipRect;

            // 顶点着色器函数,将输入的顶点数据转换为裁剪空间中的顶点位置,并传递相关数据到片段着色器
            v2f vert (appdata v) {
                v2f o;
                // 将顶点从模型空间转换到裁剪空间
                o.vertex = UnityObjectToClipPos(v.vertex);
                // 计算纹理坐标,考虑纹理的缩放和平移
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                // 将顶点从模型空间转换到世界空间
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            // 片段着色器函数,根据输入的顶点数据计算每个像素的颜色
            fixed4 frag (v2f i) : SV_Target {
                // 判断粒子是否在裁剪区域内
                // 如果粒子的世界空间 x 坐标小于裁剪区域的左边界,或者大于右边界
                // 或者粒子的世界空间 y 坐标小于裁剪区域的下边界,或者大于上边界
                if (i.worldPos.x < _ClipRect.x || i.worldPos.x > _ClipRect.z ||
                    i.worldPos.y < _ClipRect.y || i.worldPos.y > _ClipRect.w) {
                    // 如果不在裁剪区域内,则丢弃该像素,不进行渲染
                    discard;
                }
                // 从纹理中采样颜色
                fixed4 col = tex2D(_MainTex, i.uv);
                // 返回采样得到的颜色
                return col;
            }
            // 结束CG编程块
            ENDCG
        }
    }
    // 回退着色器,当当前子着色器不支持时,使用 "Diffuse" 着色器进行渲染
    FallBack "Diffuse"
}

使用方法

1.创建新材质,挂上上述shader,指定纹理

2.ScrollView挂上C#代码,遮罩采用RectMask2D

有其它更好、更方便的办法,可以提供一下,谢谢

顺便提一下,粒子在UI之间层级的控制,修改sort in layer即可,(canvas需要相机模式),可直接写成脚本控制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值