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.
This commit is contained in:
2010-11-02 21:16:41 +00:00
parent 130088300b
commit 09435ec149
3 changed files with 40 additions and 26 deletions

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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 */