From 09435ec149b499fabb112114bcdd24a9b3dc6cda Mon Sep 17 00:00:00 2001 From: Janne Karhu Date: Tue, 2 Nov 2010 21:16:41 +0000 Subject: Oops, particle collisions didn't take simulation subframes into account at all. * This caused nearly all particles to leak through the collision surface if simulation subframes were used and the collision object was moving. * In addition to fixing this I also did some more cleanup of the collision code and refined some of the comments. --- source/blender/blenkernel/BKE_particle.h | 4 +- source/blender/blenkernel/intern/boids.c | 12 ++++-- source/blender/blenkernel/intern/particle_system.c | 50 ++++++++++++---------- 3 files changed, 40 insertions(+), 26 deletions(-) (limited to 'source') diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 1416e1280cf..5bcd69865fc 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -171,7 +171,9 @@ typedef struct ParticleCollision float co1[3], co2[3]; // ray start and end points float ve1[3], ve2[3]; // particle velocities float ray_len; // original length of co2-co1, needed for collision time evaluation - float t; // time of previous collision, needed for substracting face velocity + float f; // time factor of previous collision, needed for substracting face velocity + float cfra; // start of the timestep (during frame change, since previous integer frame) + float dfra; // duration of timestep in frames } ParticleCollision; typedef struct ParticleDrawData { diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c index 5c2c0721972..1bde0639055 100644 --- a/source/blender/blenkernel/intern/boids.c +++ b/source/blender/blenkernel/intern/boids.c @@ -205,7 +205,9 @@ static int rule_avoid_collision(BoidRule *rule, BoidBrainData *bbd, BoidValues * add_v3_v3v3(col.co2, pa->prev_state.co, pa->prev_state.vel); sub_v3_v3v3(ray_dir, col.co2, col.co1); mul_v3_fl(ray_dir, acbr->look_ahead); - col.t = 0.0f; + col.f = 0.0f; + col.cfra = fmod(bbd->cfra-bbd->dfra, 1.0f); + col.dfra = bbd->dfra; hit.index = -1; hit.dist = col.ray_len = len_v3(ray_dir); @@ -772,7 +774,9 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro sub_v3_v3v3(col.co2, pa->state.co, zvec); sub_v3_v3(col.co2, zvec); sub_v3_v3v3(ray_dir, col.co2, col.co1); - col.t = 0.0f; + col.f = 0.0f; + col.cfra = fmod(bbd->cfra-bbd->dfra, 1.0f); + col.dfra = bbd->dfra; hit.index = -1; hit.dist = col.ray_len = len_v3(ray_dir); @@ -796,7 +800,9 @@ static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float *gro sub_v3_v3v3(col.co2, pa->state.co, zvec); sub_v3_v3(col.co2, zvec); sub_v3_v3v3(ray_dir, col.co2, col.co1); - col.t = 0.0f; + col.f = 0.0f; + col.cfra = fmod(bbd->cfra-bbd->dfra, 1.0f); + col.dfra = bbd->dfra; hit.index = -1; hit.dist = col.ray_len = len_v3(ray_dir); diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index a4c0776f5df..504105d5950 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2777,23 +2777,26 @@ void particle_intersect_face(void *userdata, int index, const BVHTreeRay *ray, B MVert *x = col->md->x; MVert *v = col->md->current_v; float vel[3], co1[3], co2[3], uv[2], ipoint[3], temp[3], t; + float x0[3], x1[3], x2[3], x3[3]; + float *t0=x0, *t1=x1, *t2=x2, *t3=(face->v4 ? x3 : NULL); - float *t0, *t1, *t2, *t3; - t0 = x[ face->v1 ].co; - t1 = x[ face->v2 ].co; - t2 = x[ face->v3 ].co; - t3 = face->v4 ? x[ face->v4].co : NULL; + /* move collision face to start of timestep */ + madd_v3_v3v3fl(t0, x[face->v1].co, v[face->v1].co, col->cfra); + madd_v3_v3v3fl(t1, x[face->v2].co, v[face->v2].co, col->cfra); + madd_v3_v3v3fl(t2, x[face->v3].co, v[face->v3].co, col->cfra); + if(t3) + madd_v3_v3v3fl(t3, x[face->v4].co, v[face->v4].co, col->cfra); /* calculate average velocity of face */ - VECCOPY(vel, v[ face->v1 ].co); - VECADD(vel, vel, v[ face->v2 ].co); - VECADD(vel, vel, v[ face->v3 ].co); - mul_v3_fl(vel, 0.33334f); + copy_v3_v3(vel, v[ face->v1 ].co); + add_v3_v3(vel, v[ face->v2 ].co); + add_v3_v3(vel, v[ face->v3 ].co); + mul_v3_fl(vel, 0.33334f*col->dfra); /* substract face velocity, in other words convert to a coordinate system where only the particle moves */ - VECADDFAC(co1, col->co1, vel, -col->t); - VECSUB(co2, col->co2, vel); + madd_v3_v3v3fl(co1, col->co1, vel, -col->f); + sub_v3_v3v3(co2, col->co2, vel); do { @@ -2875,7 +2878,7 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo copy_v3_v3(col.co2, pa->state.co); copy_v3_v3(col.ve1, pa->prev_state.vel); copy_v3_v3(col.ve2, pa->state.vel); - col.t = 0.0f; + col.f = 0.0f; /* override for boids */ if(part->phystype == PART_PHYS_BOIDS) { @@ -2893,6 +2896,9 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo hit.index = -1; hit.dist = col.ray_len = len_v3(ray_dir); + col.cfra = fmod(cfra-dfra, 1.0f); + col.dfra = dfra; + /* even if particle is stationary we want to check for moving colliders */ /* if hit.dist is zero the bvhtree_ray_cast will just ignore everything */ if(hit.dist == 0.0f) @@ -2917,11 +2923,11 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo /* 2. */ if(hit.index>=0) { PartDeflect *pd = col.hit_ob->pd; - float co[3]; /* point of collision */ - float x = hit.dist/col.ray_len; /* location of collision between this iteration */ - float df = col.t + x * (1.0f - col.t); /* time of collision between frame change*/ - float dt1 = (df - col.t) * timestep; /* iteration time of collision (in seconds) */ - float dt2 = (1.0f - df) * timestep; /* time left after collision (in seconds) */ + float co[3]; /* point of collision */ + float x = hit.dist/col.ray_len; /* location factor of collision between this iteration */ + float f = col.f + x * (1.0f - col.f); /* time factor of collision between timestep */ + float dt1 = (f - col.f) * timestep; /* time since previous collision (in seconds) */ + float dt2 = (1.0f - f) * timestep; /* time left after collision (in seconds) */ int through = (BLI_frand() < pd->pdef_perm) ? 1 : 0; /* did particle pass through the collision surface? */ deflections++; @@ -2935,12 +2941,12 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo /* particle dies in collision */ if(through == 0 && (part->flag & PART_DIE_ON_COL || pd->flag & PDEFLE_KILL_PART)) { pa->alive = PARS_DYING; - pa->dietime = pa->state.time + (cfra - pa->state.time) * df; + pa->dietime = pa->state.time + (cfra - pa->state.time) * f; copy_v3_v3(pa->state.co, co); - interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, df); - interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, df); - interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, df); + interp_v3_v3v3(pa->state.vel, pa->prev_state.vel, pa->state.vel, f); + interp_qt_qtqt(pa->state.rot, pa->prev_state.rot, pa->state.rot, f); + interp_v3_v3v3(pa->state.ave, pa->prev_state.ave, pa->state.ave, f); /* particle is dead so we don't need to calculate further */ return; @@ -3073,7 +3079,7 @@ static void deflect_particle(ParticleSimulationData *sim, int p, float dfra, flo copy_v3_v3(col.ve1, v0); copy_v3_v3(col.ve2, pa->state.vel); - col.t = df; + col.f = f; } else { /* final chance to prevent failure, so stick to the surface and hope for the best */ -- cgit v1.2.3