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

View File

@ -346,8 +346,9 @@ ComputeShader(V_SimParticlesCS, 64)
b32 stepped_x = 0;
b32 stepped_y = 0;
// u32 max_iterations = 32;
// TODO: Tune this
u32 max_iterations = 128;
b32 done = 0;
f32 t_diff = 0;
for (u32 iteration_idx = 0; iteration_idx < max_iterations && !done; ++iteration_idx)
@ -393,32 +394,45 @@ ComputeShader(V_SimParticlesCS, 64)
V_OccluderKind occluder = (V_OccluderKind)occluders[cell_pos];
if (occluder != V_OccluderKind_None)
{
collision = 1;
done = 1;
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;
done = 1;
{
if (stepped_x)
{
if (!AnyBit(desc.flags, V_ParticleFlag_NoReflect))
{
particle.velocity.x *= -1;
}
t = saturate(t_hit.x);
}
else if (stepped_y)
{
if (!AnyBit(desc.flags, V_ParticleFlag_NoReflect))
{
particle.velocity.y *= -1;
}
t = saturate(t_hit.y);
}
{
f32 collision_angle = lerp(-0.05 * Tau, 0.05 * Tau, rand_collision_angle);
if (stepped_x)
{
particle.velocity.x *= -1;
t = saturate(t_hit.x);
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 *= 1.0f - saturate(collision_velocity_falloff * frame.dt);
}
}
else if (stepped_y)
{
particle.velocity.y *= -1;
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_velocity_falloff = lerp(0, 1, rand_collision_velocity);
f32 collision_velocity_falloff = 0;
particle.velocity = RotateVec2Angle(particle.velocity, collision_angle);
particle.velocity *= 1.0f - collision_velocity_falloff;
}
++particle.collisions_count;
}
}
if (AnyBit(desc.flags, V_ParticleFlag_PruneWhenStill))
@ -434,31 +448,34 @@ ComputeShader(V_SimParticlesCS, 64)
particle.stain_accum += 1;
}
//- Stain
u32 stains_count = floor(particle.stain_accum);
if (stains_count > 0)
if (!collision)
{
InterlockedMax(stain_cells[cell_pos], packed);
InterlockedAdd(stain_densities[cell_pos], stains_count);
drynesses[cell_pos] = 0;
particle.stain_accum -= stains_count;
}
//- Draw
{
b32 should_draw_ground = !collision && is_visible && AnyBit(desc.flags, V_ParticleFlag_Ground);
b32 should_draw_air = !collision && is_visible && AnyBit(desc.flags, V_ParticleFlag_Air);
if (should_draw_ground)
//- Stain
u32 stains_count = floor(particle.stain_accum);
if (stains_count > 0)
{
InterlockedMax(ground_cells[cell_pos], packed);
InterlockedAdd(ground_densities[cell_pos], 1);
InterlockedMax(stain_cells[cell_pos], packed);
InterlockedAdd(stain_densities[cell_pos], stains_count);
drynesses[cell_pos] = 0;
particle.stain_accum -= stains_count;
}
if (should_draw_air)
//- Draw
{
InterlockedMax(air_cells[cell_pos], packed);
InterlockedAdd(air_densities[cell_pos], 1);
b32 should_draw_ground = is_visible && AnyBit(desc.flags, V_ParticleFlag_Ground);
b32 should_draw_air = is_visible && AnyBit(desc.flags, V_ParticleFlag_Air);
if (should_draw_ground)
{
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);
}
}
}
}
@ -467,6 +484,8 @@ ComputeShader(V_SimParticlesCS, 64)
done = 1;
prune = 1;
}
particle.cells_count += 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.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;
}
//- Ground

View File

@ -11,37 +11,43 @@ V_ParticleDesc V_DescFromParticleKind(V_ParticleKind kind)
V_ParticleDesc result;
{
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)
#undef X
};
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)
#undef X
};
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)
#undef X
};
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)
#undef X
};
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)
#undef X
};
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)
#undef X
};
result.flags = flags[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]));
}
return result;

