blood wall staining

This commit is contained in:
jacob 2026-02-14 09:08:40 -06:00
parent 6957be38b5
commit fff1b69eff
4 changed files with 131 additions and 101 deletions

View File

@ -2190,7 +2190,7 @@ void V_TickForever(WaveLaneCtx *lane)
quad->quad_uv_to_world_af = wep_uv_to_world_af; quad->quad_uv_to_world_af = wep_uv_to_world_af;
quad->tex = wep.tex; quad->tex = wep.tex;
quad->tex_slice_uv = DivRng2Vec2(wep.tex_rect, wep.tex_dims); quad->tex_slice_uv = DivRng2Vec2(wep.tex_rect, wep.tex_dims);
quad->occluder = V_OccluderKind_Guy; // quad->occluder = V_OccluderKind_Guy;
} }
//- Push body quad //- Push body quad
@ -2560,8 +2560,8 @@ void V_TickForever(WaveLaneCtx *lane)
////////////////////////////// //////////////////////////////
//- Push test emitter //- Push test emitter
if (frame->held_buttons[Button_F]) // if (frame->held_buttons[Button_F])
// if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F]) if (frame->held_buttons[Button_F] && !prev_frame->held_buttons[Button_F])
{ {
{ {
V_Emitter emitter = Zi; V_Emitter emitter = Zi;

View File

@ -346,8 +346,9 @@ ComputeShader(V_SimParticlesCS, 64)
b32 stepped_x = 0; b32 stepped_x = 0;
b32 stepped_y = 0; b32 stepped_y = 0;
// u32 max_iterations = 32; // TODO: Tune this
u32 max_iterations = 128; u32 max_iterations = 128;
b32 done = 0; b32 done = 0;
f32 t_diff = 0; f32 t_diff = 0;
for (u32 iteration_idx = 0; iteration_idx < max_iterations && !done; ++iteration_idx) for (u32 iteration_idx = 0; iteration_idx < max_iterations && !done; ++iteration_idx)
@ -392,35 +393,48 @@ ComputeShader(V_SimParticlesCS, 64)
//- Handle collision //- Handle collision
V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos]; V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos];
if (occluder != V_OccluderKind_None) if (occluder != V_OccluderKind_None)
{
u64 collision_seed = MixU64(V_ParticleCellBasis ^ seed0 ^ particle.cells_count);
f32 rand_collision_angle = Norm16(collision_seed >> 0);
f32 rand_collision_velocity = Norm16(collision_seed >> 16);
f32 rand_collision_penetration = Norm16(collision_seed >> 32);
if (rand_collision_penetration >= desc.pen_rate)
{ {
collision = 1; collision = 1;
done = 1; done = 1;
{ {
if (stepped_x) if (stepped_x)
{
if (!AnyBit(desc.flags, V_ParticleFlag_NoReflect))
{ {
particle.velocity.x *= -1; particle.velocity.x *= -1;
}
t = saturate(t_hit.x); t = saturate(t_hit.x);
} }
else if (stepped_y) else if (stepped_y)
{
if (!AnyBit(desc.flags, V_ParticleFlag_NoReflect))
{ {
particle.velocity.y *= -1; particle.velocity.y *= -1;
}
t = saturate(t_hit.y); t = saturate(t_hit.y);
} }
{ {
u64 collision_seed = MixU64(V_ParticleCollisionBasis ^ seed0 ^ particle.collisions_count);
f32 rand_collision_angle = Norm16(collision_seed >> 0);
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 = 0; 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 = 0;
particle.velocity = RotateVec2Angle(particle.velocity, collision_angle); particle.velocity = RotateVec2Angle(particle.velocity, collision_angle);
particle.velocity *= 1.0f - collision_velocity_falloff; particle.velocity *= 1.0f - saturate(collision_velocity_falloff * frame.dt);
} }
++particle.collisions_count;
} }
} }
}
if (AnyBit(desc.flags, V_ParticleFlag_PruneWhenStill)) if (AnyBit(desc.flags, V_ParticleFlag_PruneWhenStill))
{ {
if (dot(particle.velocity, particle.velocity) < 0.0001) if (dot(particle.velocity, particle.velocity) < 0.0001)
@ -434,6 +448,8 @@ ComputeShader(V_SimParticlesCS, 64)
particle.stain_accum += 1; particle.stain_accum += 1;
} }
if (!collision)
{
//- Stain //- Stain
u32 stains_count = floor(particle.stain_accum); u32 stains_count = floor(particle.stain_accum);
if (stains_count > 0) if (stains_count > 0)
@ -446,8 +462,8 @@ ComputeShader(V_SimParticlesCS, 64)
//- Draw //- Draw
{ {
b32 should_draw_ground = !collision && is_visible && AnyBit(desc.flags, V_ParticleFlag_Ground); b32 should_draw_ground = is_visible && AnyBit(desc.flags, V_ParticleFlag_Ground);
b32 should_draw_air = !collision && is_visible && AnyBit(desc.flags, V_ParticleFlag_Air); b32 should_draw_air = is_visible && AnyBit(desc.flags, V_ParticleFlag_Air);
if (should_draw_ground) if (should_draw_ground)
{ {
@ -462,11 +478,14 @@ ComputeShader(V_SimParticlesCS, 64)
} }
} }
} }
}
else else
{ {
done = 1; done = 1;
prune = 1; prune = 1;
} }
particle.cells_count += 1;
iteration_idx += 1; iteration_idx += 1;
} }
} }
@ -691,7 +710,7 @@ PixelShader(V_CompositePS, V_CompositePSOutput, V_CompositePSInput input)
stain_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, dryness); stain_particle_color = V_ColorFromParticle(particle_kind, particle_idx, density, dryness);
} }
} }
stain_particle_color.rgb *= 1.0 - (0.75 * tile_is_wall); // Darken wall stains stain_particle_color.rgb *= 1.0 - (0.30 * tile_is_wall); // Darken wall stains
stain_particle_color.rgb *= stain_particle_color.a; stain_particle_color.rgb *= stain_particle_color.a;
} }
//- Ground //- Ground

