ComputeShader Small Example: Particle Fountain
effect
principle
code
1.ComputeShader
#pragma kernel PenQuan struct Particle { float3 position; Float3 velocity;//Zimiao haunt blog (azimiao. com) float3 startingVelocity; float lifetime; }; RWStructuredBuffer<Particle> particleBuffer; float deltaTime; [numthreads(256, 1, 1)] void PenQuan(uint3 id : SV_DispatchThreadID) { //Roughly calculate its displacement particleBuffer[id.x].position += particleBuffer[id.x].velocity * deltaTime; particleBuffer[id.x].velocity += float3(0,-10,0) * deltaTime; particleBuffer[id.x].lifetime += deltaTime;// Zimiao haunting blog (azimiao. com) if (particleBuffer[id.x].lifetime >= 5) { particleBuffer[id.x].lifetime = 0; particleBuffer[id.x].position.x = 0; particleBuffer[id.x].position.y = 0; particleBuffer[id.x].position.z = 0; particleBuffer[id.x].velocity = particleBuffer[id.x].startingVelocity; } }
2.Shader
Shader "PenQuan" { Properties { _Tint ("Tint", Color) = (0, 0, 0.5, 0.3) _Randomness ("Random", Range(0.0, 1.0)) = 0.5 } SubShader { Pass { Blend SrcAlpha one CGPROGRAM #pragma target 5.0 #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct Particle { float3 position; float3 velocity; float3 startingVelocity; float lifetime; }; // Pixel shader input struct PS_INPUT { float4 position : SV_POSITION; float4 color : COLOR; }; //Shared buffer StructuredBuffer<Particle> particleBuffer; // Properties variables uniform float4 _Tint; uniform float _Randomness; // Vertex shader PS_INPUT vert(uint vertex_id : SV_VertexID, uint instance_id : SV_InstanceID) { PS_INPUT o = (PS_INPUT)0; // Color float speed = length(particleBuffer[instance_id].velocity); //Modify the color according to the current speed float4 c = _Tint; c.r *= 1.0 - _Randomness; c.g *= 1.0 - _Randomness; c.b *= 1.0 - _Randomness; c.r += fmod(abs(particleBuffer[instance_id].velocity.x), _Randomness); c.g += fmod(abs(particleBuffer[instance_id].velocity.y), _Randomness); c.b += fmod(abs(particleBuffer[instance_id].velocity.z), _Randomness); c.a = 1; o.color = c; // Position o.position = UnityObjectToClipPos(float4(particleBuffer[instance_id].position, 1.0f)); return o; } // Pixel shader float4 frag(PS_INPUT i) : COLOR { return i.color; } ENDCG } } Fallback Off }
3.CSharp
public class PenQuanTest : MonoBehaviour { private struct Particle { public Vector3 position; public Vector3 velocity; public Vector3 startingVelocity; public float lifetime; } public int particleCount = 10000; public Material material; public ComputeShader computeShader; //Structure size, used when initializing buffer private const int SIZE_PARTICLE = 40; private int mComputeShaderKernelID; //Keep references ComputeBuffer particleBuffer; private const int WARP_SIZE = 256; private int mWarpCount; private Particle[] particleArray; void Start() { if (particleCount <= 0) particleCount = 1; mWarpCount = Mathf.CeilToInt((float)particleCount / WARP_SIZE); particleArray = new Particle[particleCount]; //Initialize particle position and random velocity information for (int i = 0; i < particleCount; ++i) { particleArray[i].position.x = 0; particleArray[i].position.y = 0; particleArray[i].position.z =0; Vector2 v = Random.insideUnitCircle * 1.5f; particleArray[i].velocity.x = v.x; particleArray[i].velocity.y = 10f; particleArray[i].velocity.z = v.y; particleArray[i].startingVelocity = particleArray[i].velocity; particleArray[i].lifetime = Random. Range(-5f, 5f); } particleBuffer = new ComputeBuffer(particleCount, SIZE_PARTICLE); particleBuffer.SetData(particleArray); mComputeShaderKernelID = computeShader.FindKernel("PenQuan"); computeShader.SetBuffer(mComputeShaderKernelID, "particleBuffer", particleBuffer); material.SetBuffer("particleBuffer", particleBuffer); } void OnDestroy() { if (particleBuffer != null) particleBuffer.Release(); } // Update is called once per frame void Update() { computeShader.SetFloat("deltaTime", Time.deltaTime); computeShader.Dispatch(mComputeShaderKernelID, mWarpCount, 1, 1); } void OnRenderObject() { material.SetPass(0); Graphics.DrawProceduralNow(MeshTopology. Points, 1, particleCount); } }
References
-
[Code information] [Github] lukakostic ComputeShaderExamples