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:
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user