【Unity】Compute Shader粒子效果模拟

摘要:
在UE4引擎中,已经实现了GPU的粒子系统,可以快速计算数百万的粒子及其碰撞。在Unity中,可以简单的使用ComputeShader,来尝试实现GPU粒子的效果。粒子数量在6w+第一步,我们实现一个脚本,挂在在摄像机组件上,这个脚本我们用来控制粒子的渲染。

在UE4引擎中,已经实现了GPU的粒子系统,可以快速计算数百万的粒子及其碰撞。在Unity中,可以简单的使用Compute Shader,来尝试实现GPU粒子的效果。

实现一个简单的立方体粒子效果,图片压缩的很厉害……粒子数量在6w+

【Unity】Compute Shader粒子效果模拟第1张

第一步,我们实现一个脚本,挂在在摄像机组件上,这个脚本我们用来控制粒子的渲染。

【Unity】Compute Shader粒子效果模拟第2张【Unity】Compute Shader粒子效果模拟第3张
1 usingSystem.Collections;
2 usingSystem.Collections.Generic;
3 usingUnityEngine;
4 
5 public classCBufferTest : MonoBehaviour {
6     publicShader shader;
7     publicComputeShader computeShader;
8 
9     privateComputeBuffer offsetBuffer;
10     privateComputeBuffer outputBuffer;
11     privateComputeBuffer constantBuffer;
12     privateComputeBuffer colorBuffer;
13     private int_kernel;
14     privateMaterial material;
15 
16     public const int VertCount = 65536; //64*64*4*4 (Groups*ThreadsPerGroup)
17 
18     //We initialize the buffers and the material used to draw.
19     voidStart()
20 {
21 CreateBuffers();
22 CreateMaterial();
23         _kernel = computeShader.FindKernel("CSMain");
24 }
25 
26     //When this GameObject is disabled we must release the buffers or else Unity complains.
27     private voidOnDisable()
28 {
29 ReleaseBuffer();
30 }
31 
32     //After all rendering is complete we dispatch the compute shader and then set the material before drawing with DrawProcedural
33     //this just draws the "mesh" as a set of points
34     voidOnPostRender()
35 {
36 Dispatch();
37 
38         material.SetPass(0);
39         material.SetBuffer("buf_Points", outputBuffer);
40         material.SetBuffer("buf_Colors", colorBuffer);
41 Graphics.DrawProcedural(MeshTopology.Points, VertCount);
42 }
43 
44     //To setup a ComputeBuffer we pass in the array length, as well as the size in bytes of a single element.
45     //We fill the offset buffer with random numbers between 0 and 2*PI.
46     voidCreateBuffers()
47 {
48         offsetBuffer = new ComputeBuffer(VertCount, 4); //Contains a single float value (OffsetStruct)
49 
50         float[] values = new float[VertCount];
51         for (int i = 0; i < VertCount; i++)
52 {
53             values[i] = Random.value * 2 *Mathf.PI;
54 }
55 
56 offsetBuffer.SetData(values);
57 
58         constantBuffer = new ComputeBuffer(1, 4); //Contains a single element (time) which is a float
59         colorBuffer = new ComputeBuffer(VertCount, 12);
60         outputBuffer = new ComputeBuffer(VertCount, 12); //Output buffer contains vertices (float3 = Vector3 -> 12 bytes)
61 }
62 
63     //For some reason I made this method to create a material from the attached shader.
64     voidCreateMaterial()
65 {
66         material = newMaterial(shader);
67 }
68 
69     //Remember to release buffers and destroy the material when play has been stopped.
70     voidReleaseBuffer()
71 {
72 constantBuffer.Release();
73 offsetBuffer.Release();
74 outputBuffer.Release();
75 
76 DestroyImmediate(material);
77 }
78 
79     //The meat of this script, it sets the constant buffer (current time) and then sets all of the buffers for the compute shader.
80     //We then dispatch 32x32x1 groups of threads of our CSMain kernel.
81     voidDispatch()
82 {
83         constantBuffer.SetData(new[] { Time.time });
84 
85         computeShader.SetBuffer(_kernel, "cBuffer", constantBuffer);
86         computeShader.SetBuffer(_kernel, "offsets", offsetBuffer);
87         computeShader.SetBuffer(_kernel, "output", outputBuffer);
88         computeShader.SetBuffer(_kernel, "color", colorBuffer);
89         computeShader.Dispatch(_kernel, 64, 64, 1);
90 }
91 }
Particles

第二步,实现Compute Shader,用来计算粒子的位置以及颜色。

