Skip to content

Commit 93dfafa

Browse files
committed
particle lifetimes (very wip)
1 parent f9096f7 commit 93dfafa

File tree

4 files changed

+87
-58
lines changed

4 files changed

+87
-58
lines changed

binary/src/flex_solver.cpp

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,22 @@ void FlexBuffers::destroy() {
2626
// clears all particles
2727
void FlexSolver::reset() {
2828
reset_cloth();
29-
copy_particles.elementCount = 0;
3029
copy_active.elementCount = 0;
3130
particle_queue.clear();
3231

3332
// clear diffuse
3433
NvFlexSetDiffuseParticles(solver, NULL, NULL, 0);
3534
hosts.diffuse_count[0] = 0;
3635

37-
// These buffers are getted AND setted, so we need to make sure they are mapped before adding more particles
38-
NvFlexMap(buffers.particle_pos, eNvFlexMapWait);
36+
memset(hosts.particle_lifetime, 0, sizeof(float) * get_max_particles());
37+
38+
/*
39+
NvFlexMap(buffers.particle_pos, eNvFlexMapWait); // These buffers are getted AND setted, so we need to make sure they are mapped before adding more particles
3940
NvFlexUnmap(buffers.particle_pos);
4041
if (get_parameter("reaction_forces") > 2) {
4142
NvFlexMap(buffers.particle_vel, eNvFlexMapWait);
4243
NvFlexUnmap(buffers.particle_vel);
43-
}
44+
}*/
4445
}
4546

4647
void FlexSolver::reset_cloth() {
@@ -50,7 +51,7 @@ void FlexSolver::reset_cloth() {
5051
}
5152

5253
int FlexSolver::get_active_particles() {
53-
return copy_particles.elementCount + particle_queue.size();
54+
return copy_active.elementCount + particle_queue.size();
5455
}
5556

5657
int FlexSolver::get_active_triangles() {
@@ -78,33 +79,36 @@ std::vector<FlexMesh>* FlexSolver::get_meshes() {
7879
}
7980

8081
// Resets particle to base parameters
81-
void FlexSolver::set_particle(int index, Particle particle) {
82-
hosts.particle_pos[index] = particle.pos;
83-
hosts.particle_smooth[index] = particle.pos;
84-
hosts.particle_vel[index] = particle.vel;
85-
hosts.particle_phase[index] = particle.phase;
86-
hosts.particle_active[index] = index;
87-
hosts.particle_ani0[index] = Vector4D(0, 0, 0, 0);
88-
hosts.particle_ani1[index] = Vector4D(0, 0, 0, 0);
89-
hosts.particle_ani2[index] = Vector4D(0, 0, 0, 0);
82+
void FlexSolver::set_particle(int particle_index, int active_index, Particle particle) {
83+
hosts.particle_pos[particle_index] = particle.pos;
84+
hosts.particle_smooth[particle_index] = particle.pos;
85+
hosts.particle_vel[particle_index] = particle.vel;
86+
hosts.particle_phase[particle_index] = particle.phase;
87+
hosts.particle_lifetime[particle_index] = particle.lifetime;
88+
hosts.particle_ani0[particle_index] = Vector4D(0, 0, 0, 0);
89+
hosts.particle_ani1[particle_index] = Vector4D(0, 0, 0, 0);
90+
hosts.particle_ani2[particle_index] = Vector4D(0, 0, 0, 0);
91+
hosts.particle_active[active_index] = particle_index;
9092
}
9193

9294
void FlexSolver::add_particle(Particle particle) {
9395
if (solver == nullptr) return;
9496
if (get_active_particles() >= get_max_particles()) return;
9597

96-
set_particle(get_active_particles(), particle);
98+
//set_particle(get_active_particles(), particle);
9799
particle_queue.push_back(particle);
98100
}
99101

100102
inline int _grid(int x, int y, int x_size) { return y * x_size + x; }
101-
void FlexSolver::add_cloth(Particle particle, Vector2D size) {
103+
void FlexSolver::add_cloth(Particle particle, Vector2D size) { // TODO: FIX
102104
float radius = parameters.solidRestDistance;
103105
particle.phase = FlexPhase::CLOTH; // force to cloth
106+
particle.lifetime = FLT_MAX; // no die
104107
particle.pos.x -= size.x * radius / 2.0;
105108
particle.pos.y -= size.y * radius / 2.0;
109+
106110
NvFlexCopyDesc desc;
107-
desc.srcOffset = copy_particles.elementCount;
111+
desc.srcOffset = copy_active.elementCount;
108112
desc.dstOffset = desc.srcOffset;
109113
desc.elementCount = 0;
110114

@@ -123,7 +127,7 @@ void FlexSolver::add_cloth(Particle particle, Vector2D size) {
123127
if (get_active_particles() >= get_max_particles()) break;
124128

125129
// Add particle
126-
int index = copy_particles.elementCount++;
130+
int index = copy_active.elementCount++;
127131
particle_pos[index] = particle.pos + Vector4D(x * radius, y * radius, 0, 0);
128132
particle_vel[index] = particle.vel;
129133
particle_phase[index] = particle.phase; // force to cloth
@@ -181,7 +185,7 @@ void FlexSolver::add_cloth(Particle particle, Vector2D size) {
181185
NvFlexSetVelocities(solver, buffers.particle_vel, &desc);
182186
NvFlexSetPhases(solver, buffers.particle_phase, &desc);
183187
NvFlexSetActive(solver, buffers.particle_active, &desc);
184-
NvFlexSetActiveCount(solver, copy_particles.elementCount);
188+
NvFlexSetActiveCount(solver, copy_active.elementCount);
185189
NvFlexSetDynamicTriangles(solver, buffers.triangle_indices, NULL, copy_triangles.elementCount);
186190
NvFlexSetSprings(solver, buffers.spring_indices, buffers.spring_restlengths, buffers.spring_stiffness, copy_springs.elementCount);
187191
}
@@ -224,31 +228,49 @@ bool FlexSolver::tick(float dt, NvFlexMapFlags wait) {
224228

225229
// Avoid ticking if the deltatime ends up being zero, as it invalidates the simulation
226230
dt *= get_parameter("timescale");
227-
if (dt > 0 && get_active_particles() > 0) {
231+
if (dt > 0 && (get_active_particles() > 0 || get_active_diffuse() > 0)) {
232+
233+
// Invalidate particles with bad lifetimes
234+
// TODO: This could potentially be modified to work in a compute shader during FleX updates, would this be faster? (is this algorithm even parallelizable?)
235+
bool active_modified = false;
236+
for (int i = 0; i < copy_active.elementCount; i++) {
237+
float& particle_life = hosts.particle_lifetime[hosts.particle_active[i]];
238+
particle_life -= dt;
239+
if (particle_life <= 0) {
240+
hosts.particle_active[i] = hosts.particle_active[--copy_active.elementCount];
241+
active_modified = true;
242+
i--; // we just shifted a particle that wont be iterated over, go back and check it
243+
}
244+
}
245+
228246
// Map positions to CPU memory
229247
if (!particle_queue.empty()) {
248+
// These are both getted AND setted, so we *have* to map them
249+
NvFlexGetVelocities(solver, buffers.particle_vel, NULL);
250+
hosts.particle_pos = (Vector4D*)NvFlexMap(buffers.particle_pos, eNvFlexMapWait);
251+
hosts.particle_vel = (Vector*)NvFlexMap(buffers.particle_vel, eNvFlexMapWait);
230252
// Add queued particles
231-
for (int i = 0; i < particle_queue.size(); i++) {
232-
int particle_index = copy_particles.elementCount + i;
233-
//particle_pos[particle_index] = particle_queue[i].pos;
234-
set_particle(particle_index, particle_queue[i]);
253+
int particle_index = 0;
254+
for (int i = 0; particle_index < particle_queue.size() && i < get_max_particles(); i++) {
255+
if (hosts.particle_lifetime[i] <= 0) {
256+
set_particle(i, copy_active.elementCount++, particle_queue[particle_index++]);
257+
}
235258
}
259+
NvFlexUnmap(buffers.particle_pos);
260+
NvFlexUnmap(buffers.particle_vel);
236261

237-
// Only copy what we just added
238-
NvFlexCopyDesc desc;
239-
desc.dstOffset = copy_particles.elementCount;
240-
desc.elementCount = particle_queue.size();
241-
desc.srcOffset = desc.dstOffset;
242-
243-
copy_particles.elementCount += particle_queue.size();
244262
particle_queue.clear();
245-
263+
246264
// Update particle information
247-
NvFlexSetParticles(solver, buffers.particle_pos, &desc);
248-
NvFlexSetVelocities(solver, buffers.particle_vel, &desc);
249-
NvFlexSetPhases(solver, buffers.particle_phase, &desc);
250-
NvFlexSetActive(solver, buffers.particle_active, &desc);
251-
NvFlexSetActiveCount(solver, copy_particles.elementCount);
265+
NvFlexSetParticles(solver, buffers.particle_pos, NULL);
266+
NvFlexSetVelocities(solver, buffers.particle_vel, NULL);
267+
NvFlexSetPhases(solver, buffers.particle_phase, NULL);
268+
active_modified = true;
269+
}
270+
271+
if (active_modified) {
272+
NvFlexSetActive(solver, buffers.particle_active, &copy_active);
273+
NvFlexSetActiveCount(solver, copy_active.elementCount);
252274
}
253275

254276
// write to device (async)
@@ -269,23 +291,23 @@ bool FlexSolver::tick(float dt, NvFlexMapFlags wait) {
269291
NvFlexUpdateSolver(solver, dt, (int)get_parameter("substeps"), false);
270292

271293
// read back (async)
272-
NvFlexGetParticles(solver, buffers.particle_pos, &copy_particles);
294+
NvFlexGetParticles(solver, buffers.particle_pos, NULL);
273295
NvFlexGetDiffuseParticles(solver, buffers.diffuse_pos, buffers.diffuse_vel, buffers.diffuse_count);
274296

275297
if (get_active_triangles() > 0) {
276-
NvFlexGetNormals(solver, buffers.triangle_normals, &copy_particles);
298+
NvFlexGetNormals(solver, buffers.triangle_normals, NULL);
277299
}
278300

279301
if (parameters.anisotropyScale != 0) {
280-
NvFlexGetAnisotropy(solver, buffers.particle_ani0, buffers.particle_ani1, buffers.particle_ani2, &copy_particles);
302+
NvFlexGetAnisotropy(solver, buffers.particle_ani0, buffers.particle_ani1, buffers.particle_ani2, NULL);
281303
}
282304

283305
if (parameters.smoothing != 0) {
284-
NvFlexGetSmoothParticles(solver, buffers.particle_smooth, &copy_particles);
306+
NvFlexGetSmoothParticles(solver, buffers.particle_smooth, NULL);
285307
}
286308

287309
if (get_parameter("reaction_forces") > 1) {
288-
NvFlexGetVelocities(solver, buffers.particle_vel, &copy_particles);
310+
NvFlexGetVelocities(solver, buffers.particle_vel, NULL);
289311
NvFlexGetContacts(solver, buffers.contact_planes, buffers.contact_vel, buffers.contact_indices, buffers.contact_count);
290312
}
291313

@@ -542,7 +564,12 @@ FlexSolver::FlexSolver(NvFlexLibrary* library, int particles) {
542564
buffers.spring_restlengths = buffers.init(library, &hosts.spring_restlengths, particles * 2);
543565
buffers.spring_stiffness = buffers.init(library, &hosts.spring_stiffness, particles * 2);
544566

567+
// This is the only exception buffer, as it is never sent to the GPU
568+
hosts.particle_lifetime = (float*)malloc(sizeof(float) * particles);
569+
545570
force_field_callback = NvFlexExtCreateForceFieldCallback(solver);
571+
572+
reset();
546573
};
547574

548575
// Free memory
@@ -562,6 +589,7 @@ FlexSolver::~FlexSolver() {
562589

563590
// Free buffers / hosts
564591
buffers.destroy();
592+
free((void*)hosts.particle_lifetime);
565593

566594
NvFlexDestroySolver(solver); // bye bye solver
567595
solver = nullptr;

binary/src/flex_solver.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ enum FlexPhase {
1616
struct Particle {
1717
Vector4D pos = Vector4D(0, 0, 0, 1);
1818
Vector vel = Vector(0, 0, 0);
19-
int phase = 0;
19+
int phase = FlexPhase::WATER;
20+
float lifetime = FLT_MAX;
2021
};
2122

2223
// Holds flex buffer information
@@ -68,6 +69,7 @@ struct FlexHosts {
6869
int* particle_phase;
6970
int* particle_active;
7071
Vector4D* particle_smooth;
72+
float* particle_lifetime;
7173

7274
Vector4D* particle_ani0;
7375
Vector4D* particle_ani1;
@@ -105,7 +107,6 @@ class FlexSolver {
105107
NvFlexExtForceFieldCallback* force_field_callback = nullptr; // unsure why this is required. crashes without it
106108
NvFlexParams parameters = NvFlexParams();
107109
NvFlexCopyDesc copy_active = NvFlexCopyDesc();
108-
NvFlexCopyDesc copy_particles = NvFlexCopyDesc();
109110
NvFlexCopyDesc copy_triangles = NvFlexCopyDesc();
110111
NvFlexCopyDesc copy_springs = NvFlexCopyDesc();
111112
NvFlexSolverDesc solver_description = NvFlexSolverDesc(); // stores stuff such as max particles
@@ -114,6 +115,8 @@ class FlexSolver {
114115
std::vector<Particle> particle_queue;
115116
std::vector<NvFlexExtForceField> force_field_queue;
116117

118+
void set_particle(int particle_index, int active_index, Particle particle);
119+
117120
public:
118121
FlexBuffers buffers;
119122
FlexHosts hosts;
@@ -130,7 +133,6 @@ class FlexSolver {
130133

131134
void add_particle(Particle particle);
132135
void add_cloth(Particle particle, Vector2D size);
133-
void set_particle(int index, Particle particle);
134136
void add_force_field(NvFlexExtForceField force_field);
135137

136138
bool tick(float dt, NvFlexMapFlags wait);

binary/src/main.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,38 +47,37 @@ LUA_FUNCTION(FLEXSOLVER_GarbageCollect) {
4747
// Table on the top of the stack is parsed
4848
// ParticleData = {velocity = Vector(), mass = 1}
4949
Particle parse_particle(ILuaBase* LUA) {
50-
Vector vel = Vector(0, 0, 0);
51-
float inv_mass = 1;
52-
int phase = FlexPhase::WATER;
50+
Particle particle = Particle();
5351

5452
if (LUA->GetType(-1) == Type::Table) {
5553
// Get velocity (default = Vector())
5654
LUA->GetField(-1, "vel");
5755
if (LUA->GetType(-1) == Type::Vector) {
58-
vel = LUA->GetVector(-1);
56+
particle.vel = LUA->GetVector(-1);
5957
}
6058
LUA->Pop();
6159

6260
// Get mass (default = 1)
6361
LUA->GetField(-1, "mass");
6462
if (LUA->GetType(-1) == Type::Number) {
65-
inv_mass = 1.0 / LUA->GetNumber(-1);
63+
particle.pos.w = 1.0 / LUA->GetNumber(-1);
6664
}
6765
LUA->Pop();
6866

6967
// Gets phase (default = self colliding fluid)
7068
LUA->GetField(-1, "phase"); // literally nobody is going to use this, but whatever
7169
if (LUA->GetType(-1) == Type::Number) {
72-
phase = NvFlexMakePhase(0, LUA->GetNumber(1));
70+
particle.phase = NvFlexMakePhase(0, LUA->GetNumber(-1));
7371
}
7472
LUA->Pop();
75-
76-
}
7773

78-
Particle particle;
79-
particle.pos.w = inv_mass;
80-
particle.vel = vel;
81-
particle.phase = phase;
74+
// how long the fluid lasts in simulation seconds (default = infinite)
75+
LUA->GetField(-1, "lifetime");
76+
if (LUA->GetType(-1) == Type::Number) {
77+
particle.lifetime = LUA->GetNumber(-1) * CM_2_INCH; // dont forget to multiply by our fucked up timescale speedup
78+
}
79+
LUA->Pop();
80+
}
8281

8382
return particle;
8483
}

lua/weapons/weapon_gw2_watergun.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function SWEP:SecondaryAttack()
7575
mat:SetScale(Vector(sprite_size, sprite_size, sprite_size))
7676
mat:SetTranslation(owner:EyePos() + forward * 40 * sprite_size)
7777

78-
gwater2.solver:AddCube(mat, Vector(33, 33, 33), {vel = forward * 100})
78+
gwater2.solver:AddCube(mat, Vector(33, 33, 33), {vel = forward * 100, lifetime = 5})
7979
end
8080

8181
function SWEP:Reload()

0 commit comments

Comments
 (0)