int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int real_velocity) { float cfra = eff->scene->r.cfra; int ret = 0; if (eff->pd && eff->pd->shape==PFIELD_SHAPE_SURFACE && eff->surmd) { /* closest point in the object surface is an effector */ float vec[3]; /* using velocity corrected location allows for easier sliding over effector surface */ copy_v3_v3(vec, point->vel); mul_v3_fl(vec, point->vel_to_frame); add_v3_v3(vec, point->loc); ret = closest_point_on_surface(eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : NULL); efd->size = 0.0f; } else if (eff->pd && eff->pd->shape==PFIELD_SHAPE_POINTS) { if (eff->ob->derivedFinal) { DerivedMesh *dm = eff->ob->derivedFinal; dm->getVertCo(dm, *efd->index, efd->loc); dm->getVertNo(dm, *efd->index, efd->nor); mul_m4_v3(eff->ob->obmat, efd->loc); mul_mat3_m4_v3(eff->ob->obmat, efd->nor); normalize_v3(efd->nor); efd->size = 0.0f; /**/ ret = 1; } } else if (eff->psys) { ParticleData *pa = eff->psys->particles + *efd->index; ParticleKey state; /* exclude the particle itself for self effecting particles */ if (eff->psys == point->psys && *efd->index == point->index) { /* pass */ } else { ParticleSimulationData sim= {NULL}; sim.scene= eff->scene; sim.ob= eff->ob; sim.psys= eff->psys; /* TODO: time from actual previous calculated frame (step might not be 1) */ state.time = cfra - 1.0f; ret = psys_get_particle_state(&sim, *efd->index, &state, 0); /* TODO */ //if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) { // if (pa->dietime < eff->psys->cfra) // eff->flag |= PE_VELOCITY_TO_IMPULSE; //} copy_v3_v3(efd->loc, state.co); /* rather than use the velocity use rotated x-axis (defaults to velocity) */ efd->nor[0] = 1.f; efd->nor[1] = efd->nor[2] = 0.f; mul_qt_v3(state.rot, efd->nor); if (real_velocity) copy_v3_v3(efd->vel, state.vel); efd->size = pa->size; } } else { /* use center of object for distance calculus */ const Object *ob = eff->ob; /* use z-axis as normal*/ normalize_v3_v3(efd->nor, ob->obmat[2]); if (eff->pd && eff->pd->shape == PFIELD_SHAPE_PLANE) { float temp[3], translate[3]; sub_v3_v3v3(temp, point->loc, ob->obmat[3]); project_v3_v3v3(translate, temp, efd->nor); /* for vortex the shape chooses between old / new force */ if (eff->pd->forcefield == PFIELD_VORTEX) add_v3_v3v3(efd->loc, ob->obmat[3], translate); else /* normally efd->loc is closest point on effector xy-plane */ sub_v3_v3v3(efd->loc, point->loc, translate); } else { copy_v3_v3(efd->loc, ob->obmat[3]); } if (real_velocity) copy_v3_v3(efd->vel, eff->velocity); efd->size = 0.0f; ret = 1; } if (ret) { sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc); efd->distance = len_v3(efd->vec_to_point); /* rest length for harmonic effector, will have to see later if this could be extended to other effectors */ if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size) mul_v3_fl(efd->vec_to_point, (efd->distance-eff->pd->f_size)/efd->distance); if (eff->flag & PE_USE_NORMAL_DATA) { copy_v3_v3(efd->vec_to_point2, efd->vec_to_point); copy_v3_v3(efd->nor2, efd->nor); } else { /* for some effectors we need the object center every time */ sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->obmat[3]); normalize_v3_v3(efd->nor2, eff->ob->obmat[2]); } } return ret; }
static Object *boid_find_ground(BoidBrainData *bbd, ParticleData *pa, float ground_co[3], float ground_nor[3]) { BoidParticle *bpa = pa->boid; if (bpa->data.mode == eBoidMode_Climbing) { SurfaceModifierData *surmd = NULL; float x[3], v[3]; surmd = (SurfaceModifierData *)modifiers_findByType(bpa->ground, eModifierType_Surface ); /* take surface velocity into account */ closest_point_on_surface(surmd, pa->state.co, x, NULL, v); add_v3_v3(x, v); /* get actual position on surface */ closest_point_on_surface(surmd, x, ground_co, ground_nor, NULL); return bpa->ground; } else { float zvec[3] = {0.0f, 0.0f, 2000.0f}; ParticleCollision col; ColliderCache *coll; BVHTreeRayHit hit; float radius = 0.0f, t, ray_dir[3]; if (!bbd->sim->colliders) return NULL; memset(&col, 0, sizeof(ParticleCollision)); /* first try to find below boid */ copy_v3_v3(col.co1, pa->state.co); sub_v3_v3v3(col.co2, pa->state.co, zvec); sub_v3_v3v3(ray_dir, col.co2, col.co1); col.f = 0.0f; hit.index = -1; hit.dist = col.original_ray_length = len_v3(ray_dir); col.pce.inside = 0; for (coll = bbd->sim->colliders->first; coll; coll = coll->next) { col.current = coll->ob; col.md = coll->collmd; col.fac1 = col.fac2 = 0.f; if (col.md && col.md->bvhtree) BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); } /* then use that object */ if (hit.index>=0) { t = hit.dist/col.original_ray_length; interp_v3_v3v3(ground_co, col.co1, col.co2, t); normalize_v3_v3(ground_nor, col.pce.nor); return col.hit; } /* couldn't find below, so find upmost deflector object */ add_v3_v3v3(col.co1, pa->state.co, zvec); 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.f = 0.0f; hit.index = -1; hit.dist = col.original_ray_length = len_v3(ray_dir); for (coll = bbd->sim->colliders->first; coll; coll = coll->next) { col.current = coll->ob; col.md = coll->collmd; if (col.md && col.md->bvhtree) BLI_bvhtree_ray_cast(col.md->bvhtree, col.co1, ray_dir, radius, &hit, BKE_psys_collision_neartest_cb, &col); } /* then use that object */ if (hit.index>=0) { t = hit.dist/col.original_ray_length; interp_v3_v3v3(ground_co, col.co1, col.co2, t); normalize_v3_v3(ground_nor, col.pce.nor); return col.hit; } /* default to z=0 */ copy_v3_v3(ground_co, pa->state.co); ground_co[2] = 0; ground_nor[0] = ground_nor[1] = 0.0f; ground_nor[2] = 1.0f; return NULL; } }