【Unity】Compute Shader粒子效果模拟第4张【Unity】Compute Shader粒子效果模拟第5张
1 #pragma kernel CSMain
2 //We define the size of a group in the x and y directions, z direction will just be one
3  #define thread_group_size_x 4
4  #define thread_group_size_y 4
5  
6  //A struct that simple holds a position
7 structPositionStruct
8 {
9 float3 pos;
10 };
11  
12 //A struct containing an offset for use by Wave function
13 structOffsetStruct
14 {
15     floatoffset;
16 };
17  
18 //A constant buffer struct that holds a time variable sent from Unity
19 structCBufferStruct
20 {
21     floatt;
22 };
23  
24 //We keep three buffers accessed by the kernel, a constant buffer that is the same for every computation,
25 //an offset buffer with a value to offset the wave, and an output buffer that is written to by the kernel
26 RWStructuredBuffer<CBufferStruct>cBuffer;
27 RWStructuredBuffer<OffsetStruct>offsets;
28 RWStructuredBuffer<PositionStruct>output;
29 RWStructuredBuffer<float3>color;
30 //A simple sine modulation of the z coordinate, with an offset by a random value between 0 and 2PI
31 float3 Wave(float3 p, intidx,uint3 id)
32 {
33     p.x=cos(cBuffer[0].t+id.x);
34     p.y=sin(cBuffer[0].t+id.y);
35     p.z = sin(cBuffer[0].t +offsets[idx].offset);
36     returnp;
37 }
38 float3 SetColor(float3 p,uint3 id)
39 {
40     p.x=abs(sin(cBuffer[0].t+id.x));
41     p.y=abs(sin(cBuffer[0].t+id.y));
42     p.z=abs(sin(cBuffer[0].t+id.x+id.y));
43     returnp;
44 }
45 //The kernel for this compute shader, each thread group contains a number of threads specified by numthreads(x,y,z)
46 //We lookup the the index into the flat array by using x + y * x_stride
47 //The position is calculated from the thread index and then the z component is shifted by the Wave function
48 [numthreads(thread_group_size_x,thread_group_size_y,1)]
49 voidCSMain (uint3 id : SV_DispatchThreadID)
50 {
51     int idx = id.x + id.y * thread_group_size_x * 32;
52     float spacing = 1;
53  
54     float3 pos = float3(id.x*spacing, id.y*spacing, id.z*spacing);
55     pos =Wave(pos, idx,id);
56     color[idx]=SetColor(pos,id);
57     output[idx].pos =pos;
58 }
Compute Shader

第三步,实现简单的V&F Shader,用于渲染像素到屏幕。

【Unity】Compute Shader粒子效果模拟第6张【Unity】Compute Shader粒子效果模拟第7张
1 Shader "Custom/CBufferTest"{
2 Properties {
3         _MainTex ("Albedo (RGB)", 2D) = "white"{}
4 }
5 SubShader {
6 Tags { 
7     "Queue"="Transparent" 
8     "IgnoreProjector"="True" 
9     "RenderType"="Transparent" 
10 }
11     LOD 200
12 Cull Off
13 blend srcAlpha one
14 Pass {
15 CGPROGRAM
16             #pragma target 5.0
17  
18             #pragma vertex vert
19             #pragma fragment frag
20  
21             #include "UnityCG.cginc"
22  
23             //The buffer containing the points we want to draw.
24             StructuredBuffer<float3>buf_Points;
25             StructuredBuffer<float3>buf_Colors;
26             //A simple input struct for our pixel shader step containing a position.
27             structps_input {
28 float4 pos : SV_POSITION;
29 half3 color:COLOR;
30 };
31  
32             //Our vertex function simply fetches a point from the buffer corresponding to the vertex index
33             //which we transform with the view-projection matrix before passing to the pixel program.
34             ps_input vert (uintid : SV_VertexID)
35 {
36 ps_input o;
37                 float3 worldPos =buf_Points[id];
38                 o.color=buf_Colors[id];
39                 o.pos = mul (UNITY_MATRIX_VP, float4(worldPos,1.0f));
40 
41                 returno;
42 }
43  
44             //Pixel function returns a solid color for each point.
45 float4 frag (ps_input i) : COLOR
46 {
47                 return float4(i.color,0.5);
48 }
49  
50 ENDCG
51 }
52         
53 } 
54     FallBack "Diffuse"
55 }
CBufferTest

可以搜索不同的几何体算法,来实现不同的效果。

免责声明:文章转载自《【Unity】Compute Shader粒子效果模拟》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇python 工具 二进制文件处理之——大小端变换Echarts自动刷新数据下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

嵌入式 uboot、fs、kernel制作和烧录简记-hi3518c

NULL RAM : mkdir ramdisk_test 临时挂在点 dd if=/dev/zero of=rootfs.ramdisk bs=1k count=10000 建立空硬盘//15000(15M) losetup /dev/loop0 rootfs.ramdisk 挂在临时硬盘 mke2fs -m 0 /dev/loop0 格式化此硬盘 mo...

unity editor模式下读取文件夹资源

string path = EditorUtility.OpenFolderPanel("Load png Textures", "", "");  //打开文件夹 string[] files = Directory.GetFiles(path);  //获取所有文件路径 Object[] os = new Object[] { AssetDatabas...

Unity3d在Android环境下读取XML的注意事项

PC环境下读取一般可以直接用 XmlDocument doc = new XmlDocument(); doc.Load(path);可以直接加载进来。 path为直接路径。 此时路径可以为streamingAssets文件夹下,也可以是自己自建的文件夹下面,如果是你自己建的文件夹下打包后需要手动添加一下,就是说比如你自己在Assets文件下新建了一个Co...

Unity移动Basic版授权从此免费

具体信息参见官方博客:http://blogs.unity3d.com/2013/05/21/putting-the-power-of-unity-in-the-hands-of-every-mobile-developer/ 在今年的Unite 2013大会上,Unity CEO David Helgason宣布,原本需要分别购买、总价合计800美元 的...

Docker的内核,性能与调优

Docker的内核,性能与调优 首先我们抛出3个问题: docker容器的内核与宿主机内核是怎样的关系? 容器在运行时如何调用系统资源? docker的性能参数有没有作用范围? 能够将这3个问题全部解答,关于docker的内核与调优策略便有了一定程度的认识。   一、容器与宿主机的内核关系 —— 共享内核 docker镜像是一个“应用程序和它运行依赖...

Liunx之Centos系统无人值守全自动化安装

  作者:邓聪聪 定制centos6.8自动安装ISO光盘 安装系统为centos6.8 (base server),安装方式为全新安装 使用ext4分区格式 安装前可以交互输入root密码,主机名,分区大小,然后安装过程自动化 关闭防火墙,selinux 网络为dhcp方式获取 时区为Asia/Shanghai 分区表类型为mbr 默认设置三个分区,b...