/* axis is using another define!!! */ static bool calc_curve_deform(Scene *scene, Object *par, float co[3], const short axis, CurveDeform *cd, float r_quat[4]) { Curve *cu = par->data; float fac, loc[4], dir[3], new_quat[4], radius; short index; const bool is_neg_axis = (axis > 2); /* to be sure, mostly after file load */ if (ELEM(NULL, par->curve_cache, par->curve_cache->path)) { #ifdef CYCLIC_DEPENDENCY_WORKAROUND BKE_displist_make_curveTypes(scene, par, false); #endif if (par->curve_cache->path == NULL) { return 0; // happens on append and cyclic dependencies... } } /* options */ if (is_neg_axis) { index = axis - 3; if (cu->flag & CU_STRETCH) fac = (-co[index] - cd->dmax[index]) / (cd->dmax[index] - cd->dmin[index]); else fac = -(co[index] - cd->dmax[index]) / (par->curve_cache->path->totdist); } else { index = axis; if (cu->flag & CU_STRETCH) { fac = (co[index] - cd->dmin[index]) / (cd->dmax[index] - cd->dmin[index]); } else { if (LIKELY(par->curve_cache->path->totdist > FLT_EPSILON)) { fac = +(co[index] - cd->dmin[index]) / (par->curve_cache->path->totdist); } else { fac = 0.0f; } } } if (where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ float quat[4], cent[3]; if (cd->no_rot_axis) { /* set by caller */ /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than * changing the axis before calculating the tilt but serves much the same purpose */ float dir_flat[3] = {0, 0, 0}, q[4]; copy_v3_v3(dir_flat, dir); dir_flat[cd->no_rot_axis - 1] = 0.0f; normalize_v3(dir); normalize_v3(dir_flat); rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ mul_qt_qtqt(new_quat, q, new_quat); } /* Logic for 'cent' orientation * * * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. * * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark. * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise * Notice X,Y,Z Up all have light colors and each ordered CCW. * * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell * * note: moved functions into quat_apply_track/vec_apply_track * */ copy_qt_qt(quat, new_quat); copy_v3_v3(cent, co); /* zero the axis which is not used, * the big block of text above now applies to these 3 lines */ quat_apply_track(quat, axis, (axis == 0 || axis == 2) ? 1 : 0); /* up flag is a dummy, set so no rotation is done */ vec_apply_track(cent, axis); cent[index] = 0.0f; /* scale if enabled */ if (cu->flag & CU_PATH_RADIUS) mul_v3_fl(cent, radius); /* local rotation */ normalize_qt(quat); mul_qt_v3(quat, cent); /* translation */ add_v3_v3v3(co, cent, loc); if (r_quat) copy_qt_qt(r_quat, quat); return 1; } return 0; }
/* axis is using another define!!! */ static int calc_curve_deform(Scene *scene, Object *par, float *co, short axis, CurveDeform *cd, float *quatp) { Curve *cu= par->data; float fac, loc[4], dir[3], new_quat[4], radius; short /*upflag, */ index; index= axis-1; if(index>2) index -= 3; /* negative */ /* to be sure, mostly after file load */ if(cu->path==NULL) { makeDispListCurveTypes(scene, par, 0); if(cu->path==NULL) return 0; // happens on append... } /* options */ if(ELEM3(axis, OB_NEGX+1, OB_NEGY+1, OB_NEGZ+1)) { /* OB_NEG# 0-5, MOD_CURVE_POS# 1-6 */ if(cu->flag & CU_STRETCH) fac= (-co[index]-cd->dmax[index])/(cd->dmax[index] - cd->dmin[index]); else fac= (cd->dloc[index])/(cu->path->totdist) - (co[index]-cd->dmax[index])/(cu->path->totdist); } else { if(cu->flag & CU_STRETCH) fac= (co[index]-cd->dmin[index])/(cd->dmax[index] - cd->dmin[index]); else fac= (cd->dloc[index])/(cu->path->totdist) + (co[index]-cd->dmin[index])/(cu->path->totdist); } #if 0 // XXX old animation system /* we want the ipo to work on the default 100 frame range, because there's no actual time involved in path position */ // huh? by WHY!!!!???? - Aligorith if(cu->ipo) { fac*= 100.0f; if(calc_ipo_spec(cu->ipo, CU_SPEED, &fac)==0) fac/= 100.0; } #endif // XXX old animation system if( where_on_path_deform(par, fac, loc, dir, new_quat, &radius)) { /* returns OK */ float quat[4], cent[3]; #if 0 // XXX - 2.4x Z-Up, Now use bevel tilt. if(cd->no_rot_axis) /* set by caller */ dir[cd->no_rot_axis-1]= 0.0f; /* -1 for compatibility with old track defines */ vec_to_quat( quat,dir, axis-1, upflag); /* the tilt */ if(loc[3]!=0.0) { normalize_v3(dir); q[0]= (float)cos(0.5*loc[3]); fac= (float)sin(0.5*loc[3]); q[1]= -fac*dir[0]; q[2]= -fac*dir[1]; q[3]= -fac*dir[2]; mul_qt_qtqt(quat, q, quat); } #endif if(cd->no_rot_axis) { /* set by caller */ /* this is not exactly the same as 2.4x, since the axis is having rotation removed rather than * changing the axis before calculating the tilt but serves much the same purpose */ float dir_flat[3]={0,0,0}, q[4]; copy_v3_v3(dir_flat, dir); dir_flat[cd->no_rot_axis-1]= 0.0f; normalize_v3(dir); normalize_v3(dir_flat); rotation_between_vecs_to_quat(q, dir, dir_flat); /* Could this be done faster? */ mul_qt_qtqt(new_quat, q, new_quat); } /* Logic for 'cent' orientation * * * The way 'co' is copied to 'cent' may seem to have no meaning, but it does. * * Use a curve modifier to stretch a cube out, color each side RGB, positive side light, negative dark. * view with X up (default), from the angle that you can see 3 faces RGB colors (light), anti-clockwise * Notice X,Y,Z Up all have light colors and each ordered CCW. * * Now for Neg Up XYZ, the colors are all dark, and ordered clockwise - Campbell * * note: moved functions into quat_apply_track/vec_apply_track * */ copy_qt_qt(quat, new_quat); copy_v3_v3(cent, co); /* zero the axis which is not used, * the big block of text above now applies to these 3 lines */ quat_apply_track(quat, axis-1, (axis==1 || axis==3) ? 1:0); /* up flag is a dummy, set so no rotation is done */ vec_apply_track(cent, axis-1); cent[axis < 4 ? axis-1 : axis-4]= 0.0f; /* scale if enabled */ if(cu->flag & CU_PATH_RADIUS) mul_v3_fl(cent, radius); /* local rotation */ normalize_qt(quat); mul_qt_v3(quat, cent); /* translation */ add_v3_v3v3(co, cent, loc); if(quatp) copy_qt_qt(quatp, quat); return 1; } return 0; }
static void do_physical_effector(EffectorCache *eff, EffectorData *efd, EffectedPoint *point, float *total_force) { PartDeflect *pd = eff->pd; RNG *rng = pd->rng; float force[3] = {0, 0, 0}; float temp[3]; float fac; float strength = pd->f_strength; float damp = pd->f_damp; float noise_factor = pd->f_noise; if (noise_factor > 0.0f) { strength += wind_func(rng, noise_factor); if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)) damp += wind_func(rng, noise_factor); } copy_v3_v3(force, efd->vec_to_point); switch (pd->forcefield) { case PFIELD_WIND: copy_v3_v3(force, efd->nor); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_FORCE: normalize_v3(force); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_VORTEX: /* old vortex force */ if (pd->shape == PFIELD_SHAPE_POINT) { cross_v3_v3v3(force, efd->nor, efd->vec_to_point); normalize_v3(force); mul_v3_fl(force, strength * efd->distance * efd->falloff); } else { /* new vortex force */ cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2); mul_v3_fl(temp, strength * efd->falloff); cross_v3_v3v3(force, efd->nor2, temp); mul_v3_fl(force, strength * efd->falloff); madd_v3_v3fl(temp, point->vel, -point->vel_to_sec); add_v3_v3(force, temp); } break; case PFIELD_MAGNET: if (eff->pd->shape == PFIELD_SHAPE_POINT) /* magnetic field of a moving charge */ cross_v3_v3v3(temp, efd->nor, efd->vec_to_point); else copy_v3_v3(temp, efd->nor); normalize_v3(temp); mul_v3_fl(temp, strength * efd->falloff); cross_v3_v3v3(force, point->vel, temp); mul_v3_fl(force, point->vel_to_sec); break; case PFIELD_HARMONIC: mul_v3_fl(force, -strength * efd->falloff); copy_v3_v3(temp, point->vel); mul_v3_fl(temp, -damp * 2.0f * sqrtf(fabsf(strength)) * point->vel_to_sec); add_v3_v3(force, temp); break; case PFIELD_CHARGE: mul_v3_fl(force, point->charge * strength * efd->falloff); break; case PFIELD_LENNARDJ: fac = pow((efd->size + point->size) / efd->distance, 6.0); fac = - fac * (1.0f - fac) / efd->distance; /* limit the repulsive term drastically to avoid huge forces */ fac = ((fac>2.0f) ? 2.0f : fac); mul_v3_fl(force, strength * fac); break; case PFIELD_BOID: /* Boid field is handled completely in boids code. */ return; case PFIELD_TURBULENCE: if (pd->flag & PFIELD_GLOBAL_CO) { copy_v3_v3(temp, point->loc); } else { add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2); } force[0] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[0], temp[1], temp[2], 2, 0, 2); force[1] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[1], temp[2], temp[0], 2, 0, 2); force[2] = -1.0f + 2.0f * BLI_gTurbulence(pd->f_size, temp[2], temp[0], temp[1], 2, 0, 2); mul_v3_fl(force, strength * efd->falloff); break; case PFIELD_DRAG: copy_v3_v3(force, point->vel); fac = normalize_v3(force) * point->vel_to_sec; strength = MIN2(strength, 2.0f); damp = MIN2(damp, 2.0f); mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp)); break; case PFIELD_SMOKEFLOW: zero_v3(force); if (pd->f_source) { float density; if ((density = smoke_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) { float influence = strength * efd->falloff; if (pd->flag & PFIELD_SMOKE_DENSITY) influence *= density; mul_v3_fl(force, influence); /* apply flow */ madd_v3_v3fl(total_force, point->vel, -pd->f_flow * influence); } } break; } if (pd->flag & PFIELD_DO_LOCATION) { madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec); if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) { madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff); } } if (point->ave) zero_v3(point->ave); if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) { float xvec[3] = {1.0f, 0.0f, 0.0f}; float dave[3]; mul_qt_v3(point->rot, xvec); cross_v3_v3v3(dave, xvec, force); if (pd->f_flow != 0.0f) { madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff); } add_v3_v3(point->ave, dave); } }
/* tries to realize the wanted velocity taking all constraints into account */ void boid_body(BoidBrainData *bbd, ParticleData *pa) { BoidSettings *boids = bbd->part->boids; BoidParticle *bpa = pa->boid; BoidValues val; EffectedPoint epoint; float acc[3] = {0.0f, 0.0f, 0.0f}, tan_acc[3], nor_acc[3]; float dvec[3], bvec[3]; float new_dir[3], new_speed; float old_dir[3], old_speed; float wanted_dir[3]; float q[4], mat[3][3]; /* rotation */ float ground_co[3] = {0.0f, 0.0f, 0.0f}, ground_nor[3] = {0.0f, 0.0f, 1.0f}; float force[3] = {0.0f, 0.0f, 0.0f}; float pa_mass=bbd->part->mass, dtime=bbd->dfra*bbd->timestep; set_boid_values(&val, boids, pa); /* make sure there's something in new velocity, location & rotation */ copy_particle_key(&pa->state,&pa->prev_state,0); if(bbd->part->flag & PART_SIZEMASS) pa_mass*=pa->size; /* if boids can't fly they fall to the ground */ if((boids->options & BOID_ALLOW_FLIGHT)==0 && ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)==0 && psys_uses_gravity(bbd->sim)) bpa->data.mode = eBoidMode_Falling; if(bpa->data.mode == eBoidMode_Falling) { /* Falling boids are only effected by gravity. */ acc[2] = bbd->sim->scene->physics_settings.gravity[2]; } else { /* figure out acceleration */ float landing_level = 2.0f; float level = landing_level + 1.0f; float new_vel[3]; if(bpa->data.mode == eBoidMode_Liftoff) { bpa->data.mode = eBoidMode_InAir; bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); } else if(bpa->data.mode == eBoidMode_InAir && boids->options & BOID_ALLOW_LAND) { /* auto-leveling & landing if close to ground */ bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); /* level = how many particle sizes above ground */ level = (pa->prev_state.co[2] - ground_co[2])/(2.0f * pa->size) - 0.5f; landing_level = - boids->landing_smoothness * pa->prev_state.vel[2] * pa_mass; if(pa->prev_state.vel[2] < 0.0f) { if(level < 1.0f) { bbd->wanted_co[0] = bbd->wanted_co[1] = bbd->wanted_co[2] = 0.0f; bbd->wanted_speed = 0.0f; bpa->data.mode = eBoidMode_Falling; } else if(level < landing_level) { bbd->wanted_speed *= (level - 1.0f)/landing_level; bbd->wanted_co[2] *= (level - 1.0f)/landing_level; } } } copy_v3_v3(old_dir, pa->prev_state.ave); new_speed = normalize_v3_v3(wanted_dir, bbd->wanted_co); /* first check if we have valid direction we want to go towards */ if(new_speed == 0.0f) { copy_v3_v3(new_dir, old_dir); } else { float old_dir2[2], wanted_dir2[2], nor[3], angle; copy_v2_v2(old_dir2, old_dir); normalize_v2(old_dir2); copy_v2_v2(wanted_dir2, wanted_dir); normalize_v2(wanted_dir2); /* choose random direction to turn if wanted velocity */ /* is directly behind regardless of z-coordinate */ if(dot_v2v2(old_dir2, wanted_dir2) < -0.99f) { wanted_dir[0] = 2.0f*(0.5f - BLI_frand()); wanted_dir[1] = 2.0f*(0.5f - BLI_frand()); wanted_dir[2] = 2.0f*(0.5f - BLI_frand()); normalize_v3(wanted_dir); } /* constrain direction with maximum angular velocity */ angle = saacos(dot_v3v3(old_dir, wanted_dir)); angle = MIN2(angle, val.max_ave); cross_v3_v3v3(nor, old_dir, wanted_dir); axis_angle_to_quat( q,nor, angle); copy_v3_v3(new_dir, old_dir); mul_qt_v3(q, new_dir); normalize_v3(new_dir); /* save direction in case resulting velocity too small */ axis_angle_to_quat( q,nor, angle*dtime); copy_v3_v3(pa->state.ave, old_dir); mul_qt_v3(q, pa->state.ave); normalize_v3(pa->state.ave); } /* constrain speed with maximum acceleration */ old_speed = len_v3(pa->prev_state.vel); if(bbd->wanted_speed < old_speed) new_speed = MAX2(bbd->wanted_speed, old_speed - val.max_acc); else new_speed = MIN2(bbd->wanted_speed, old_speed + val.max_acc); /* combine direction and speed */ copy_v3_v3(new_vel, new_dir); mul_v3_fl(new_vel, new_speed); /* maintain minimum flying velocity if not landing */ if(level >= landing_level) { float len2 = dot_v2v2(new_vel,new_vel); float root; len2 = MAX2(len2, val.min_speed*val.min_speed); root = sasqrt(new_speed*new_speed - len2); new_vel[2] = new_vel[2] < 0.0f ? -root : root; normalize_v2(new_vel); mul_v2_fl(new_vel, sasqrt(len2)); } /* finally constrain speed to max speed */ new_speed = normalize_v3(new_vel); mul_v3_fl(new_vel, MIN2(new_speed, val.max_speed)); /* get acceleration from difference of velocities */ sub_v3_v3v3(acc, new_vel, pa->prev_state.vel); /* break acceleration to components */ project_v3_v3v3(tan_acc, acc, pa->prev_state.ave); sub_v3_v3v3(nor_acc, acc, tan_acc); } /* account for effectors */ pd_point_from_particle(bbd->sim, pa, &pa->state, &epoint); pdDoEffectors(bbd->sim->psys->effectors, bbd->sim->colliders, bbd->part->effector_weights, &epoint, force, NULL); if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) { float length = normalize_v3(force); length = MAX2(0.0f, length - boids->land_stick_force); mul_v3_fl(force, length); } add_v3_v3(acc, force); /* store smoothed acceleration for nice banking etc. */ madd_v3_v3fl(bpa->data.acc, acc, dtime); mul_v3_fl(bpa->data.acc, 1.0f / (1.0f + dtime)); /* integrate new location & velocity */ /* by regarding the acceleration as a force at this stage we*/ /* can get better control allthough it's a bit unphysical */ mul_v3_fl(acc, 1.0f/pa_mass); copy_v3_v3(dvec, acc); mul_v3_fl(dvec, dtime*dtime*0.5f); copy_v3_v3(bvec, pa->prev_state.vel); mul_v3_fl(bvec, dtime); add_v3_v3(dvec, bvec); add_v3_v3(pa->state.co, dvec); madd_v3_v3fl(pa->state.vel, acc, dtime); //if(bpa->data.mode != eBoidMode_InAir) bpa->ground = boid_find_ground(bbd, pa, ground_co, ground_nor); /* change modes, constrain movement & keep track of down vector */ switch(bpa->data.mode) { case eBoidMode_InAir: { float grav[3]; grav[0]= 0.0f; grav[1]= 0.0f; grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; /* don't take forward acceleration into account (better banking) */ if(dot_v3v3(bpa->data.acc, pa->state.vel) > 0.0f) { project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); sub_v3_v3v3(dvec, bpa->data.acc, dvec); } else { copy_v3_v3(dvec, bpa->data.acc); } /* gather apparent gravity */ madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); normalize_v3(bpa->gravity); /* stick boid on goal when close enough */ if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { bpa->data.mode = eBoidMode_Climbing; bpa->ground = bbd->goal_ob; boid_find_ground(bbd, pa, ground_co, ground_nor); boid_climb(boids, pa, ground_co, ground_nor); } else if(pa->state.co[2] <= ground_co[2] + pa->size * boids->height) { /* land boid when below ground */ if(boids->options & BOID_ALLOW_LAND) { pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; bpa->data.mode = eBoidMode_OnLand; } /* fly above ground */ else if(bpa->ground) { pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; } } break; } case eBoidMode_Falling: { float grav[3]; grav[0]= 0.0f; grav[1]= 0.0f; grav[2]= bbd->sim->scene->physics_settings.gravity[2] < 0.0f ? -1.0f : 0.0f; /* gather apparent gravity */ madd_v3_v3fl(bpa->gravity, grav, dtime); normalize_v3(bpa->gravity); if(boids->options & BOID_ALLOW_LAND) { /* stick boid on goal when close enough */ if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { bpa->data.mode = eBoidMode_Climbing; bpa->ground = bbd->goal_ob; boid_find_ground(bbd, pa, ground_co, ground_nor); boid_climb(boids, pa, ground_co, ground_nor); } /* land boid when really near ground */ else if(pa->state.co[2] <= ground_co[2] + 1.01f * pa->size * boids->height){ pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; bpa->data.mode = eBoidMode_OnLand; } /* if we're falling, can fly and want to go upwards lets fly */ else if(boids->options & BOID_ALLOW_FLIGHT && bbd->wanted_co[2] > 0.0f) bpa->data.mode = eBoidMode_InAir; } else bpa->data.mode = eBoidMode_InAir; break; } case eBoidMode_Climbing: { boid_climb(boids, pa, ground_co, ground_nor); //float nor[3]; //copy_v3_v3(nor, ground_nor); ///* gather apparent gravity to r_ve */ //madd_v3_v3fl(pa->r_ve, ground_nor, -1.0); //normalize_v3(pa->r_ve); ///* raise boid it's size from surface */ //mul_v3_fl(nor, pa->size * boids->height); //add_v3_v3v3(pa->state.co, ground_co, nor); ///* remove normal component from velocity */ //project_v3_v3v3(v, pa->state.vel, ground_nor); //sub_v3_v3v3(pa->state.vel, pa->state.vel, v); break; } case eBoidMode_OnLand: { /* stick boid on goal when close enough */ if(bbd->goal_ob && boid_goal_signed_dist(pa->state.co, bbd->goal_co, bbd->goal_nor) <= pa->size * boids->height) { bpa->data.mode = eBoidMode_Climbing; bpa->ground = bbd->goal_ob; boid_find_ground(bbd, pa, ground_co, ground_nor); boid_climb(boids, pa, ground_co, ground_nor); } /* ground is too far away so boid falls */ else if(pa->state.co[2]-ground_co[2] > 1.1f * pa->size * boids->height) bpa->data.mode = eBoidMode_Falling; else { /* constrain to surface */ pa->state.co[2] = ground_co[2] + pa->size * boids->height; pa->state.vel[2] = 0.0f; } if(boids->banking > 0.0f) { float grav[3]; /* Don't take gravity's strength in to account, */ /* otherwise amount of banking is hard to control. */ negate_v3_v3(grav, ground_nor); project_v3_v3v3(dvec, bpa->data.acc, pa->state.vel); sub_v3_v3v3(dvec, bpa->data.acc, dvec); /* gather apparent gravity */ madd_v3_v3v3fl(bpa->gravity, grav, dvec, -boids->banking); normalize_v3(bpa->gravity); } else { /* gather negative surface normal */ madd_v3_v3fl(bpa->gravity, ground_nor, -1.0f); normalize_v3(bpa->gravity); } break; } } /* save direction to state.ave unless the boid is falling */ /* (boids can't effect their direction when falling) */ if(bpa->data.mode!=eBoidMode_Falling && len_v3(pa->state.vel) > 0.1f*pa->size) { copy_v3_v3(pa->state.ave, pa->state.vel); pa->state.ave[2] *= bbd->part->boids->pitch; normalize_v3(pa->state.ave); } /* apply damping */ if(ELEM(bpa->data.mode, eBoidMode_OnLand, eBoidMode_Climbing)) mul_v3_fl(pa->state.vel, 1.0f - 0.2f*bbd->part->dampfac); /* calculate rotation matrix based on forward & down vectors */ if(bpa->data.mode == eBoidMode_InAir) { copy_v3_v3(mat[0], pa->state.ave); project_v3_v3v3(dvec, bpa->gravity, pa->state.ave); sub_v3_v3v3(mat[2], bpa->gravity, dvec); normalize_v3(mat[2]); } else { project_v3_v3v3(dvec, pa->state.ave, bpa->gravity); sub_v3_v3v3(mat[0], pa->state.ave, dvec); normalize_v3(mat[0]); copy_v3_v3(mat[2], bpa->gravity); } negate_v3(mat[2]); cross_v3_v3v3(mat[1], mat[2], mat[0]); /* apply rotation */ mat3_to_quat_is_ok( q,mat); copy_qt_qt(pa->state.rot, q); }
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; }