View File

@ -11,37 +11,43 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind)
V_ParticleDesc result; V_ParticleDesc result;
{ {
PERSIST Readonly V_ParticleFlag flags[V_ParticleKind_COUNT] = { PERSIST Readonly V_ParticleFlag flags[V_ParticleKind_COUNT] = {
#define X(name, flags, stain_rate, r, g, b, a) flags, #define X(name, flags, stain_rate, pen_rate, r, g, b, a) flags,
V_ParticlesXList(X) V_ParticlesXList(X)
#undef X #undef X
}; };
PERSIST Readonly f32 stain_rates[V_ParticleKind_COUNT] = { PERSIST Readonly f32 stain_rates[V_ParticleKind_COUNT] = {
#define X(name, flags, stain_rate, r, g, b, a) stain_rate, #define X(name, flags, 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, stain_rate, pen_rate, r, g, b, a) pen_rate,
V_ParticlesXList(X) V_ParticlesXList(X)
#undef X #undef X
}; };
PERSIST Readonly f32 r[V_ParticleKind_COUNT] = { PERSIST Readonly f32 r[V_ParticleKind_COUNT] = {
#define X(name, flags, stain_rate, r, g, b, a) r, #define X(name, flags, stain_rate, pen_rate, r, g, b, a) r,
V_ParticlesXList(X) V_ParticlesXList(X)
#undef X #undef X
}; };
PERSIST Readonly f32 g[V_ParticleKind_COUNT] = { PERSIST Readonly f32 g[V_ParticleKind_COUNT] = {
#define X(name, flags, stain_rate, r, g, b, a) g, #define X(name, flags, stain_rate, pen_rate, r, g, b, a) g,
V_ParticlesXList(X) V_ParticlesXList(X)
#undef X #undef X
}; };
PERSIST Readonly f32 b[V_ParticleKind_COUNT] = { PERSIST Readonly f32 b[V_ParticleKind_COUNT] = {
#define X(name, flags, stain_rate, r, g, b, a) b, #define X(name, flags, stain_rate, pen_rate, r, g, b, a) b,
V_ParticlesXList(X) V_ParticlesXList(X)
#undef X #undef X
}; };
PERSIST Readonly f32 a[V_ParticleKind_COUNT] = { PERSIST Readonly f32 a[V_ParticleKind_COUNT] = {
#define X(name, flags, stain_rate, r, g, b, a) a, #define X(name, flags, stain_rate, pen_rate, r, g, b, a) a,
V_ParticlesXList(X) V_ParticlesXList(X)
#undef X #undef X
}; };
result.flags = flags[kind]; result.flags = flags[kind];
result.stain_rate = stain_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])); result.color = LinearFromSrgb(VEC4(r[kind], g[kind], b[kind], a[kind]));
} }
return result; return result;

View File

