From ed40711781e0792280719c03fe98627a9ea5953d Mon Sep 17 00:00:00 2001 From: jacob Date: Mon, 16 Feb 2026 22:14:51 -0600 Subject: [PATCH] working splatter with particle layers --- src/pp/pp_vis/pp_vis_core.c | 181 ++++++++++++++++++++++++++++---- src/pp/pp_vis/pp_vis_gpu.g | 62 ++++------- src/pp/pp_vis/pp_vis_shared.cg | 20 ++-- src/pp/pp_vis/pp_vis_shared.cgh | 23 ++-- 4 files changed, 202 insertions(+), 84 deletions(-) diff --git a/src/pp/pp_vis/pp_vis_core.c b/src/pp/pp_vis/pp_vis_core.c index e07158c5..851f899f 100644 --- a/src/pp/pp_vis/pp_vis_core.c +++ b/src/pp/pp_vis/pp_vis_core.c @@ -2265,6 +2265,143 @@ void V_TickForever(WaveLaneCtx *lane) + // if (0) + { + for (P_Ent *bullet = P_FirstEnt(local_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) + { + if (bullet->is_bullet && bullet->has_hit) + { + P_MaterialKind material = bullet->hit_material; + + Vec2 hit_entry = bullet->hit_entry; + Vec2 hit_entry_normal = bullet->hit_entry_normal; + Vec2 bullet_vel = SubVec2(bullet->bullet_end, bullet->bullet_start); + + V_DrawLine(bullet->bullet_start, bullet->bullet_end, Color_Cyan); + + ////////////////////////////// + //- Wall particles + + // if (material != P_MaterialKind_Flesh) + // { + // //- Wall debris + // { + // V_Emitter emitter = Zi; + // { + // // emitter.flags |= V_ParticleFlag_PruneWhenStill; + // // emitter.flags |= V_ParticleFlag_StainOnPrune; + + + // emitter.count = 4; + + // emitter.start = hit_entry; + // emitter.end = emitter.start; + + // emitter.color_lin = LinearFromSrgb(VEC4(0.4, 0.3, 0.2, 0.75)); + // emitter.color_spread = VEC4(0, 0, 0, 0.25); + + // emitter.speed = 2; + // // emitter.speed_spread = emitter.speed * 2; + // emitter.speed_spread = emitter.speed * 2.5; + + // emitter.velocity_falloff = 5; + // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; + + // Vec2 dir = hit_entry_normal; + + // emitter.angle = AngleFromVec2(dir); + // emitter.angle_spread = Tau * 0.5; + + // // emitter.lifetime = 0.25; + // // emitter.lifetime = 0.05; + // // emitter.lifetime = 0.04; + // emitter.lifetime_spread = emitter.lifetime * 2; + // } + // V_PushParticles(emitter); + // } + + // //- Wall dust + // { + // V_Emitter emitter = Zi; + // { + // // emitter.flags |= V_ParticleFlag_PruneWhenStill; + + // emitter.count = 32; + + // emitter.start = hit_entry; + // emitter.end = emitter.start; + + // emitter.color_lin = LinearFromSrgb(VEC4(0.5, 0.5, 0.5, 0.75)); + + // emitter.speed = 4; + // // emitter.speed_spread = emitter.speed * 2; + // emitter.speed_spread = emitter.speed * 2; + + // emitter.velocity_falloff = 12; + // emitter.velocity_falloff_spread = emitter.velocity_falloff_spread * 1.5; + + // Vec2 dir = hit_entry_normal; + + // emitter.angle = AngleFromVec2(dir); + // emitter.angle_spread = Tau * 0.1; + + // emitter.lifetime = 1; + // // emitter.lifetime = 0.05; + // // emitter.lifetime = 0.04; + // emitter.lifetime_spread = emitter.lifetime * 2; + // } + // V_PushParticles(emitter); + // } + // } + + ////////////////////////////// + //- Blood particles + + if (material == P_MaterialKind_Flesh) + { + { + V_Emitter emitter = Zi; + + emitter.kind = V_ParticleKind_BloodTrail; + // emitter.kind = V_ParticleKind_BloodDebris; + + Vec2 dir = NormVec2(NegVec2(bullet_vel)); + + f32 angle = AngleFromVec2(dir); + // f32 angle = 0; + // f32 angle_spread = Tau * 0.25; + f32 angle_spread = TweakFloat("Emitter angle spread", 0.1, 0, 1) * Tau; + // f32 angle_spread = Tau; + // f32 angle_spread = 0; + + // f32 speed = 5; + // f32 speed = 25; + f32 speed = 50; + // f32 speed = 100; + f32 speed_spread = speed * 2; + + emitter.pos.p0 = emitter.pos.p1 = hit_entry; + 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.count = TweakFloat("Emitter count", 1, 0, 100) * (Kibi(32) * frame->dt); + V_PushParticles(emitter); + } + } + + // V_DrawPoint(victim_raycast.p, Color_Green); + // V_DrawLine(victim_raycast.p, AddVec2(victim_raycast.p, MulVec2(victim_raycast.normal, 0.5)), Color_White); + } + } + } + + + + + + + // if (0) // { // for (P_Ent *bullet = P_FirstEnt(local_frame); !P_IsEntNil(bullet); bullet = P_NextEnt(bullet)) @@ -2556,32 +2693,32 @@ void V_TickForever(WaveLaneCtx *lane) V_PushParticles(emitter); } - { - V_Emitter emitter = Zi; + // { + // V_Emitter emitter = Zi; - // emitter.kind = V_ParticleKind_BloodTrail; - emitter.kind = V_ParticleKind_BloodDebris; + // // emitter.kind = V_ParticleKind_BloodTrail; + // emitter.kind = V_ParticleKind_BloodDebris; - f32 angle = AngleFromVec2(frame->look); - // f32 angle = 0; - f32 angle_spread = Tau * 0.25; - // f32 angle_spread = Tau; - // f32 angle_spread = 0; + // f32 angle = AngleFromVec2(frame->look); + // // f32 angle = 0; + // f32 angle_spread = Tau * 0.25; + // // f32 angle_spread = Tau; + // // f32 angle_spread = 0; - // f32 speed = 5; - f32 speed = 10; - // f32 speed = 50; - // f32 speed = 100; - f32 speed_spread = speed * 2; + // // f32 speed = 5; + // f32 speed = 10; + // // f32 speed = 50; + // // f32 speed = 100; + // 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.count = Kibi(32) * frame->dt; - V_PushParticles(emitter); - } + // 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.count = Kibi(32) * frame->dt; + // V_PushParticles(emitter); + // } } ////////////////////////////// diff --git a/src/pp/pp_vis/pp_vis_gpu.g b/src/pp/pp_vis/pp_vis_gpu.g index 9226f75c..b3bc5827 100644 --- a/src/pp/pp_vis/pp_vis_gpu.g +++ b/src/pp/pp_vis/pp_vis_gpu.g @@ -18,21 +18,6 @@ Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) result = desc.color; - // // FIXME: Base color on particle desc - // if (desc.kind == V_ParticleKind_Test) - // { - // // result.rgb = Vec3(0, 0, 0); - // result = LinearFromSrgb(Vec4(0.5, 0.1, 0.1, 0.5)); - // } - // else if (desc.kind == V_ParticleKind_Debris) - // { - // result = Color_Orange; - // } - // else if (desc.kind == V_ParticleKind_Smoke) - // { - // result = Vec4(0.15, 0.15, 0.15, 1); - // } - // Apply density { if (desc.kind == V_ParticleKind_Smoke) @@ -49,10 +34,10 @@ Vec4 V_ColorFromParticle(V_ParticleDesc desc, u32 particle_idx, u32 density) // t = saturate(t); // result.rgb *= 1.0 - (t * 0.9); - f32 t = (f32)density / 5; + f32 t = (f32)density / 10; // t = smoothstep(-10, 10, t); // t = smoothstep(-5, 5, t); - t = smoothstep(0, 50, t); + t = smoothstep(-50, 50, t); // result.rgb *= 1.0 - (t * 0.9); // result.a = t; @@ -296,9 +281,6 @@ ComputeShader(V_SimParticlesCS, 64) f32 rand_speed = Norm16(seed0 >> 32); f32 rand_falloff = Norm16(seed0 >> 48); - u64 seed1 = MixU64(seed0); - f32 rand_density = Norm16(seed1 >> 0); - ////////////////////////////// //- Init @@ -335,11 +317,6 @@ ComputeShader(V_SimParticlesCS, 64) StaticAssert(V_ParticlesCap <= (1 << 24)); // particle idx must fit in 24 bits StaticAssert(V_ParticleKind_COUNT <= 0x7F); // particle kind must fit in 7 bits - if (AnyBit(desc.flags, V_ParticleFlag_StainTrail)) - { - packed |= 1 << 31; - } - ////////////////////////////// //- Move @@ -414,8 +391,8 @@ ComputeShader(V_SimParticlesCS, 64) if (is_in_world) { - f32 commit_delta = abs(t_diff) * desc.commit_rate * frame.dt; - particle.commit_accum += commit_delta; + f32 stain_delta = abs(t_diff) * desc.stain_rate * frame.dt; + particle.stain_accum += stain_delta; //- Handle collision V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos]; @@ -449,9 +426,10 @@ ComputeShader(V_SimParticlesCS, 64) { f32 collision_angle = lerp(-0.05 * Tau, 0.05 * Tau, rand_collision_angle); - f32 collision_velocity_falloff = lerp(50, 100, rand_collision_velocity); + // f32 collision_velocity_falloff = lerp(50, 100, rand_collision_velocity); // f32 collision_velocity_falloff = lerp(5000, 10000, rand_collision_velocity); // f32 collision_velocity_falloff = lerp(500, 10000, rand_collision_velocity); + f32 collision_velocity_falloff = lerp(50, 100, rand_collision_velocity); // f32 collision_velocity_falloff = 0; particle.velocity = RotateVec2Angle(particle.velocity, collision_angle); @@ -472,22 +450,26 @@ ComputeShader(V_SimParticlesCS, 64) done = 1; if (AnyBit(desc.flags, V_ParticleFlag_StainWhenPruned)) { - // particle.commit_accum = max(particle.commit_accum, 1); - particle.commit_accum += 1; + // particle.stain_accum = max(particle.stain_accum, 1); + particle.stain_accum += 1; packed |= 1 << 31; } } if (!collision) { - u32 commit_count = floor(particle.commit_accum); - u32 density = commit_count; + u32 stain_count = floor(particle.stain_accum); + u32 density = 1; + u32 commit = packed; + if (stain_count > 0) { - InterlockedMax(cells[cell_pos], packed); - InterlockedAdd(densities[cell_pos], density); - particle.commit_accum -= commit_count; + commit |= (1 << 31); } + + InterlockedMax(cells[cell_pos], commit); + InterlockedAdd(densities[cell_pos], density); + particle.stain_accum -= stain_count; } } else @@ -609,8 +591,8 @@ ComputeShader(V_SimParticlesCS, 64) // if (is_in_world) // { - // f32 commit_delta = abs(t_diff) * desc.commit_rate * frame.dt; - // particle.commit_accum += commit_delta; + // f32 stain_delta = abs(t_diff) * desc.stain_rate * frame.dt; + // particle.stain_accum += stain_delta; // //- Handle collision // V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos]; @@ -667,13 +649,13 @@ ComputeShader(V_SimParticlesCS, 64) // if (prune && AnyBit(desc.flags, V_ParticleFlag_StainWhenPruned)) // { - // particle.commit_accum += 1; + // particle.stain_accum += 1; // } // if (!collision) // { // //- Stain - // u32 stains_count = floor(particle.commit_accum); + // u32 stains_count = floor(particle.stain_accum); // if (stains_count > 0) // { // // TODO: Fixed point @@ -681,7 +663,7 @@ ComputeShader(V_SimParticlesCS, 64) // InterlockedMax(stain_cells[cell_pos], packed); // InterlockedAdd(stain_densities[cell_pos], density); // drynesses[cell_pos] = 0; - // particle.commit_accum -= stains_count; + // particle.stain_accum -= stains_count; // } // //- Draw diff --git a/src/pp/pp_vis/pp_vis_shared.cg b/src/pp/pp_vis/pp_vis_shared.cg index b7fd4b9f..783558f6 100644 --- a/src/pp/pp_vis/pp_vis_shared.cg +++ b/src/pp/pp_vis/pp_vis_shared.cg @@ -11,49 +11,49 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind) V_ParticleDesc result; { PERSIST Readonly V_ParticleFlag flags[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) flags, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) flags, V_ParticlesXList(X) #undef X }; PERSIST Readonly V_ParticleLayer layers[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) layer, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) layer, V_ParticlesXList(X) #undef X }; - PERSIST Readonly f32 commit_rates[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) commit_rate, + PERSIST Readonly f32 stain_rates[V_ParticleKind_COUNT] = { + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) stain_rate, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 pen_rates[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) pen_rate, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) pen_rate, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 r[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) r, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) r, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 g[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) g, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) g, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 b[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) b, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) b, V_ParticlesXList(X) #undef X }; PERSIST Readonly f32 a[V_ParticleKind_COUNT] = { - #define X(name, flags, layer, commit_rate, pen_rate, r, g, b, a) a, + #define X(name, flags, layer, stain_rate, pen_rate, r, g, b, a) a, V_ParticlesXList(X) #undef X }; result.kind = kind; result.flags = flags[kind]; result.layer = layers[kind]; - result.commit_rate = commit_rates[kind]; + result.stain_rate = stain_rates[kind]; result.pen_rate = pen_rates[kind]; result.color = LinearFromSrgb(VEC4(r[kind], g[kind], b[kind], a[kind])); } diff --git a/src/pp/pp_vis/pp_vis_shared.cgh b/src/pp/pp_vis/pp_vis_shared.cgh index 8ee8e6ce..6737ceaf 100644 --- a/src/pp/pp_vis/pp_vis_shared.cgh +++ b/src/pp/pp_vis/pp_vis_shared.cgh @@ -42,7 +42,6 @@ Enum(V_ParticleFlag) V_ParticleFlag_NoPruneWhenStill = (1 << 0), V_ParticleFlag_StainWhenPruned = (1 << 1), V_ParticleFlag_NoReflect = (1 << 2), - V_ParticleFlag_StainTrail = (1 << 3), }; Enum(V_ParticleLayer) @@ -60,30 +59,30 @@ Enum(V_ParticleLayer) /* Name */ None, \ /* Flags */ V_ParticleFlag_None, \ /* Layer */ V_ParticleLayer_Ground, \ - /* Commit rate, pen chance */ 30, 0, \ + /* Stain rate, pen chance */ 30, 0, \ /* Base color */ 0, 0, 0, 0 \ ) \ \ /* Ground particles */ \ X( \ /* Name */ BloodTrail, \ - /* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_StainTrail, \ + /* Flags */ V_ParticleFlag_NoReflect | V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Ground, \ - /* Commit rate, pen chance */ 500, 0.25, \ - /* Base color */ 0.5, 0.1, 0.1, 0.1 \ + /* Stain rate, pen chance */ 30, 0.25, \ + /* Base color */ 0.5, 0.1, 0.1, 0.05 \ ) \ X( \ /* Name */ BloodDebris, \ /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ - /* Commit rate, pen chance */ 30, 0, \ + /* Stain rate, pen chance */ 30, 0, \ /* Base color */ 0.5, 0.1, 0.1, 0.8 \ ) \ X( \ /* Name */ Debris, \ /* Flags */ V_ParticleFlag_StainWhenPruned, \ /* Layer */ V_ParticleLayer_Mid, \ - /* Commit rate, pen chance */ 10000, 0, \ + /* Stain rate, pen chance */ 0, 0, \ /* Base color */ 2, 0.5, 0, 1 \ ) \ \ @@ -92,14 +91,14 @@ Enum(V_ParticleLayer) /* Name */ Smoke, \ /* Flags */ V_ParticleFlag_None, \ /* Layer */ V_ParticleLayer_Air, \ - /* Commit rate, pen chance */ 30, 0, \ + /* Stain rate, pen chance */ 0, 0, \ /* Base color */ 0.15, 0.15, 0.15, 0.5 \ ) \ X( \ /* Name */ BulletTrail, \ /* Flags */ V_ParticleFlag_None, \ /* Layer */ V_ParticleLayer_Air, \ - /* Commit rate, pen chance */ 30, 0, \ + /* Stain rate, pen chance */ 0, 0, \ /* Base color */ 1, 0, 1, 1 \ ) \ \ @@ -108,7 +107,7 @@ Enum(V_ParticleLayer) /* Name */ Test, \ /* Flags */ V_ParticleFlag_None, \ /* Layer */ V_ParticleLayer_Mid, \ - /* Commit rate, pen chance */ 30, 0, \ + /* Stain rate, pen chance */ 0, 0, \ /* Base color */ 1, 1, 0, 1 \ ) \ /* ----------------------------------------------------------------------------------------------------------------------------------- */ @@ -138,7 +137,7 @@ Struct(V_Particle) { i32 kind; // If >= 0, then map to V_ParticleKind. Otherwize initialize particle using emitter at index [abs(kind) - 1] f32 life; - f32 commit_accum; + f32 stain_accum; u32 cells_count; Vec2 pos; Vec2 velocity; @@ -149,7 +148,7 @@ Struct(V_ParticleDesc) V_ParticleKind kind; V_ParticleFlag flags; V_ParticleLayer layer; - f32 commit_rate; + f32 stain_rate; f32 pen_rate; Vec4 color; };