#define ParticleType_Dead 0 #define ParticleType_Emitter 1 #define ParticleType_Point 2 struct ParticleState { int type; float3 oldPosition; float3 currentPosition; float3 direction; float creationTime; float mass; };//48 bytes #define PI 3.14159265 float hash(float n) { return frac(sin(n)*43758.5453123); } cbuffer _0 : register(b0) { float demoTime; float deltaTime; float dummy1; float dummy2; }; static const float emitRate = 0.00001f; //delay in seconds between each particle spawn static const float lifeTime = 1.0f; //particle lifetime in seconds ConsumeStructuredBuffer particles:register(u0); AppendStructuredBuffer writeParticles:register(u1); StructuredBuffer readParticles:register(t0); void emit(int type, float3 oldPosition, float3 position, float3 direction, float time) { ParticleState emittedParticle; emittedParticle.type = type; emittedParticle.oldPosition = position; emittedParticle.currentPosition = position; emittedParticle.creationTime = time; emittedParticle.direction = direction; emittedParticle.mass = 1; writeParticles.Append(emittedParticle); // emit new particle } void recycle(ParticleState particle) { ParticleState newParticle; newParticle.type = particle.type; newParticle.oldPosition = particle.currentPosition; newParticle.currentPosition = particle.currentPosition + particle.direction * deltaTime; newParticle.creationTime = particle.creationTime; newParticle.direction = particle.direction; if (particle.type == ParticleType_Point) newParticle.direction += float3(0, -10, 0) * deltaTime; newParticle.mass = particle.mass; writeParticles.Append(newParticle); } [numthreads(1, 1, 1)] void init(int3 id:SV_DispatchThreadID) { emit(ParticleType_Emitter, float3(0, 0, 0), float3(0, 0, 0), float3(0, 0, 0), demoTime); } float3 project(float3 v) { return float3(v.x, v.y, (1 - v.z) / 10.0f) / -v.z; } float3 h2r(float h, float s, float v){ return lerp(saturate((abs(frac(h + float3(1, 2, 3) / 3) * 6 - 3) - 1)), 1, s)*v; } [numthreads(1, 1, 1)] void update(int3 id:SV_DispatchThreadID) { float seed = 1024 * id.y + id.x + hash(demoTime) * 1024; ParticleState particle = particles.Consume(); if (particle.type == ParticleType_Emitter) { float t = particle.creationTime; particle.currentPosition = float3(sin(t * 20), -1, cos(t * 20) - 3) * 0.3; if (demoTime - particle.creationTime < emitRate) { recycle(particle); } else { while (t <= demoTime) { particle.currentPosition = float3(sin(t * 20), -1, cos(t * 20) - 3) * 0.3; emit(ParticleType_Point, particle.currentPosition, particle.currentPosition, hash(seed++ * demoTime) * 5 * normalize(float3(hash(seed++) * 2 - 1, 10 * hash(seed++ * demoTime * demoTime), hash(seed++ * demoTime * 10) * 2 - 1)), t); t += emitRate; } emit(ParticleType_Emitter, particle.currentPosition, particle.currentPosition, particle.direction, t); } } else if (particle.type == ParticleType_Point) { float age = (demoTime - particle.creationTime) / lifeTime; uint index; if (age <= 1) { recycle(particle); } } } struct _2 { float3 pos1 : TEXCOORD0; float3 pos2 : TEXCOORD1; float3 dir : TEXCOORD2; float age : AGE; int valid : VALID; }; struct _3 { float4 pos : SV_POSITION; float length : LENGTH; float age : AGE; }; void pvs(uint id : SV_VertexID, out _2 o) { ParticleState particle = readParticles[id]; o.pos1 = particle.oldPosition; o.pos2 = particle.currentPosition; o.dir = particle.direction; o.age = (demoTime - particle.creationTime) / lifeTime; o.valid = particle.type == ParticleType_Point ? 1 : 0; } float particleSize(float z) { return 0.0005f / -z; } [maxvertexcount(18)] void pgs(point _2 input[1], inout TriangleStream<_3> o) { _2 p = input[0]; if (p.valid == 0) return; float s1 = particleSize(p.pos1.z); float s2 = particleSize(p.pos2.z); float3 p1 = project(p.pos1); float3 p2 = project(p.pos2); float2 d = normalize(p2.xy - p1.xy); if (length(d) == 0) d = normalize(project(p.dir).xy); float2 pr = float2(-d.y, d.x); p1.xy += d * s1 * 0.5; p2.xy -= d * s2 * 0.5; _3 r; r.length = distance(p1.xy, p2.xy) * 128; r.age = p.age; r.pos = float4(p1.xy - d * s1, p1.z, 1.0); o.Append(r); r.pos = float4(p1.xy + pr * s1, p1.z, 1.0); o.Append(r); r.pos = float4(p1.xy - pr * s1, p1.z, 1.0); o.Append(r); o.RestartStrip(); r.pos = float4(p1.xy - pr * s1, p1.z, 1.0); o.Append(r); r.pos = float4(p1, 1.0); o.Append(r); r.pos = float4(p2.xy - pr * s2, p2.z, 1.0); o.Append(r); o.RestartStrip(); r.pos = float4(p1, 1.0); o.Append(r); r.pos = float4(p2, 1.0); o.Append(r); r.pos = float4(p2.xy - pr * s2, p2.z, 1.0); o.Append(r); o.RestartStrip(); r.pos = float4(p1, 1.0); o.Append(r); r.pos = float4(p2.xy + pr * s2, p2.z, 1.0); o.Append(r); r.pos = float4(p2, 1.0); o.Append(r); o.RestartStrip(); r.pos = float4(p1, 1.0); o.Append(r); r.pos = float4(p1.xy + pr * s1, p1.z, 1.0); o.Append(r); r.pos = float4(p2.xy + pr * s2, p2.z, 1.0); o.Append(r); o.RestartStrip(); r.pos = float4(p2.xy + d * s2, p2.z, 1.0); o.Append(r); r.pos = float4(p2.xy - pr * s2, p2.z, 1.0); o.Append(r); r.pos = float4(p2.xy + pr * s2, p2.z, 1.0); o.Append(r); o.RestartStrip(); } float4 pps(_3 i) : SV_Target { float intensity = 1.0 / (i.length + 50); float3 color = h2r(i.age * 3, 0.2, 1.0); return float4(color, intensity); }