unity URP 利用particle system制作简单的shader交互

news2024/11/17 0:44:01

首先这里制作了一个简单交互,使用shader grapgh,根据计算距离和变化数值的差实现交互后的扩散,同时计算消散遮罩让它逐渐谈去。

将他赋予材质物体,根据脚本传入位置和逐渐变化的大小后,呈现这样的效果。

但是,shader graph这样的工具,在做这种效果非常快的同时,也存在不少缺点,比如这里我希望我传入的位置和大小变化都是数组,使用shader graph就不太好办了。

这时候就需要把它翻译成代码,根据连线图的逻辑翻译即可,此外把传入的位置和size值替换为数组。

Shader "yourname"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _HitPos("HitPos", Vector) = (0, 0, 0, 0)
        _HitSize("HitSize", Float) = 0.001
        _HitSpread("HitSpread", Range(0, 10)) = 1
        _HitSizeMax("HitSizeMax", Float) = 0
        _DisappearSpread("DisappearSpread", Float) = 1
        _HitSpreadNoiseMulti("HitSpreadNoiseMulti", Range(0.01, 10)) = 1
        _HitSpreadNoiseScale("HitSpreadNoiseScale", Range(1, 200)) = 20
        [HideInInspector]_QueueOffset("_QueueOffset", Float) = 0
        [HideInInspector]_QueueControl("_QueueControl", Float) = -1
        [HideInInspector][NoScaleOffset]unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {}
        [HideInInspector][NoScaleOffset]unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {}
        [HideInInspector][NoScaleOffset]unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {}


    }
    SubShader
    {

        Tags
        {
            "RenderPipeline"="UniversalPipeline"
            "RenderType"="Opaque"
            //"UniversalMaterialType" = "Lit"
            "Queue"="Geometry"
            "DisableBatching"="False"
        }

        Pass
        {

            Name "Universal Forward"
            Tags
            {
                "LightMode" = "UniversalForward"
            }
            Cull Back
            Blend One Zero
            ZTest LEqual
            ZWrite On
           
            HLSLPROGRAM
            #pragma enable_d3d11_debug_symbols  //  debug信息
            #pragma multi_compile_instancing
            #pragma target 4.0  // 默认2.5 target的详细信息 https://docs.unity3d.com/Manual/SL-ShaderCompileTargets.html
   
            #pragma vertex vert
         
            #pragma fragment frag
         
            //https://github.com/Unity-Technologies/Graphics/tree/master/Packages/com.unity.render-pipelines.universal/ShaderLibrary
            #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
            #include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
            #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Hashes.hlsl"

      

            float Unity_SimpleNoise_ValueNoise_Deterministic_float (float2 uv)
            {
                float2 i = floor(uv);
                float2 f = frac(uv);
                f = f * f * (3.0 - 2.0 * f);
                uv = abs(frac(uv) - 0.5);
                float2 c0 = i + float2(0.0, 0.0);
                float2 c1 = i + float2(1.0, 0.0);
                float2 c2 = i + float2(0.0, 1.0);
                float2 c3 = i + float2(1.0, 1.0);
                float r0; Hash_Tchou_2_1_float(c0, r0);
                float r1; Hash_Tchou_2_1_float(c1, r1);
                float r2; Hash_Tchou_2_1_float(c2, r2);
                float r3; Hash_Tchou_2_1_float(c3, r3);
                float bottomOfGrid = lerp(r0, r1, f.x);
                float topOfGrid = lerp(r2, r3, f.x);
                float t = lerp(bottomOfGrid, topOfGrid, f.y);
                return t;
            }
        
            void Unity_SimpleNoise_Deterministic_float(float2 UV, float Scale, out float Out)
            {
                float freq, amp;
                Out = 0.0f;
                freq = pow(2.0, float(0));
                amp = pow(0.5, float(3-0));
                Out += Unity_SimpleNoise_ValueNoise_Deterministic_float(float2(UV.xy*(Scale/freq)))*amp;
                freq = pow(2.0, float(1));
                amp = pow(0.5, float(3-1));
                Out += Unity_SimpleNoise_ValueNoise_Deterministic_float(float2(UV.xy*(Scale/freq)))*amp;
                freq = pow(2.0, float(2));
                amp = pow(0.5, float(3-2));
                Out += Unity_SimpleNoise_ValueNoise_Deterministic_float(float2(UV.xy*(Scale/freq)))*amp;
            }

            void Unity_SampleGradientV1_float(Gradient Gradient, float Time, out float4 Out)
            {
                float3 color = Gradient.colors[0].rgb;
                [unroll]
                for (int c = 1; c < Gradient.colorsLength; c++)
                {
                    float colorPos = saturate((Time - Gradient.colors[c - 1].w) / (Gradient.colors[c].w - Gradient.colors[c - 1].w)) * step(c, Gradient.colorsLength - 1);
                    color = lerp(color, Gradient.colors[c].rgb, lerp(colorPos, step(0.01, colorPos), Gradient.type));
                }
            #ifdef UNITY_COLORSPACE_GAMMA
                color = LinearToSRGB(color);
            #endif
                float alpha = Gradient.alphas[0].x;
                [unroll]
                for (int a = 1; a < Gradient.alphasLength; a++)
                {
                    float alphaPos = saturate((Time - Gradient.alphas[a - 1].y) / (Gradient.alphas[a].y - Gradient.alphas[a - 1].y)) * step(a, Gradient.alphasLength - 1);
                    alpha = lerp(alpha, Gradient.alphas[a].x, lerp(alphaPos, step(0.01, alphaPos), Gradient.type));
                }
                Out = float4(color, alpha);
            }

            struct appdata
            {
                //顶点着色器语义 https://learn.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics?redirectedfrom=MSDN
                float4 vertex : POSITION;
                float3  normal  : NORMAL;
                float4  tan  : TANGENT;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                //像素着色器语义 https://learn.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics?redirectedfrom=MSDN
                float4 positionCS : SV_POSITION;
                float3  normal  : NORMAL;
                float2 uv : TEXCOORD0;
                float3 positionWS : TEXCOORD1;
            };
            //从片段着色器的返回结构,SV_Target,SV_Depth等,不知道这两个之外还有能用的不。SV_Target可以从0到7,在多渲染目标(MRT)时很有用
            struct fragOutput {
                //语义 https://learn.microsoft.com/zh-cn/windows/win32/direct3dhlsl/dx-graphics-hlsl-semantics?redirectedfrom=MSDN
                float4 Emission : SV_Target;
            };


            sampler2D _MainTex;
            float4 _MainTex_ST; 

            float _HitSpreadNoiseScale;
            float _HitSpreadNoiseMulti;
            int count;
            float3 hitposarray[20];
            float hitsizearray[20];
            float hitspreadarray[20];
            float hitsizemaxarray[20];
            float disappearspreadarray[20];


            v2f vert(appdata v, uint vid : SV_VertexID)
            {
                v2f o;
                o.positionCS = TransformObjectToHClip(v.vertex);
                o.positionWS = TransformObjectToWorld(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.normal = v.normal;
                return o;
            }

            float4 CalculateCircle(v2f i, float3 _HitPos, float _HitSize, float _HitSpread, float _HitSizeMax, float _DisappearSpread)
            {
                float3 tempdis = distance(_HitPos, i.positionWS);
                float tempupmul = clamp(((tempdis - _HitSizeMax) * (-1) )/ _DisappearSpread, 0, 1);

                float noiseout = 0;
                Unity_SimpleNoise_Deterministic_float(i.uv, _HitSpreadNoiseScale, noiseout);
                noiseout = noiseout * _HitSpreadNoiseMulti;
                float temp1 = noiseout + (tempdis - _HitSize);
                float temp2 = 1 - clamp(temp1 / min(_HitSize, _HitSpread), 0, 1);
                Gradient _Gradient = NewGradient(0, 4, 2, float4(0, 0, 0, 0),float4(0.767647, 0.767647, 0.767647, 0.1058824),float4(0.6861503, 0.6861503, 0.6861503, 0.7705958),float4(0, 0, 0, 0.9647059),float4(0, 0, 0, 0),float4(0, 0, 0, 0),float4(0, 0, 0, 0),float4(0, 0, 0, 0), float2(1, 0),float2(1, 1),float2(0, 0),float2(0, 0),float2(0, 0),float2(0, 0),float2(0, 0),float2(0, 0));
                float4 gradientout = 0;
                Unity_SampleGradientV1_float(_Gradient, temp2, gradientout);

                return tempupmul * gradientout;
            }

            fragOutput frag(v2f i) : SV_Target
            {
                fragOutput o = (fragOutput)0;
                float4 tempemission = 0;
                for(int j = 0; j < count; j++){
                    tempemission += CalculateCircle(i, hitposarray[j], hitsizearray[j], hitspreadarray[j], hitsizemaxarray[j], disappearspreadarray[j]);
                };
                o.Emission = tempemission;


                return o;
            }
            ENDHLSL
        }
    }
    Fallback Off
}

