240 lines
5.8 KiB
GLSL
240 lines
5.8 KiB
GLSL
// 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);
|
|
}
|
|
}
|