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

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

【Unity】Compute Shader粒子效果模拟

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

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 
 5 public class CBufferTest : MonoBehaviour {
 6     public Shader shader;
 7     public ComputeShader computeShader;
 8 
 9     private ComputeBuffer offsetBuffer;
10     private ComputeBuffer outputBuffer;
11     private ComputeBuffer constantBuffer;
12     private ComputeBuffer colorBuffer;
13     private int _kernel;
14     private Material 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     void Start()
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 void OnDisable()
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     void OnPostRender()
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     void CreateBuffers()
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     void CreateMaterial()
65     {
66         material = new Material(shader);
67     }
68 
69     //Remember to release buffers and destroy the material when play has been stopped.
70     void ReleaseBuffer()
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     void Dispatch()
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

相关文章: