200 lines
5.3 KiB
HLSL
200 lines
5.3 KiB
HLSL
#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<ParticleState> particles:register(u0);
|
|
AppendStructuredBuffer<ParticleState> writeParticles:register(u1);
|
|
StructuredBuffer<ParticleState> 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);
|
|
} |