ComputeShader Small Example: Snow

This is an example of how ComputeShader combines with Shader to achieve snow. We calculate the position of each snow particle in parallel through ComputeShader, and draw it through Shader.

effect

principle

Compute the position of each particle in parallel through ComputeShader, and share the Buffer with the Shader. The Shader draws particles at the corresponding position.

code

1.ComputeShder

 #pragma kernel CSMain //Snow particle attributes (position, survival time) struct Particle { float3 position; float lifetime; }; //Buffer, used to set or retrieve data RWStructuredBuffer<Particle> particleBuffer; //Frame time interval float deltaTime; [numthreads (256, 1, 1)]//It is convenient to cut groups when calculating. Only one dimension value is used void CSMain(uint3 id : SV_DispatchThreadID) { float3 delta = float3(0, -2, 0); // gravity //Gravity fall particleBuffer[id.x].position += delta * deltaTime; //Update lifetime particleBuffer[id.x].lifetime += deltaTime; //When the particle survives for more than 25 seconds, reset it back to the point where y=0 if (particleBuffer[id.x].lifetime > 25) { particleBuffer[id.x].lifetime = 0; particleBuffer[id.x].position.y = 0; } }

2.Shader

 Shader "SnowShader" { Properties { _Tint("Tint", Color) = (1, 1, 1, 1) } SubShader { Pass { Blend SrcAlpha one CGPROGRAM #pragma target 5.0 #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" //Particle data (corresponding to ComputeShader) struct Particle { float3 position; float lifetime; }; //input struct PS_INPUT { float4 position : SV_POSITION; float4 color : COLOR; }; //Buffer shared with ComputeShader StructuredBuffer<Particle> particleBuffer; //Color set through editor (Properties above) uniform float4 _Tint; //Vertex shader PS_INPUT vert(uint vertex_id : SV_VertexID,  uint instance_id : SV_InstanceID) { PS_INPUT o = (PS_INPUT)0; o.color = _Tint; //Set position (take particle data at different positions from buffer through instance_id) 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 Snow : MonoBehaviour { //Particle data structure (same as in ComputeShader, used to set buffer) private struct Particle { public Vector3 position; public float lifetime; } //Quantity public int particleCount = 10000; //Material for painting particles (shader is the above snow) public Material material; public ComputeShader computeShader; //Single structure size (bytes, used to initialize buffer, 3 * 4+4=16) private const int SIZE_PARTICLE = 16; //kernel ID private int mComputeShaderKernelID; //Buffer, setting, retrieving data, sharing with shader, etc ComputeBuffer particleBuffer; //ComputeBuffer The number of threads in a group, which is used to calculate packets when dispatching private const int WARP_SIZE = 256; //Number of groups required private int mWarpCount; void Start() { if (particleCount <= 0) particleCount = 1; //Calculate the number of groups mWarpCount = Mathf.CeilToInt((float)particleCount / WARP_SIZE); //Initialize particle data Particle[] particleArray = new Particle[particleCount]; for (int i = 0;  i < particleCount; ++i) { particleArray[i].position.x = Random. Range(-50f, 50f); particleArray[i].position.y = 0; particleArray[i].position.z = Random. Range(-50f, 50f); particleArray[i].lifetime = Random. Range(0f, 25f); } //Create and set buffer data particleBuffer = new ComputeBuffer(particleCount, SIZE_PARTICLE); particleBuffer.SetData(particleArray); mComputeShaderKernelID = computeShader.FindKernel("CSMain"); //Set the buffer of the current kernel computeShader.SetBuffer(mComputeShaderKernelID, "particleBuffer", particleBuffer); //Shader shares this buffer material.SetBuffer("particleBuffer", particleBuffer); } void OnDestroy() { if (particleBuffer !=  null) particleBuffer.Release(); } void Update() { computeShader.SetFloat("deltaTime", Time.deltaTime); //Performing operations computeShader.Dispatch(mComputeShaderKernelID, mWarpCount, 1, 1); } void OnRenderObject() { //Activate the given pass for rendering material.SetPass(0); //GPU drawing Graphics.DrawProceduralNow(MeshTopology. Points, 1, particleCount); } }

References

  1. [Code information] [Github] lukakostic ComputeShaderExamples
Zimiao haunting blog (azimiao. com) All rights reserved. Please note the link when reprinting: https://www.azimiao.com/7645.html
Welcome to the Zimiao haunting blog exchange group: three hundred and thirteen million seven hundred and thirty-two thousand

Comment

*

*