@ -174,7 +174,7 @@ Enum(V_OccluderKind)
#define V_ParticleSimBasis 0xb49f2d9e406873b9ull #define V_ParticleSimBasis 0xb49f2d9e406873b9ull
#define V_ParticleColorBasis 0x569aa8341ecc0ea3ull #define V_ParticleColorBasis 0x569aa8341ecc0ea3ull
#define V_ParticleCollisionBasis 0xf60c0cff344b0c5dull #define V_ParticleCellBasis 0xf60c0cff344b0c5dull
#define V_ParticleStainBasis 0x3c64e8226d98d376ull #define V_ParticleStainBasis 0x3c64e8226d98d376ull
Enum(V_ParticleFlag) Enum(V_ParticleFlag)
@ -184,50 +184,54 @@ Enum(V_ParticleFlag)
V_ParticleFlag_Air = (1 << 1), V_ParticleFlag_Air = (1 << 1),
V_ParticleFlag_PruneWhenStill = (1 << 2), V_ParticleFlag_PruneWhenStill = (1 << 2),
V_ParticleFlag_StainWhenPruned = (1 << 3), V_ParticleFlag_StainWhenPruned = (1 << 3),
V_ParticleFlag_NoReflect = (1 << 4),
}; };
// NOTE: Higher particle enum values take priority over lower ones // NOTE: Higher particle enum values take priority over lower ones
#define V_ParticlesXList(X) \ #define V_ParticlesXList(X) \
X( \ X( \
None, \ /* Name */ None, \
V_ParticleFlag_None, \ /* Flags */ V_ParticleFlag_None, \
0, \ /* Stain rate, pen chance */ 0, 0, \
0, 0, 0, 0 \ /* Base color */ 0, 0, 0, 0 \
) \ ) \
\
/* Ground particles */ \ /* Ground particles */ \
X( \ X( \
Blood, \ /* Name */ Blood, \
V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill, \ /* Flags */ V_ParticleFlag_None | V_ParticleFlag_NoReflect, \
500, \ /* Stain rate, pen chance */ 500, 0.25, \
0.5, 0.1, 0.1, 1 \ /* Base color */ 0.5, 0.1, 0.1, 1 \
) \ ) \
X( \ X( \
Debris, \ /* Name */ Debris, \
V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill | V_ParticleFlag_StainWhenPruned , \ /* Flags */ V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill | V_ParticleFlag_StainWhenPruned, \
0, \ /* Stain rate, pen chance */ 0, 0, \
1, 0.5, 0, 1 \ /* Base color */ 1, 0.5, 0, 1 \
) \ ) \
\
/* Air particles */ \ /* Air particles */ \
X( \ X( \
Smoke, \ /* Name */ Smoke, \
V_ParticleFlag_Air, \ /* Flags */ V_ParticleFlag_Air, \
0, \ /* Stain rate, pen chance */ 0, 0, \
0.15, 0.15, 0.15, 0.5 \ /* Base color */ 0.15, 0.15, 0.15, 0.5 \
) \ ) \
X( \ X( \
BulletTrail, \ /* Name */ BulletTrail, \
V_ParticleFlag_Air, \ /* Flags */ V_ParticleFlag_Air, \
0, \ /* Stain rate, pen chance */ 0, 0, \
1, 0, 1, 1 \ /* Base color */ 1, 0, 1, 1 \
) \ ) \
\
/* Test particles */ \ /* Test particles */ \
X( \ X( \
Test, \ /* Name */ Test, \
V_ParticleFlag_PruneWhenStill, \ /* Flags */ V_ParticleFlag_PruneWhenStill, \
0, \ /* Stain rate, pen chance */ 0, 0, \
1, 1, 0, 1 \ /* Base color */ 1, 1, 0, 1 \
) \ ) \
/* -------------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */
Enum(V_ParticleKind) Enum(V_ParticleKind)
{ {
@ -255,7 +259,7 @@ Struct(V_Particle)
i32 kind; // If >= 0, then map to V_ParticleKind. Otherwize initialize particle using emitter at index [abs(kind) - 1] i32 kind; // If >= 0, then map to V_ParticleKind. Otherwize initialize particle using emitter at index [abs(kind) - 1]
f32 life; f32 life;
f32 stain_accum; f32 stain_accum;
u32 collisions_count; u32 cells_count;
Vec2 pos; Vec2 pos;
Vec2 velocity; Vec2 velocity;
}; };
@ -264,6 +268,7 @@ Struct(V_ParticleDesc)
{ {
V_ParticleFlag flags; V_ParticleFlag flags;
f32 stain_rate; f32 stain_rate;
f32 pen_rate;
Vec4 color; Vec4 color;
}; };