particle system制作为在点击位置射线检测,生成粒子,并逐渐放大,最后消失。

弄好后关闭粒子的renderer,使其不可见。

然后创建脚本根据particle system产生的粒子位置和大小,particle system,按个数传入shader代码的数组中,按照粒子的位置和大小同步shader数组中的值以实现效果。

using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.InputSystem;
using static UnityEngine.Rendering.DebugUI;

[ExecuteAlways]
public class ForceField : MonoBehaviour
{
    //编辑器引用
    public GameObject forcefield;
    public ParticleSystem ps;
    //静态存储
    [Header("粒子系统最大数量")]
    public int psAmount = 20;
    Material material;
    Shader shader;
    Mouse mouse;
    //动态变化存储
    RaycastHit raycastHit;
    ParticleSystem.Particle[] particles;
    bool isInited = false;

    void Init()
    {
        if (material == null)
            material = forcefield.GetComponent<MeshRenderer>().sharedMaterial;
        if (shader == null)
            shader = material.shader;
        if (mouse == null)
            mouse = Mouse.current;

        particles = new ParticleSystem.Particle[psAmount];
    }

    void Update()
    {
        //编辑器模式下就要做的事情
        if (forcefield == null) return;
        if (ps == null) return;

        if (!isInited)
        {
            Init();
            isInited = true;
        }

        //运行模式下才要做的事情
        if (!Application.isPlaying) return;
        if (mouse.leftButton.wasPressedThisFrame)//Status:鼠标左键按下  运行时才有作用
        {
            Vector2 mousePos = Pointer.current.position.ReadValue();
            Ray ray = Camera.main.ScreenPointToRay(mousePos);
            Physics.Raycast(ray, out raycastHit, 1000, LayerMask.GetMask("ForceField"));
            
            if(raycastHit.collider != null)//检测有效,做以下操作
            {
                ps.transform.position = raycastHit.point;
                ps.Emit(1);
            }
        }

        ParticleSystem.MainModule psMainModule = ps.main;
        int count = ps.GetParticles(particles);
        Debug.Log(count);

        material.SetInteger("count", count);  //  激活的个数

        if(count > 0)
        {
            Vector4[] hitposs = new Vector4[20];
            float[] hitsizes = new float[20];
            float[] hitspreads = new float[20];
            float[] hitsizemaxs = new float[20];
            float[] disappearspreads = new float[20];
            for (int i = 0; i < count; i++)
            {
                hitposs[i] = new Vector4(particles[i].position.x, particles[i].position.y, particles[i].position.z, 1);
                hitsizes[i] = particles[i].GetCurrentSize(ps);
                hitspreads[i] = 1;
                hitsizemaxs[i] = psMainModule.startSize.constantMax;
                disappearspreads[i] = psMainModule.startSize.constantMax / 2;
            }
            material.SetVectorArray("hitposarray", hitposs);
            material.SetFloatArray("hitsizearray", hitsizes);
            material.SetFloatArray("hitspreadarray", hitspreads);
            material.SetFloatArray("hitsizemaxarray", hitsizemaxs);
            material.SetFloatArray("disappearspreadarray", disappearspreads);
        }

    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1082762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

040:mapboxGL鼠标hover更换选中feature颜色

第040个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+mapbox中通过鼠标hover的方式来更换选中feature颜色。这里面利用了mousemove和mouseleave的方法,通过选中图层的feature,来设置hover的true或者false,从而通过opacity的case状态来判断透明度用哪一个值。 直接复…

6款流程图制作软件:一站式指南

流程图是一种常用的图示工具&#xff0c;可以帮助我们更清晰地表达和展示流程、流程图等内容。在今天已经变得非常普及和便捷&#xff0c;接下来本文将于大家分享6款好用的流程图软件&#xff0c;一起来看看吧&#xff01; 博思白板boardmix 博思白板boardmix是一款基于浏览器…

【HTML】web worker

Web Worker是HTML5中的一项技术&#xff0c;可以在后台运行JavaScript代码&#xff0c;以提高Web应用程序的性能并改善用户体验。它允许在独立的线程中执行耗时的操作&#xff0c;而不会阻塞主线程。 主线程是浏览器用来渲染页面、处理用户交互和执行JavaScript代码的线程。然…

记录一次紧急的版本切换

背景 由于一些特殊原因&#xff0c;需要前同事的代码。他并没有给我们后端一份他走时的src。因此这边需要拉到前同事的代码。 过程 查看版本信息 前同事和我们现在开发用的是一个gitee仓库。因此&#xff0c;我们可以看一下之前的开发线。 说白了&#xff0c;每一次提交&a…

【数据结构】算法之道与实践指南:深入理解二叉树的遍历和分治思想(一)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;数据结构 &#x1f525;该文章主要讲述二叉树的递归结构及分治算法的思想。 目录&#xff1a; &#x1f30d;前言&#xff1a;&#x1f30d;…

面试准备-软件工程

参考&#xff1a; 《程序员面试笔试宝典》&#xff08;何昊、叶向阳&#xff09; 标准的软件开发过程&#xff1a; 1&#xff09;可行性分析&#xff1a;要确定开发目标和总要求&#xff0c;一般要考虑技术是否可行&#xff0c;收益是否可行、用户操作是否可行&#xff0c;是…

【C++】如何使用RapidXML读取和创建XML文件

2023年10月11日&#xff0c;周三下午 目录 RapidXML的官网使用rapidXML读取XML文件中的元素的属性和值此次要读取的XML文件&#xff1a;ReadExample.xml用于读取此XML文件的C代码运行结果使用rapidXML创建XML文件用于创建XML文件的C代码 如果上面的代码无法运行运行结果​编辑…

Peter算法小课堂—DP背包问题

大家好&#xff0c;我是Peter&#xff0c;我又来啦&#x1f388;&#x1f384;✨ &#x1f388;&#x1f9e8;&#x1f389;《动态规划》专栏来啦&#xff0c;目前为止&#xff0c;此专栏已经有四篇文章啦&#x1f381;&#x1f380;&#x1f384; 1.DP概念与编程方法 DP概念…

交叉熵Loss多分类问题实战(手写数字)

1、import所需要的torch库和包 2、加载mnist手写数字数据集&#xff0c;划分训练集和测试集&#xff0c;转化数据格式&#xff0c;batch_size设置为200 3、定义三层线性网络参数w&#xff0c;b&#xff0c;设置求导信息 4、初始化参数&#xff0c;这一步比较关键&#xff0c;…

bootz启动 Linux内核涉及do_bootm_linux 函数

一. bootz启动Linux uboot 启动Linux内核使用bootz命令。当然还有其它的启动命令&#xff0c;例如&#xff0c;bootm命令等等。 本文只分析 bootz命令启动 Linux内核的过程中涉及的几个重要函数。具体分析 do_bootm_linux函数执行过程。 本文继上一篇文章&#xff0c;地址…

vue3 + element Plus实现表格根据关键字合并行,并实现行的增删改操作

根据关键字合并表格 1.实现初始化表格2.实现添加班级与学生的功能3.添加的弹窗4.删除班级5.删除学生 首先看最终实现的效果 1.实现初始化表格 <template><div class"main-page"><div class"flex-end"><div class"public-search…

Service Weaver:以单体形式编码,以微服务形式部署

分布式应用的主流架构模式演化为微服务架构已经有些年头了。微服务、DevOps、持续交付和容器技术(k8s)是构成最初云原生概念[1]的核心要素。它们相生相拌&#xff0c;共同演进&#xff0c;并推动了云计算全面进入云原生时代。 云原生应用普遍采用微服务架构&#xff0c;遗留的单…

阿里云r7服务器内存型CPU采用

阿里云服务器ECS内存型r7实例是第七代内存型实例规格族&#xff0c;CPU采用第三代Intel Xeon可扩展处理器&#xff08;Ice Lake&#xff09;&#xff0c;基频2.7 GHz&#xff0c;全核睿频3.5 GHz&#xff0c;计算性能稳定&#xff0c;CPU内存比1:8&#xff0c;2核16G起步&#…

HBase 表如何按照某表字段排序后顺序存储的方法?

首先需要明白HBase表的排序规则&#xff1a; &#xff08;1&#xff09;rowkey排序&#xff08;字典排序&#xff09;——升序 &#xff08;2&#xff09;Column排序&#xff08;字典排序&#xff09;——升序 &#xff08;3&#xff09;时间戳排序——降序 rowkey 字典序排序…

DeskHIL桌面级仿真测试平台

硬件在环测试系统&#xff0c;一直是汽车电子功能测试的重要工具。随着测试工程师对硬件在环系统的要求越来越高&#xff0c;对其高集成性、便携性的需求也愈发强烈。由于硬件在环系统设计复杂、定制化程度高等因素&#xff0c;成本一直居高不下&#xff0c;因此&#xff0c;市…

C++基础入门学习笔记

问题1&#xff1a;什么是 C 中的多态&#xff1f;如何实现多态&#xff1f; 回答1&#xff1a;C 中的多态是指同一种类型的实体&#xff0c;可以在不同的情况下表现出不同的行为。实现多态的方式有两种&#xff1a;虚函数和模板函数。虚函数是在基类中声明为虚函数的函数&…

c++视觉处理---仿射变换和二维旋转变换矩阵的函数

仿射变换cv::warpAffine cv::warpAffine 是OpenCV中用于执行仿射变换的函数。仿射变换是一种线性变换&#xff0c;可用于执行平移、旋转、缩放和剪切等操作。下面是 cv::warpAffine 函数的基本用法&#xff1a; cv::warpAffine(src, dst, M, dsize, flags, borderMode, borde…

嵌入式Linux裸机开发(七)UART串口、IIC、SPI通信

系列文章目录 文章目录 系列文章目录前言UART串口通信介绍UART配置 IIC介绍I.MX6U 的 I2C SPI介绍I.MX6U ECSPI 结语 前言 大概学完这三种通信后&#xff0c;之后就先去学系统移植&#xff0c;其他的先暂时放下 UART串口通信 介绍 串口全称叫做串行接口&#xff0c;通常也叫…

Maven创建父子工程详解

引言 在微服务盛行的当下&#xff0c;我们创建的工程基本都是父子工程&#xff0c;我们通过父工程来引入jar&#xff0c;定义统一的版本号等&#xff0c;这样我们在子工程中就可以直接引用后使用了&#xff0c;而不需要去重复的声明版本号等&#xff0c;这样会更方便对整个项目…

Linux中Locate命令查找不全

Locate locate(locate) 命令用来查找文件或目录。 locate命令要比find -name快得多&#xff0c;原因在于它不搜索具体目录&#xff0c;而是搜索一个数据库/var/lib/mlocate/mlocate.db 。这个数据库中含有本地所有文件信息。Linux系统会自动创建这个数据库&#xff0c;并且每天…