smoke particle testing
This commit is contained in:
parent
d9228b78a3
commit
463e142727
@ -551,7 +551,7 @@ Vec2 CeilVec2(Vec2 a)
|
|||||||
return VEC2(CeilF32(a.x), CeilF32(a.y));
|
return VEC2(CeilF32(a.x), CeilF32(a.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
//- Angle
|
//- Rotation
|
||||||
|
|
||||||
// Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise
|
// Returns 1 if winding between vectors a & b is clockwise or straight, -1 if counter-clockwise
|
||||||
i32 WindingFromVec2(Vec2 a, Vec2 b)
|
i32 WindingFromVec2(Vec2 a, Vec2 b)
|
||||||
|
|||||||
@ -384,7 +384,7 @@ Vec2 RoundVec2(Vec2 a);
|
|||||||
Vec2 FloorVec2(Vec2 a);
|
Vec2 FloorVec2(Vec2 a);
|
||||||
Vec2 CeilVec2(Vec2 a);
|
Vec2 CeilVec2(Vec2 a);
|
||||||
|
|
||||||
//- Angle
|
//- Rotation
|
||||||
i32 WindingFromVec2(Vec2 a, Vec2 b);
|
i32 WindingFromVec2(Vec2 a, Vec2 b);
|
||||||
Vec2 RotateVec2Angle(Vec2 v, f32 a);
|
Vec2 RotateVec2Angle(Vec2 v, f32 a);
|
||||||
Vec2 RotateVec2(Vec2 a, Vec2 b);
|
Vec2 RotateVec2(Vec2 a, Vec2 b);
|
||||||
|
|||||||
@ -138,12 +138,33 @@ Inline f64 Norm53(u64 v)
|
|||||||
#define MatchFloor(a, b) all(floor(a) == floor(b))
|
#define MatchFloor(a, b) all(floor(a) == floor(b))
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Derivative helpers
|
//~ Rotation
|
||||||
|
|
||||||
|
Inline Vec2 RotateVec2Angle(Vec2 v, f32 a)
|
||||||
|
{
|
||||||
|
f32 c = cos(a);
|
||||||
|
f32 s = sin(a);
|
||||||
|
return Vec2(v.x * c - v.y * s, v.x * s + v.y * c);
|
||||||
|
}
|
||||||
|
|
||||||
|
Inline Vec2 RotateVec2(Vec2 a, Vec2 b)
|
||||||
|
{
|
||||||
|
return Vec2(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
Inline Vec2 InvertRot(Vec2 r)
|
||||||
|
{
|
||||||
|
r.y = -r.y;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
//~ Derivatives
|
||||||
|
|
||||||
#define fwidth_fine(v) (abs(ddx_fine((v))) + abs(ddy_fine((v))))
|
#define fwidth_fine(v) (abs(ddx_fine((v))) + abs(ddy_fine((v))))
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ Color helpers
|
//~ Colors
|
||||||
|
|
||||||
Inline Vec4 Vec4FromU32(u32 v)
|
Inline Vec4 Vec4FromU32(u32 v)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -533,9 +533,11 @@ void M_BuildEntryPoint(WaveLaneCtx *lane)
|
|||||||
//- Dxc
|
//- Dxc
|
||||||
{
|
{
|
||||||
PushStringToList(perm, &cp.flags_dxc, Lit("-O3"));
|
PushStringToList(perm, &cp.flags_dxc, Lit("-O3"));
|
||||||
PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug"));
|
|
||||||
PushStringToList(perm, &cp.flags_dxc, Lit("-HV 202x")); // 202x makes numeric literals less weird
|
PushStringToList(perm, &cp.flags_dxc, Lit("-HV 202x")); // 202x makes numeric literals less weird
|
||||||
|
|
||||||
|
// TODO: Export debug info separately for release builds
|
||||||
|
PushStringToList(perm, &cp.flags_dxc, Lit("-Zi -Qembed_debug"));
|
||||||
|
|
||||||
// Enable warnings
|
// Enable warnings
|
||||||
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wall"));
|
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wall"));
|
||||||
PushStringToList(perm, &cp.warnings_dxc, Lit("-Werror"));
|
PushStringToList(perm, &cp.warnings_dxc, Lit("-Werror"));
|
||||||
@ -544,6 +546,7 @@ void M_BuildEntryPoint(WaveLaneCtx *lane)
|
|||||||
// Disable warnings
|
// Disable warnings
|
||||||
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable"));
|
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-unused-variable"));
|
||||||
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-conversion"));
|
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-conversion"));
|
||||||
|
PushStringToList(perm, &cp.warnings_dxc, Lit("-Wno-switch"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,7 @@ String P_PackWorld(Arena *arena, P_World *src_world)
|
|||||||
}
|
}
|
||||||
if (ent->is_weapon)
|
if (ent->is_weapon)
|
||||||
{
|
{
|
||||||
result.len += PushString(arena, Lit(" is_weapon\n")).len;
|
result.len += PushString(arena, Lit(" weapon\n")).len;
|
||||||
}
|
}
|
||||||
if (ent->is_bullet)
|
if (ent->is_bullet)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -392,17 +392,21 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
// Init gpu state
|
// Init gpu state
|
||||||
G_ResourceHandle gpu_tiles_res = Zi;
|
G_ResourceHandle gpu_tiles_res = Zi;
|
||||||
G_ResourceHandle gpu_particles_res = Zi;
|
G_ResourceHandle gpu_particles_res = Zi;
|
||||||
G_ResourceHandle gpu_cells_res = Zi;
|
|
||||||
G_ResourceHandle gpu_stains_res = Zi;
|
G_ResourceHandle gpu_stains_res = Zi;
|
||||||
|
G_ResourceHandle gpu_ground_cells_res = Zi;
|
||||||
|
G_ResourceHandle gpu_air_cells_res = Zi;
|
||||||
|
G_ResourceHandle gpu_ground_densities_res = Zi;
|
||||||
|
G_ResourceHandle gpu_air_densities_res = Zi;
|
||||||
G_ResourceHandle gpu_drynesses_res = Zi;
|
G_ResourceHandle gpu_drynesses_res = Zi;
|
||||||
G_ResourceHandle gpu_densities_res = Zi;
|
|
||||||
|
|
||||||
G_Texture2DRef gpu_tiles = Zi;
|
G_Texture2DRef gpu_tiles = Zi;
|
||||||
G_RWStructuredBufferRef gpu_particles = Zi;
|
G_RWStructuredBufferRef gpu_particles = Zi;
|
||||||
G_RWTexture2DRef gpu_cells = Zi;
|
|
||||||
G_RWTexture2DRef gpu_stains = Zi;
|
G_RWTexture2DRef gpu_stains = Zi;
|
||||||
|
G_RWTexture2DRef gpu_ground_cells = Zi;
|
||||||
|
G_RWTexture2DRef gpu_air_cells = Zi;
|
||||||
|
G_RWTexture2DRef gpu_ground_densities = Zi;
|
||||||
|
G_RWTexture2DRef gpu_air_densities = Zi;
|
||||||
G_RWTexture2DRef gpu_drynesses = Zi;
|
G_RWTexture2DRef gpu_drynesses = Zi;
|
||||||
G_RWTexture2DRef gpu_densities = Zi;
|
|
||||||
{
|
{
|
||||||
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
G_CommandListHandle cl = G_PrepareCommandList(G_QueueKind_Direct);
|
||||||
{
|
{
|
||||||
@ -429,29 +433,10 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
);
|
);
|
||||||
gpu_particles = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles_res, V_Particle);
|
gpu_particles = G_PushRWStructuredBufferRef(gpu_perm, gpu_particles_res, V_Particle);
|
||||||
}
|
}
|
||||||
// Init cells texture
|
// Init stains texture
|
||||||
{
|
|
||||||
gpu_cells_res = G_PushTexture2D(
|
|
||||||
gpu_perm, cl,
|
|
||||||
// G_Format_R8_Uint,
|
|
||||||
G_Format_R32_Uint,
|
|
||||||
// G_Format_R11G11B10_Float,
|
|
||||||
// G_Format_R10G10B10A2_Unorm,
|
|
||||||
// G_Format_R16G16B16A16_Float,
|
|
||||||
cells_dims,
|
|
||||||
G_Layout_DirectQueue_ShaderReadWrite,
|
|
||||||
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
|
|
||||||
.name = Lit("Cells")
|
|
||||||
);
|
|
||||||
gpu_cells = G_PushRWTexture2DRef(gpu_perm, gpu_cells_res);
|
|
||||||
}
|
|
||||||
// Init stain texture
|
|
||||||
{
|
{
|
||||||
gpu_stains_res = G_PushTexture2D(
|
gpu_stains_res = G_PushTexture2D(
|
||||||
gpu_perm, cl,
|
gpu_perm, cl,
|
||||||
// G_Format_R8_Uint,
|
|
||||||
// G_Format_R11G11B10_Float,
|
|
||||||
// G_Format_R10G10B10A2_Unorm,
|
|
||||||
G_Format_R16G16B16A16_Float,
|
G_Format_R16G16B16A16_Float,
|
||||||
cells_dims,
|
cells_dims,
|
||||||
G_Layout_DirectQueue_ShaderReadWrite,
|
G_Layout_DirectQueue_ShaderReadWrite,
|
||||||
@ -460,14 +445,58 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
);
|
);
|
||||||
gpu_stains = G_PushRWTexture2DRef(gpu_perm, gpu_stains_res);
|
gpu_stains = G_PushRWTexture2DRef(gpu_perm, gpu_stains_res);
|
||||||
}
|
}
|
||||||
|
// Init ground cells texture
|
||||||
|
{
|
||||||
|
gpu_ground_cells_res = G_PushTexture2D(
|
||||||
|
gpu_perm, cl,
|
||||||
|
G_Format_R32_Uint,
|
||||||
|
cells_dims,
|
||||||
|
G_Layout_DirectQueue_ShaderReadWrite,
|
||||||
|
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
|
||||||
|
.name = Lit("Ground cells")
|
||||||
|
);
|
||||||
|
gpu_ground_cells = G_PushRWTexture2DRef(gpu_perm, gpu_ground_cells_res);
|
||||||
|
}
|
||||||
|
// Init air cells texture
|
||||||
|
{
|
||||||
|
gpu_air_cells_res = G_PushTexture2D(
|
||||||
|
gpu_perm, cl,
|
||||||
|
G_Format_R32_Uint,
|
||||||
|
cells_dims,
|
||||||
|
G_Layout_DirectQueue_ShaderReadWrite,
|
||||||
|
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
|
||||||
|
.name = Lit("Air cells")
|
||||||
|
);
|
||||||
|
gpu_air_cells = G_PushRWTexture2DRef(gpu_perm, gpu_air_cells_res);
|
||||||
|
}
|
||||||
|
// Init ground densities texture
|
||||||
|
{
|
||||||
|
gpu_ground_densities_res = G_PushTexture2D(
|
||||||
|
gpu_perm, cl,
|
||||||
|
G_Format_R32_Uint,
|
||||||
|
cells_dims,
|
||||||
|
G_Layout_DirectQueue_ShaderReadWrite,
|
||||||
|
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
|
||||||
|
.name = Lit("Ground densities")
|
||||||
|
);
|
||||||
|
gpu_ground_densities = G_PushRWTexture2DRef(gpu_perm, gpu_ground_densities_res);
|
||||||
|
}
|
||||||
|
// Init air densities texture
|
||||||
|
{
|
||||||
|
gpu_air_densities_res = G_PushTexture2D(
|
||||||
|
gpu_perm, cl,
|
||||||
|
G_Format_R32_Uint,
|
||||||
|
cells_dims,
|
||||||
|
G_Layout_DirectQueue_ShaderReadWrite,
|
||||||
|
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
|
||||||
|
.name = Lit("Air densities")
|
||||||
|
);
|
||||||
|
gpu_air_densities = G_PushRWTexture2DRef(gpu_perm, gpu_air_densities_res);
|
||||||
|
}
|
||||||
// Init drynesses texture
|
// Init drynesses texture
|
||||||
{
|
{
|
||||||
gpu_drynesses_res = G_PushTexture2D(
|
gpu_drynesses_res = G_PushTexture2D(
|
||||||
gpu_perm, cl,
|
gpu_perm, cl,
|
||||||
// G_Format_R8_Uint,
|
|
||||||
// G_Format_R11G11B10_Float,
|
|
||||||
// G_Format_R10G10B10A2_Unorm,
|
|
||||||
// G_Format_R16_Float,
|
|
||||||
G_Format_R32_Float,
|
G_Format_R32_Float,
|
||||||
cells_dims,
|
cells_dims,
|
||||||
G_Layout_DirectQueue_ShaderReadWrite,
|
G_Layout_DirectQueue_ShaderReadWrite,
|
||||||
@ -476,22 +505,6 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
);
|
);
|
||||||
gpu_drynesses = G_PushRWTexture2DRef(gpu_perm, gpu_drynesses_res);
|
gpu_drynesses = G_PushRWTexture2DRef(gpu_perm, gpu_drynesses_res);
|
||||||
}
|
}
|
||||||
// Init densities texture
|
|
||||||
{
|
|
||||||
gpu_densities_res = G_PushTexture2D(
|
|
||||||
gpu_perm, cl,
|
|
||||||
// G_Format_R8_Uint,
|
|
||||||
// G_Format_R11G11B10_Float,
|
|
||||||
// G_Format_R10G10B10A2_Unorm,
|
|
||||||
// G_Format_R16_Float,
|
|
||||||
G_Format_R32_Uint,
|
|
||||||
cells_dims,
|
|
||||||
G_Layout_DirectQueue_ShaderReadWrite,
|
|
||||||
.flags = G_ResourceFlag_ZeroMemory | G_ResourceFlag_AllowShaderReadWrite,
|
|
||||||
.name = Lit("Densities")
|
|
||||||
);
|
|
||||||
gpu_densities = G_PushRWTexture2DRef(gpu_perm, gpu_densities_res);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
G_CommitCommandList(cl);
|
G_CommitCommandList(cl);
|
||||||
}
|
}
|
||||||
@ -610,10 +623,12 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
frame->pt_clamp_sampler = G_BasicPointClampSampler();
|
frame->pt_clamp_sampler = G_BasicPointClampSampler();
|
||||||
frame->pt_wrap_sampler = G_BasicPointWrapSampler();
|
frame->pt_wrap_sampler = G_BasicPointWrapSampler();
|
||||||
frame->particles = gpu_particles;
|
frame->particles = gpu_particles;
|
||||||
frame->cells = gpu_cells;
|
|
||||||
frame->stains = gpu_stains;
|
frame->stains = gpu_stains;
|
||||||
|
frame->ground_cells = gpu_ground_cells;
|
||||||
|
frame->air_cells = gpu_air_cells;
|
||||||
|
frame->ground_densities = gpu_ground_densities;
|
||||||
|
frame->air_densities = gpu_air_densities;
|
||||||
frame->drynesses = gpu_drynesses;
|
frame->drynesses = gpu_drynesses;
|
||||||
frame->densities = gpu_densities;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
@ -2523,12 +2538,14 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Push test emitter
|
//- Push test emitter
|
||||||
|
|
||||||
if (frame->held_buttons[Button_G])
|
// if (frame->held_buttons[Button_G])
|
||||||
// if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G])
|
if (frame->held_buttons[Button_G] && !prev_frame->held_buttons[Button_G])
|
||||||
|
{
|
||||||
|
// Debris
|
||||||
{
|
{
|
||||||
V_Emitter emitter = Zi;
|
V_Emitter emitter = Zi;
|
||||||
|
|
||||||
emitter.kind = V_ParticleKind_Test;
|
emitter.kind = V_ParticleKind_Debris;
|
||||||
|
|
||||||
f32 angle = AngleFromVec2(frame->look);
|
f32 angle = AngleFromVec2(frame->look);
|
||||||
// f32 angle = 0;
|
// f32 angle = 0;
|
||||||
@ -2536,9 +2553,9 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
f32 angle_spread = Tau;
|
f32 angle_spread = Tau;
|
||||||
// f32 angle_spread = 0;
|
// f32 angle_spread = 0;
|
||||||
|
|
||||||
f32 speed = 25;
|
// f32 speed = 25;
|
||||||
// f32 speed = 50;
|
f32 speed = 50;
|
||||||
// f32 speed = 1000;
|
// f32 speed = 100;
|
||||||
f32 speed_spread = speed * 2;
|
f32 speed_spread = speed * 2;
|
||||||
|
|
||||||
emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor;
|
emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor;
|
||||||
@ -2554,7 +2571,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
// emitter.count = Mebi(2);
|
// emitter.count = Mebi(2);
|
||||||
// emitter.count = Kibi(32);
|
// emitter.count = Kibi(32);
|
||||||
// emitter.count = Kibi(8);
|
// emitter.count = Kibi(8);
|
||||||
emitter.count = Kibi(1);
|
emitter.count = 128;
|
||||||
// emitter.count = 128;
|
// emitter.count = 128;
|
||||||
// emitter.count = 32;
|
// emitter.count = 32;
|
||||||
// emitter.count = 1;
|
// emitter.count = 1;
|
||||||
@ -2562,6 +2579,45 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
V_PushParticles(emitter);
|
V_PushParticles(emitter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Smoke
|
||||||
|
{
|
||||||
|
V_Emitter emitter = Zi;
|
||||||
|
|
||||||
|
emitter.kind = V_ParticleKind_Smoke;
|
||||||
|
|
||||||
|
f32 angle = AngleFromVec2(frame->look);
|
||||||
|
// f32 angle = 0;
|
||||||
|
// f32 angle_spread = Tau * 0.25;
|
||||||
|
f32 angle_spread = Tau;
|
||||||
|
// f32 angle_spread = 0;
|
||||||
|
|
||||||
|
f32 speed = 25;
|
||||||
|
// f32 speed = 50;
|
||||||
|
// f32 speed = 50;
|
||||||
|
f32 speed_spread = speed * 2;
|
||||||
|
|
||||||
|
emitter.pos.p0 = emitter.pos.p1 = frame->world_cursor;
|
||||||
|
emitter.speed.min = speed - speed_spread * 0.5;
|
||||||
|
emitter.speed.max = speed + speed_spread * 0.5;
|
||||||
|
emitter.angle.min = angle - angle_spread * 0.5;
|
||||||
|
emitter.angle.max = angle + angle_spread * 0.5;
|
||||||
|
|
||||||
|
// emitter.falloff.min = emitter.falloff.max = 0;
|
||||||
|
|
||||||
|
// emitter.count = CeilF32(Kibi(64) * frame->dt);
|
||||||
|
// emitter.count = Mebi(16);
|
||||||
|
// emitter.count = Mebi(2);
|
||||||
|
// emitter.count = Kibi(32);
|
||||||
|
emitter.count = Kibi(8);
|
||||||
|
// emitter.count = Kibi(1);
|
||||||
|
// emitter.count = 128;
|
||||||
|
// emitter.count = 32;
|
||||||
|
// emitter.count = 1;
|
||||||
|
|
||||||
|
V_PushParticles(emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Debug draw
|
//- Debug draw
|
||||||
@ -4816,6 +4872,7 @@ void V_TickForever(WaveLaneCtx *lane)
|
|||||||
if (frame->should_clear_particles)
|
if (frame->should_clear_particles)
|
||||||
{
|
{
|
||||||
G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(V_ParticlesCap));
|
G_Compute(frame->cl, V_ClearParticlesCS, V_ThreadGroupSizeFromBufferSize(V_ParticlesCap));
|
||||||
|
V.particle_seq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare screen RT
|
// Prepare screen RT
|
||||||
|
|||||||
@ -36,18 +36,22 @@ ComputeShader2D(V_PrepareShadeCS, 8, 8)
|
|||||||
ComputeShader2D(V_PrepareCellsCS, 8, 8)
|
ComputeShader2D(V_PrepareCellsCS, 8, 8)
|
||||||
{
|
{
|
||||||
V_SharedFrame frame = G_Dereference<V_SharedFrame>(V_ShaderConst_Frame)[0];
|
V_SharedFrame frame = G_Dereference<V_SharedFrame>(V_ShaderConst_Frame)[0];
|
||||||
RWTexture2D<u32> cells = G_Dereference<u32>(frame.cells);
|
RWTexture2D<u32> ground_cells = G_Dereference<u32>(frame.ground_cells);
|
||||||
|
RWTexture2D<u32> air_cells = G_Dereference<u32>(frame.air_cells);
|
||||||
|
RWTexture2D<u32> ground_densities = G_Dereference<u32>(frame.ground_densities);
|
||||||
|
RWTexture2D<u32> air_densities = G_Dereference<u32>(frame.air_densities);
|
||||||
RWTexture2D<f32> drynesses = G_Dereference<f32>(frame.drynesses);
|
RWTexture2D<f32> drynesses = G_Dereference<f32>(frame.drynesses);
|
||||||
RWTexture2D<u32> densities = G_Dereference<u32>(frame.densities);
|
|
||||||
|
|
||||||
Vec2 cells_pos = SV_DispatchThreadID + 0.5;
|
Vec2 cells_pos = SV_DispatchThreadID + 0.5;
|
||||||
if (all(cells_pos < countof(cells)))
|
if (all(cells_pos < countof(air_cells)))
|
||||||
{
|
{
|
||||||
// Clear cell
|
// Clear cells
|
||||||
cells[cells_pos] = 0;
|
ground_cells[cells_pos] = 0;
|
||||||
|
air_cells[cells_pos] = 0;
|
||||||
|
|
||||||
// Clear density
|
// Clear densities
|
||||||
densities[cells_pos] = 0;
|
ground_densities[cells_pos] = 0;
|
||||||
|
air_densities[cells_pos] = 0;
|
||||||
|
|
||||||
// Increase dryness
|
// Increase dryness
|
||||||
// TODO: Use simulation dt
|
// TODO: Use simulation dt
|
||||||
@ -160,10 +164,12 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
{
|
{
|
||||||
V_SharedFrame frame = G_Dereference<V_SharedFrame>(V_ShaderConst_Frame)[0];
|
V_SharedFrame frame = G_Dereference<V_SharedFrame>(V_ShaderConst_Frame)[0];
|
||||||
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(frame.particles);
|
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(frame.particles);
|
||||||
RWTexture2D<u32> cells = G_Dereference<u32>(frame.cells);
|
|
||||||
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(frame.stains);
|
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(frame.stains);
|
||||||
|
RWTexture2D<u32> ground_cells = G_Dereference<u32>(frame.ground_cells);
|
||||||
|
RWTexture2D<u32> air_cells = G_Dereference<u32>(frame.air_cells);
|
||||||
|
RWTexture2D<u32> ground_densities = G_Dereference<u32>(frame.ground_densities);
|
||||||
|
RWTexture2D<u32> air_densities = G_Dereference<u32>(frame.air_densities);
|
||||||
RWTexture2D<f32> drynesses = G_Dereference<f32>(frame.drynesses);
|
RWTexture2D<f32> drynesses = G_Dereference<f32>(frame.drynesses);
|
||||||
RWTexture2D<u32> densities = G_Dereference<u32>(frame.densities);
|
|
||||||
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(frame.tiles);
|
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(frame.tiles);
|
||||||
|
|
||||||
u32 particle_idx = SV_DispatchThreadID;
|
u32 particle_idx = SV_DispatchThreadID;
|
||||||
@ -176,11 +182,11 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
|
|
||||||
if (particle.kind != 0)
|
if (particle.kind != 0)
|
||||||
{
|
{
|
||||||
u64 seed = MixU64(P_ParticleSimBasis ^ particle_idx);
|
u64 seed0 = MixU64(P_ParticleSimBasis ^ particle_idx);
|
||||||
f32 rand_offset = Norm16(seed >> 0);
|
f32 rand_offset = Norm16(seed0 >> 0);
|
||||||
f32 rand_angle = Norm16(seed >> 16);
|
f32 rand_angle = Norm16(seed0 >> 16);
|
||||||
f32 rand_speed = Norm16(seed >> 32);
|
f32 rand_speed = Norm16(seed0 >> 32);
|
||||||
f32 rand_falloff = Norm16(seed >> 48);
|
f32 rand_falloff = Norm16(seed0 >> 48);
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Init
|
//- Init
|
||||||
@ -201,6 +207,26 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
|
|
||||||
if (particle.kind > V_ParticleKind_None && particle.kind < V_ParticleKind_COUNT)
|
if (particle.kind > V_ParticleKind_None && particle.kind < V_ParticleKind_COUNT)
|
||||||
{
|
{
|
||||||
|
//////////////////////////////
|
||||||
|
//- Velocity effects
|
||||||
|
|
||||||
|
{
|
||||||
|
// TODO: Separate particle basis for whisp effects
|
||||||
|
u64 seed1 = MixU64(seed0);
|
||||||
|
f32 rand_whisp = Norm16(seed1 >> 0);
|
||||||
|
|
||||||
|
b32 is_whispy = particle.kind == V_ParticleKind_Smoke;
|
||||||
|
if (is_whispy)
|
||||||
|
{
|
||||||
|
f32 whisp = lerp(-1, 1, rand_whisp);
|
||||||
|
particle.velocity.x += whisp * cos(particle.life * 10);
|
||||||
|
particle.velocity.y += whisp * sin(particle.life * 10);
|
||||||
|
|
||||||
|
// f32 whisp = lerp(0, Tau, rand_whisp) * frame.dt;
|
||||||
|
// particle.velocity = RotateVec2Angle(particle.velocity, whisp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Move
|
//- Move
|
||||||
|
|
||||||
@ -288,18 +314,13 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
particle.velocity.y *= -1;
|
particle.velocity.y *= -1;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
u64 collision_seed = MixU64s(seed, particle.collisions_count);
|
u64 collision_seed = MixU64s(seed0, particle.collisions_count);
|
||||||
f32 rand_collision_angle = Norm16(collision_seed >> 0);
|
f32 rand_collision_angle = Norm16(collision_seed >> 0);
|
||||||
f32 rand_collision_velocity = Norm16(collision_seed >> 16);
|
f32 rand_collision_velocity = Norm16(collision_seed >> 16);
|
||||||
f32 collision_angle = lerp(-0.05 * Tau, 0.05 * Tau, rand_collision_angle);
|
f32 collision_angle = lerp(-0.05 * Tau, 0.05 * Tau, rand_collision_angle);
|
||||||
// f32 collision_velocity_falloff = lerp(0, 1, rand_collision_velocity);
|
// f32 collision_velocity_falloff = lerp(0, 1, rand_collision_velocity);
|
||||||
f32 collision_velocity_falloff = 0;
|
f32 collision_velocity_falloff = 0;
|
||||||
f32 x = particle.velocity.x;
|
particle.velocity = RotateVec2Angle(particle.velocity, collision_angle);
|
||||||
f32 y = particle.velocity.y;
|
|
||||||
f32 c = cos(collision_angle);
|
|
||||||
f32 s = sin(collision_angle);
|
|
||||||
particle.velocity.x = x * c - y * s;
|
|
||||||
particle.velocity.y = x * s + y * c;
|
|
||||||
particle.velocity *= 1.0f - collision_velocity_falloff;
|
particle.velocity *= 1.0f - collision_velocity_falloff;
|
||||||
}
|
}
|
||||||
++particle.collisions_count;
|
++particle.collisions_count;
|
||||||
@ -317,12 +338,21 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
//- Commit
|
//- Commit
|
||||||
|
|
||||||
Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1));
|
Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1));
|
||||||
Vec2 screen_pos = mul(frame.af.world_to_screen, Vec3(particle.pos, 1));
|
Vec2 cell_screen_pos_p0 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(floor(cell_pos), 1)), 1));
|
||||||
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
|
Vec2 cell_screen_pos_p1 = mul(frame.af.world_to_screen, Vec3(mul(frame.af.cell_to_world, Vec3(ceil(cell_pos), 1)), 1));
|
||||||
b32 is_in_screen = all(screen_pos >= 0) && all(screen_pos < frame.screen_dims);
|
cell_screen_pos_p1 = max(cell_screen_pos_p1, cell_screen_pos_p0 + 1);
|
||||||
|
|
||||||
b32 should_draw = is_in_world && is_in_screen;
|
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(air_cells));
|
||||||
b32 should_stain = 0;
|
b32 is_visible = all(cell_screen_pos_p1 >= 0) && all(cell_screen_pos_p0 < frame.screen_dims);
|
||||||
|
|
||||||
|
// TODO: Particle based flags
|
||||||
|
b32 is_stain_particle = particle.kind == V_ParticleKind_Debris;
|
||||||
|
b32 is_ground_particle = particle.kind == V_ParticleKind_Debris;
|
||||||
|
b32 is_air_particle = particle.kind == V_ParticleKind_Smoke;
|
||||||
|
|
||||||
|
b32 should_stain = is_stain_particle && is_in_world;
|
||||||
|
b32 should_draw_ground = is_ground_particle && is_in_world && (is_visible || should_stain);
|
||||||
|
b32 should_draw_air = is_air_particle && is_in_world && is_visible;
|
||||||
|
|
||||||
// // Stain
|
// // Stain
|
||||||
// if (is_in_world)
|
// if (is_in_world)
|
||||||
@ -350,7 +380,7 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// Draw
|
// Draw
|
||||||
if (should_draw)
|
if (should_draw_ground || should_draw_air)
|
||||||
{
|
{
|
||||||
u32 packed = 0;
|
u32 packed = 0;
|
||||||
packed |= (particle_idx & ((1 >> 24) - 1)) << 0;
|
packed |= (particle_idx & ((1 >> 24) - 1)) << 0;
|
||||||
@ -358,15 +388,24 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits
|
StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits
|
||||||
StaticAssert(V_ParticleKind_COUNT <= 0xFF); // particle kind must fit in 8 bits
|
StaticAssert(V_ParticleKind_COUNT <= 0xFF); // particle kind must fit in 8 bits
|
||||||
|
|
||||||
InterlockedMax(cells[cell_pos], packed);
|
if (should_draw_ground)
|
||||||
InterlockedAdd(densities[cell_pos], 1);
|
{
|
||||||
|
InterlockedMax(ground_cells[cell_pos], packed);
|
||||||
|
InterlockedAdd(ground_densities[cell_pos], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (should_draw_air)
|
||||||
|
{
|
||||||
|
InterlockedMax(air_cells[cell_pos], packed);
|
||||||
|
InterlockedAdd(air_densities[cell_pos], 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1));
|
// Vec2 cell_pos = mul(frame.af.world_to_cell, Vec3(particle.pos, 1));
|
||||||
// Vec2 screen_pos = mul(frame.af.world_to_screen, Vec3(particle.pos, 1));
|
// Vec2 screen_pos = mul(frame.af.world_to_screen, Vec3(particle.pos, 1));
|
||||||
// b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
|
// b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
|
||||||
// b32 is_in_screen = all(screen_pos >= 0) && all(screen_pos < frame.screen_dims);
|
// b32 is_visible = all(screen_pos >= 0) && all(screen_pos < frame.screen_dims);
|
||||||
|
|
||||||
// Vec4 color = particle.color;
|
// Vec4 color = particle.color;
|
||||||
// color.a *= prev_exists;
|
// color.a *= prev_exists;
|
||||||
@ -407,6 +446,9 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// Increment life
|
||||||
|
particle.life += frame.dt;
|
||||||
|
|
||||||
// Prune
|
// Prune
|
||||||
if (!is_in_world)
|
if (!is_in_world)
|
||||||
{
|
{
|
||||||
@ -417,7 +459,6 @@ ComputeShader(V_SimParticlesCS, 64)
|
|||||||
{
|
{
|
||||||
particle.kind = V_ParticleKind_None;
|
particle.kind = V_ParticleKind_None;
|
||||||
}
|
}
|
||||||
|
|
||||||
particles[particle_idx] = particle;
|
particles[particle_idx] = particle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -485,11 +526,13 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
|
|||||||
// Texture2D<Vec4> shade_tex = G_Dereference<Vec4>(frame.shade_ro);
|
// Texture2D<Vec4> shade_tex = G_Dereference<Vec4>(frame.shade_ro);
|
||||||
Texture2D<Vec4> albedo_tex = G_Dereference<Vec4>(frame.albedo_ro);
|
Texture2D<Vec4> albedo_tex = G_Dereference<Vec4>(frame.albedo_ro);
|
||||||
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(frame.stains);
|
RWTexture2D<Vec4> stains = G_Dereference<Vec4>(frame.stains);
|
||||||
RWTexture2D<u32> cells = G_Dereference<u32>(frame.cells);
|
RWTexture2D<u32> ground_cells = G_Dereference<u32>(frame.ground_cells);
|
||||||
|
RWTexture2D<u32> air_cells = G_Dereference<u32>(frame.air_cells);
|
||||||
|
RWTexture2D<u32> ground_densities = G_Dereference<u32>(frame.ground_densities);
|
||||||
|
RWTexture2D<u32> air_densities = G_Dereference<u32>(frame.air_densities);
|
||||||
RWTexture2D<f32> drynesses = G_Dereference<f32>(frame.drynesses);
|
RWTexture2D<f32> drynesses = G_Dereference<f32>(frame.drynesses);
|
||||||
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(frame.tiles);
|
Texture2D<P_TileKind> tiles = G_Dereference<P_TileKind>(frame.tiles);
|
||||||
SamplerState clamp_sampler = G_Dereference(frame.pt_clamp_sampler);
|
SamplerState clamp_sampler = G_Dereference(frame.pt_clamp_sampler);
|
||||||
RWTexture2D<u32> densities = G_Dereference<u32>(frame.densities);
|
|
||||||
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(frame.particles);
|
RWStructuredBuffer<V_Particle> particles = G_Dereference<V_Particle>(frame.particles);
|
||||||
|
|
||||||
Vec2 screen_pos = input.sv_position.xy;
|
Vec2 screen_pos = input.sv_position.xy;
|
||||||
@ -501,7 +544,7 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
|
|||||||
Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5;
|
Vec2 half_world_dims = Vec2(P_WorldPitch, P_WorldPitch) * 0.5;
|
||||||
Vec2 world_bounds_screen_p0 = mul(frame.af.world_to_screen, Vec3(-half_world_dims.xy, 1));
|
Vec2 world_bounds_screen_p0 = mul(frame.af.world_to_screen, Vec3(-half_world_dims.xy, 1));
|
||||||
Vec2 world_bounds_screen_p1 = mul(frame.af.world_to_screen, Vec3(half_world_dims.xy, 1));
|
Vec2 world_bounds_screen_p1 = mul(frame.af.world_to_screen, Vec3(half_world_dims.xy, 1));
|
||||||
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(cells));
|
b32 is_in_world = all(cell_pos >= 0) && all(cell_pos < countof(ground_cells));
|
||||||
|
|
||||||
P_TileKind tile = tiles[tile_pos];
|
P_TileKind tile = tiles[tile_pos];
|
||||||
P_TileKind equipped_tile = frame.equipped_tile;
|
P_TileKind equipped_tile = frame.equipped_tile;
|
||||||
@ -632,45 +675,83 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
//- Particle
|
//- Ground particle
|
||||||
|
|
||||||
// TODO: Remove this
|
// TODO: Remove this
|
||||||
|
|
||||||
// Vec4 particle_color = cells[cell_pos];
|
Vec4 ground_particle_color = 0;
|
||||||
// particle_color.rgb *= particle_color.a;
|
|
||||||
|
|
||||||
Vec4 particle_color = 0;
|
|
||||||
{
|
{
|
||||||
u32 packed = cells[cell_pos];
|
Vec4 color = 0;
|
||||||
|
{
|
||||||
|
u32 packed = ground_cells[cell_pos];
|
||||||
V_ParticleKind kind = (V_ParticleKind)((packed >> 24) & 0xFF);
|
V_ParticleKind kind = (V_ParticleKind)((packed >> 24) & 0xFF);
|
||||||
if (kind != V_ParticleKind_None)
|
if (kind != V_ParticleKind_None)
|
||||||
{
|
{
|
||||||
u32 particle_idx = packed & ((1 << 24) - 1);
|
u32 particle_idx = packed & ((1 << 24) - 1);
|
||||||
|
|
||||||
if (particle_idx < V_ParticlesCap)
|
if (particle_idx < V_ParticlesCap)
|
||||||
{
|
|
||||||
if (kind == V_ParticleKind_Test)
|
|
||||||
{
|
{
|
||||||
u64 seed = MixU64(P_ParticleCompositeBasis ^ particle_idx);
|
u64 seed = MixU64(P_ParticleCompositeBasis ^ particle_idx);
|
||||||
f32 rand_color = Norm16(seed >> 0);
|
f32 rand_color = Norm16(seed >> 0);
|
||||||
|
if (kind == V_ParticleKind_Debris)
|
||||||
Vec4 color = Vec4(0.15, 0.15, 0.15, 1);
|
|
||||||
color.rgb += (rand_color - 0.5) * 0.025;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
f32 density = densities[cell_pos];
|
color.rgb = Color_Orange.rgb;
|
||||||
|
}
|
||||||
|
else if (kind == V_ParticleKind_Smoke)
|
||||||
|
{
|
||||||
|
color.rgb = Vec3(0.15, 0.15, 0.15);
|
||||||
|
}
|
||||||
|
color.rgb += (rand_color - 0.5) * 0.025;
|
||||||
|
{
|
||||||
|
f32 density = ground_densities[cell_pos];
|
||||||
// f32 t = saturate(density / 10.0);
|
// f32 t = saturate(density / 10.0);
|
||||||
f32 t = smoothstep(-10, 32, density);
|
f32 t = smoothstep(-10, 32, density);
|
||||||
color.a = lerp(0, 0.85, t);
|
color.a = lerp(0, 0.85, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
particle_color = color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ground_particle_color = color;
|
||||||
|
ground_particle_color.rgb *= ground_particle_color.a;
|
||||||
|
}
|
||||||
|
|
||||||
particle_color.rgb *= particle_color.a;
|
//////////////////////////////
|
||||||
|
//- Air particle
|
||||||
|
|
||||||
|
// TODO: Remove this
|
||||||
|
|
||||||
|
Vec4 air_particle_color = 0;
|
||||||
|
{
|
||||||
|
Vec4 color = 0;
|
||||||
|
{
|
||||||
|
u32 packed = air_cells[cell_pos];
|
||||||
|
V_ParticleKind kind = (V_ParticleKind)((packed >> 24) & 0xFF);
|
||||||
|
if (kind != V_ParticleKind_None)
|
||||||
|
{
|
||||||
|
u32 particle_idx = packed & ((1 << 24) - 1);
|
||||||
|
if (particle_idx < V_ParticlesCap)
|
||||||
|
{
|
||||||
|
u64 seed = MixU64(P_ParticleCompositeBasis ^ particle_idx);
|
||||||
|
f32 rand_color = Norm16(seed >> 0);
|
||||||
|
if (kind == V_ParticleKind_Debris)
|
||||||
|
{
|
||||||
|
color.rgb = Color_Orange.rgb;
|
||||||
|
}
|
||||||
|
else if (kind == V_ParticleKind_Smoke)
|
||||||
|
{
|
||||||
|
color.rgb = Vec3(0.15, 0.15, 0.15);
|
||||||
|
}
|
||||||
|
color.rgb += (rand_color - 0.5) * 0.025;
|
||||||
|
{
|
||||||
|
f32 density = air_densities[cell_pos];
|
||||||
|
// f32 t = saturate(density / 10.0);
|
||||||
|
f32 t = smoothstep(-10, 32, density);
|
||||||
|
color.a = lerp(0, 0.85, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
air_particle_color = color;
|
||||||
|
air_particle_color.rgb *= air_particle_color.a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -679,7 +760,8 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
|
|||||||
|
|
||||||
// world_color = BlendPremul(shade_color, world_color);
|
// world_color = BlendPremul(shade_color, world_color);
|
||||||
world_color = BlendPremul(albedo_color, world_color);
|
world_color = BlendPremul(albedo_color, world_color);
|
||||||
world_color = BlendPremul(particle_color, world_color);
|
world_color = BlendPremul(ground_particle_color, world_color);
|
||||||
|
world_color = BlendPremul(air_particle_color, world_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
// #define V_ParticlesCap Kibi(128)
|
// #define V_ParticlesCap Kibi(128)
|
||||||
// #define V_ParticlesCap Mebi(1)
|
// #define V_ParticlesCap Mebi(1)
|
||||||
// #define V_ParticlesCap Mebi(2)
|
#define V_ParticlesCap Mebi(2)
|
||||||
#define V_ParticlesCap Mebi(16)
|
// #define V_ParticlesCap Mebi(16)
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
//~ State types
|
//~ State types
|
||||||
@ -146,10 +146,12 @@ Struct(V_SharedFrame)
|
|||||||
G_StructuredBufferRef emitters;
|
G_StructuredBufferRef emitters;
|
||||||
G_RWStructuredBufferRef particles;
|
G_RWStructuredBufferRef particles;
|
||||||
|
|
||||||
G_RWTexture2DRef cells;
|
|
||||||
G_RWTexture2DRef stains;
|
G_RWTexture2DRef stains;
|
||||||
|
G_RWTexture2DRef ground_cells;
|
||||||
|
G_RWTexture2DRef air_cells;
|
||||||
|
G_RWTexture2DRef ground_densities;
|
||||||
|
G_RWTexture2DRef air_densities;
|
||||||
G_RWTexture2DRef drynesses;
|
G_RWTexture2DRef drynesses;
|
||||||
G_RWTexture2DRef densities;
|
|
||||||
|
|
||||||
G_StructuredBufferRef dverts;
|
G_StructuredBufferRef dverts;
|
||||||
G_StructuredBufferRef quads;
|
G_StructuredBufferRef quads;
|
||||||
@ -166,11 +168,17 @@ Enum(V_ParticleKind)
|
|||||||
{
|
{
|
||||||
V_ParticleKind_None,
|
V_ParticleKind_None,
|
||||||
|
|
||||||
|
//- Ground particles
|
||||||
V_ParticleKind_Blood,
|
V_ParticleKind_Blood,
|
||||||
V_ParticleKind_Debris,
|
V_ParticleKind_Debris,
|
||||||
V_ParticleKind_Test,
|
|
||||||
|
//- Air particles
|
||||||
|
V_ParticleKind_Smoke,
|
||||||
V_ParticleKind_BulletTrail,
|
V_ParticleKind_BulletTrail,
|
||||||
|
|
||||||
|
//- Test particles
|
||||||
|
V_ParticleKind_Test,
|
||||||
|
|
||||||
V_ParticleKind_COUNT,
|
V_ParticleKind_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user