View File

@ -174,60 +174,64 @@ Enum(V_OccluderKind)
#define V_ParticleSimBasis 0xb49f2d9e406873b9ull
#define V_ParticleColorBasis 0x569aa8341ecc0ea3ull
#define V_ParticleCollisionBasis 0xf60c0cff344b0c5dull
#define V_ParticleCellBasis 0xf60c0cff344b0c5dull
#define V_ParticleStainBasis 0x3c64e8226d98d376ull
Enum(V_ParticleFlag)
{
V_ParticleFlag_None = 0,
V_ParticleFlag_Ground = (1 << 0),
V_ParticleFlag_Air = (1 << 1),
V_ParticleFlag_PruneWhenStill = (1 << 2),
V_ParticleFlag_StainWhenPruned = (1 << 3),
V_ParticleFlag_None = 0,
V_ParticleFlag_Ground = (1 << 0),
V_ParticleFlag_Air = (1 << 1),
V_ParticleFlag_PruneWhenStill = (1 << 2),
V_ParticleFlag_StainWhenPruned = (1 << 3),
V_ParticleFlag_NoReflect = (1 << 4),
};
// NOTE: Higher particle enum values take priority over lower ones
#define V_ParticlesXList(X) \
X( \
None, \
V_ParticleFlag_None, \
0, \
0, 0, 0, 0 \
) \
/* Ground particles */ \
X( \
Blood, \
V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill, \
500, \
0.5, 0.1, 0.1, 1 \
) \
X( \
Debris, \
V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill | V_ParticleFlag_StainWhenPruned , \
0, \
1, 0.5, 0, 1 \
) \
/* Air particles */ \
X( \
Smoke, \
V_ParticleFlag_Air, \
0, \
0.15, 0.15, 0.15, 0.5 \
) \
X( \
BulletTrail, \
V_ParticleFlag_Air, \
0, \
1, 0, 1, 1 \
) \
/* Test particles */ \
X( \
Test, \
V_ParticleFlag_PruneWhenStill, \
0, \
1, 1, 0, 1 \
) \
/* -------------------------------------------------------------------------------- */
#define V_ParticlesXList(X) \
X( \
/* Name */ None, \
/* Flags */ V_ParticleFlag_None, \
/* Stain rate, pen chance */ 0, 0, \
/* Base color */ 0, 0, 0, 0 \
) \
\
/* Ground particles */ \
X( \
/* Name */ Blood, \
/* Flags */ V_ParticleFlag_None | V_ParticleFlag_NoReflect, \
/* Stain rate, pen chance */ 500, 0.25, \
/* Base color */ 0.5, 0.1, 0.1, 1 \
) \
X( \
/* Name */ Debris, \
/* Flags */ V_ParticleFlag_Ground | V_ParticleFlag_PruneWhenStill | V_ParticleFlag_StainWhenPruned, \
/* Stain rate, pen chance */ 0, 0, \
/* Base color */ 1, 0.5, 0, 1 \
) \
\
/* Air particles */ \
X( \
/* Name */ Smoke, \
/* Flags */ V_ParticleFlag_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Base color */ 0.15, 0.15, 0.15, 0.5 \
) \
X( \
/* Name */ BulletTrail, \
/* Flags */ V_ParticleFlag_Air, \
/* Stain rate, pen chance */ 0, 0, \
/* Base color */ 1, 0, 1, 1 \
) \
\
/* Test particles */ \
X( \
/* Name */ Test, \
/* Flags */ V_ParticleFlag_PruneWhenStill, \
/* Stain rate, pen chance */ 0, 0, \
/* Base color */ 1, 1, 0, 1 \
) \
/* -------------------------------------------------------------------------- */
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]
f32 life;
f32 stain_accum;
u32 collisions_count;
u32 cells_count;
Vec2 pos;
Vec2 velocity;
};
@ -264,6 +268,7 @@ Struct(V_ParticleDesc)
{
V_ParticleFlag flags;
f32 stain_rate;
f32 pen_rate;
Vec4 color;
};