// File generated by Flax Editor // Version: @0 @3 #include "./Flax/Common.hlsl" #include "./Flax/GBufferCommon.hlsl" #include "./Flax/Matrix.hlsl" @7 // Primary constant buffer META_CB_BEGIN(0, Data) float4x4 ViewProjectionMatrix; float4x4 InvViewProjectionMatrix; float4x4 InvViewMatrix; float4x4 ViewMatrix; float4x4 WorldMatrix; float4x4 InvWorldMatrix; float3 ViewPos; float ViewFar; float3 ViewDir; float Time; float4 ViewInfo; float4 ScreenSize; float3 EffectPosition; float DeltaTime; float4 EffectRotation; float3 EffectScale; uint ParticleCounterOffset; float3 Dummy0; uint SpawnCount; @1META_CB_END // Particles data buffers ByteAddressBuffer SrcParticlesData : register(t0); RWByteAddressBuffer DstParticlesData : register(u0); // The GPU particles simulation context data struct Context { uint ParticleIndex; uint ParticlesCount; uint Seed; }; @6 // Seed generation function uint WangHash(uint seed) { seed = (seed ^ 61) ^ (seed >> 16); seed += (seed << 3); seed = seed ^ (seed >> 4); seed *= 0x27d4eb2d; seed = seed ^ (seed >> 15); return seed; } // Random number generation function float Rand(inout uint seed) { const uint multiplier = 0x0019660d; const uint increment = 0x3c6ef35f; seed = multiplier * seed + increment; return asfloat((seed >> 9) | 0x3f800000) - 1.0f; } float4 Mod289(float4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } float4 Perm(float4 x) { return Mod289(((x * 34.0) + 1.0) * x); } float Noise(float3 p) { float3 a = floor(p); float3 d = p - a; d = d * d * (3.0 - 2.0 * d); float4 b = a.xxyy + float4(0.0, 1.0, 0.0, 1.0); float4 k1 = Perm(b.xyxy); float4 k2 = Perm(k1.xyxy + b.zzww); float4 c = k2 + a.zzzz; float4 k3 = Perm(c); float4 k4 = Perm(c + 1.0); float4 o1 = frac(k3 * (1.0 / 41.0)); float4 o2 = frac(k4 * (1.0 / 41.0)); float4 o3 = o2 * d.z + o1 * (1.0 - d.z); float2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x); return o4.y * d.y + o4.x * (1.0 - d.y); } float3 Noise3D(float3 p) { float o = Noise(p); float a = Noise(p + float3(0.0001f, 0.0f, 0.0f)); float b = Noise(p + float3(0.0f, 0.0001f, 0.0f)); float c = Noise(p + float3(0.0f, 0.0f, 0.0001f)); float3 grad = float3(o - a, o - b, o - c); float3 other = abs(grad.zxy); return normalize(cross(grad,other)); } float3 Noise3D(float3 position, int octaves, float roughness) { float weight = 0.0f; float3 noise = float3(0.0, 0.0, 0.0); float scale = 1.0f; for (int i = 0; i < octaves; i++) { float curWeight = pow((1.0-((float)i / octaves)), lerp(2.0, 0.2, roughness)); noise += Noise3D(position * scale) * curWeight; weight += curWeight; scale *= 1.72531; } return noise / weight; } // Reprojects the world space position from the given UV and raw device depth float3 ReprojectPosition(float2 uv, float rawDepth) { uv = uv * float2(2.0, -2.0) + float2(-1.0, 1.0); float4 pos = mul(float4(uv.x, uv.y, rawDepth, 1.0f), InvViewProjectionMatrix); return pos.xyz / pos.w; } // Random values generation wrapper macros #define RAND Rand(context.Seed) #define RAND2 float2(RAND, RAND) #define RAND3 float3(RAND, RAND, RAND) #define RAND4 float4(RAND, RAND, RAND, RAND) @2uint GetParticleUint(uint particleIndex, int offset) { return SrcParticlesData.Load(particleIndex * PARTICLE_STRIDE + offset); } int GetParticleInt(uint particleIndex, int offset) { return asint(SrcParticlesData.Load(particleIndex * PARTICLE_STRIDE + offset)); } float GetParticleFloat(uint particleIndex, int offset) { return asfloat(SrcParticlesData.Load(particleIndex * PARTICLE_STRIDE + offset)); } float2 GetParticleVec2(uint particleIndex, int offset) { return asfloat(SrcParticlesData.Load2(particleIndex * PARTICLE_STRIDE + offset)); } float3 GetParticleVec3(uint particleIndex, int offset) { return asfloat(SrcParticlesData.Load3(particleIndex * PARTICLE_STRIDE + offset)); } float4 GetParticleVec4(uint particleIndex, int offset) { return asfloat(SrcParticlesData.Load4(particleIndex * PARTICLE_STRIDE + offset)); } void SetParticleUint(uint particleIndex, int offset, uint value) { DstParticlesData.Store(particleIndex * PARTICLE_STRIDE + offset, value); } void SetParticleInt(uint particleIndex, int offset, int value) { DstParticlesData.Store(particleIndex * PARTICLE_STRIDE + offset, asuint(value)); } void SetParticleFloat(uint particleIndex, int offset, float value) { DstParticlesData.Store(particleIndex * PARTICLE_STRIDE + offset, asuint(value)); } void SetParticleVec2(uint particleIndex, int offset, float2 value) { DstParticlesData.Store2(particleIndex * PARTICLE_STRIDE + offset, asuint(value)); } void SetParticleVec3(uint particleIndex, int offset, float3 value) { DstParticlesData.Store3(particleIndex * PARTICLE_STRIDE + offset, asuint(value)); } void SetParticleVec4(uint particleIndex, int offset, float4 value) { DstParticlesData.Store4(particleIndex * PARTICLE_STRIDE + offset, asuint(value)); } bool AddParticle(out uint dstIndex) { // Acquire the particle index in the destination buffer DstParticlesData.InterlockedAdd(ParticleCounterOffset, 1, dstIndex); // Prevent overflow return dstIndex >= PARTICLE_CAPACITY; } void UpdateParticle(Context context) { @5} void SpawnParticle(Context context) { if (AddParticle(context.ParticleIndex)) return; @4} // Main entry point for the particles simulation and spawning META_CS(true, FEATURE_LEVEL_SM5) [numthreads(THREAD_GROUP_SIZE, 1, 1)] void CS_Main(uint3 dispatchThreadId : SV_DispatchThreadID) { Context context; context.ParticleIndex = dispatchThreadId.x; context.ParticlesCount = min(SrcParticlesData.Load(ParticleCounterOffset), PARTICLE_CAPACITY); context.Seed = WangHash(context.ParticleIndex ^ asuint(Time)); if (context.ParticleIndex < context.ParticlesCount) { UpdateParticle(context); } else if (context.ParticleIndex < context.ParticlesCount + SpawnCount) { SpawnParticle(context); } }