static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time) { /* Collect forces and derivatives: F, dFdX, dFdV */ Cloth *cloth = clmd->clothObject; Implicit_Data *data = cloth->implicit; unsigned int i = 0; float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */ float gravity[3] = {0.0f, 0.0f, 0.0f}; const MVertTri *tri = cloth->tri; unsigned int mvert_num = cloth->mvert_num; ClothVertex *vert; #ifdef CLOTH_FORCE_GRAVITY /* global acceleration (gravitation) */ if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { /* scale gravity force */ mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity); } vert = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, vert++) { BPH_mass_spring_force_gravity(data, i, vert->mass, gravity); } #endif /* cloth_calc_volume_force(clmd); */ #ifdef CLOTH_FORCE_DRAG BPH_mass_spring_force_drag(data, drag); #endif /* handle external forces like wind */ if (effectors) { /* cache per-vertex forces to avoid redundant calculation */ float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float[3]) * mvert_num, "effector forces"); for (i = 0; i < cloth->mvert_num; i++) { float x[3], v[3]; EffectedPoint epoint; BPH_mass_spring_get_motion_state(data, i, x, v); pd_point_from_loc(clmd->scene, x, v, i, &epoint); pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL); } for (i = 0; i < cloth->tri_num; i++) { const MVertTri *vt = &tri[i]; BPH_mass_spring_force_face_wind(data, vt->tri[0], vt->tri[1], vt->tri[2], winvec); } /* Hair has only edges */ if (cloth->tri_num == 0) { #if 0 ClothHairData *hairdata = clmd->hairdata; ClothHairData *hair_ij, *hair_kl; for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) { if (hairdata) { hair_ij = &hairdata[spring->ij]; hair_kl = &hairdata[spring->kl]; BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec); } else BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec); } } #else ClothHairData *hairdata = clmd->hairdata; vert = cloth->verts; for (i = 0; i < cloth->mvert_num; i++, vert++) { if (hairdata) { ClothHairData *hair = &hairdata[i]; BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec); } else BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec); } } #endif MEM_freeN(winvec); } // calculate spring forces for (LinkNode *link = cloth->springs; link; link = link->next) { ClothSpring *spring = (ClothSpring *)link->link; // only handle active springs if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE)) cloth_calc_spring_force(clmd, spring, time); } }
/* 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_rng_get_float(bbd->rng)); wanted_dir[1] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng)); wanted_dir[2] = 2.0f*(0.5f - BLI_rng_get_float(bbd->rng)); normalize_v3(wanted_dir); } /* constrain direction with maximum angular velocity */ angle = saacos(dot_v3v3(old_dir, wanted_dir)); angle = min_ff(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); }
static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *ob, RigidBodyOb *rbo) { float loc[3]; float rot[4]; float scale[3]; /* only update if rigid body exists */ if (rbo->physics_object == NULL) return; if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { DerivedMesh *dm = ob->derivedDeform; if (dm) { MVert *mvert = dm->getVertArray(dm); int totvert = dm->getNumVerts(dm); BoundBox *bb = BKE_object_boundbox_get(ob); RB_shape_trimesh_update(rbo->physics_shape, (float *)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]); } } mat4_decompose(loc, rot, scale, ob->obmat); /* update scale for all objects */ RB_body_set_scale(rbo->physics_object, scale); /* compensate for embedded convex hull collision margin */ if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && rbo->shape == RB_SHAPE_CONVEXH) RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo) * MIN3(scale[0], scale[1], scale[2])); /* make transformed objects temporarily kinmatic so that they can be moved by the user during simulation */ if (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ) { RB_body_set_kinematic_state(rbo->physics_object, TRUE); RB_body_set_mass(rbo->physics_object, 0.0f); } /* update rigid body location and rotation for kinematic bodies */ if (rbo->flag & RBO_FLAG_KINEMATIC || (ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { RB_body_activate(rbo->physics_object); RB_body_set_loc_rot(rbo->physics_object, loc, rot); } /* update influence of effectors - but don't do it on an effector */ /* only dynamic bodies need effector update */ else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) { EffectorWeights *effector_weights = rbw->effector_weights; EffectedPoint epoint; ListBase *effectors; /* get effectors present in the group specified by effector_weights */ effectors = pdInitEffectors(scene, ob, NULL, effector_weights); if (effectors) { float eff_force[3] = {0.0f, 0.0f, 0.0f}; float eff_loc[3], eff_vel[3]; /* create dummy 'point' which represents last known position of object as result of sim */ // XXX: this can create some inaccuracies with sim position, but is probably better than using unsimulated vals? RB_body_get_position(rbo->physics_object, eff_loc); RB_body_get_linear_velocity(rbo->physics_object, eff_vel); pd_point_from_loc(scene, eff_loc, eff_vel, 0, &epoint); /* calculate net force of effectors, and apply to sim object * - we use 'central force' since apply force requires a "relative position" which we don't have... */ pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL); if (G.f & G_DEBUG) printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2); /* activate object in case it is deactivated */ if (!is_zero_v3(eff_force)) RB_body_activate(rbo->physics_object); RB_body_apply_central_force(rbo->physics_object, eff_force); } else if (G.f & G_DEBUG) printf("\tno forces to apply to '%s'\n", ob->id.name + 2); /* cleanup */ pdEndEffectors(&effectors); } /* NOTE: passive objects don't need to be updated since they don't move */ /* NOTE: no other settings need to be explicitly updated here, * since RNA setters take care of the rest :) */ }
static void smoke_calc_domain(Scene *scene, Object *ob, SmokeModifierData *smd) { SmokeDomainSettings *sds = smd->domain; GroupObject *go = NULL; Base *base = NULL; // do flows and fluids if(1) { Object *otherobj = NULL; ModifierData *md = NULL; if(sds->fluid_group) // we use groups since we have 2 domains go = sds->fluid_group->gobject.first; else base = scene->base.first; while(base || go) { otherobj = NULL; if(sds->fluid_group) { if(go->ob) otherobj = go->ob; } else otherobj = base->object; if(!otherobj) { if(sds->fluid_group) go = go->next; else base= base->next; continue; } md = modifiers_findByType(otherobj, eModifierType_Smoke); // check for active smoke modifier if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { SmokeModifierData *smd2 = (SmokeModifierData *)md; // check for initialized smoke object if((smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) { // we got nice flow object SmokeFlowSettings *sfs = smd2->flow; if(sfs->psys && sfs->psys->part && sfs->psys->part->type==PART_EMITTER) // is particle system selected { ParticleSystem *psys = sfs->psys; ParticleSettings *part=psys->part; ParticleData *pa = NULL; int p = 0; float *density = smoke_get_density(sds->fluid); float *bigdensity = smoke_turbulence_get_density(sds->wt); float *heat = smoke_get_heat(sds->fluid); float *velocity_x = smoke_get_velocity_x(sds->fluid); float *velocity_y = smoke_get_velocity_y(sds->fluid); float *velocity_z = smoke_get_velocity_z(sds->fluid); unsigned char *obstacle = smoke_get_obstacle(sds->fluid); int bigres[3]; // mostly copied from particle code for(p=0, pa=psys->particles; p<psys->totpart; p++, pa++) { int cell[3]; size_t i = 0; size_t index = 0; int badcell = 0; if(pa->alive == PARS_UNBORN && (part->flag & PART_UNBORN)==0) continue; else if(pa->alive == PARS_DEAD && (part->flag & PART_DIED)==0) continue; else if(pa->flag & (PARS_UNEXIST+PARS_NO_DISP)) continue; // VECCOPY(pos, pa->state.co); // Mat4MulVecfl (ob->imat, pos); // 1. get corresponding cell get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, pa->state.co, cell, 0); // check if cell is valid (in the domain boundary) for(i = 0; i < 3; i++) { if((cell[i] > sds->res[i] - 1) || (cell[i] < 0)) { badcell = 1; break; } } if(badcell) continue; // 2. set cell values (heat, density and velocity) index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); if(!(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) && !(obstacle[index] & 2)) // this is inflow { // heat[index] += sfs->temp * 0.1; // density[index] += sfs->density * 0.1; heat[index] = sfs->temp; density[index] = sfs->density; /* velocity_x[index] = pa->state.vel[0]; velocity_y[index] = pa->state.vel[1]; velocity_z[index] = pa->state.vel[2]; */ // obstacle[index] |= 2; // we need different handling for the high-res feature if(bigdensity) { // init all surrounding cells according to amplification, too int i, j, k; smoke_turbulence_get_res(smd->domain->wt, bigres); for(i = 0; i < smd->domain->amplify + 1; i++) for(j = 0; j < smd->domain->amplify + 1; j++) for(k = 0; k < smd->domain->amplify + 1; k++) { index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); bigdensity[index] = sfs->density; } } } else if(sfs->type & MOD_SMOKE_FLOW_TYPE_OUTFLOW) // outflow { heat[index] = 0.f; density[index] = 0.f; velocity_x[index] = 0.f; velocity_y[index] = 0.f; velocity_z[index] = 0.f; // we need different handling for the high-res feature if(bigdensity) { // init all surrounding cells according to amplification, too int i, j, k; smoke_turbulence_get_res(smd->domain->wt, bigres); for(i = 0; i < smd->domain->amplify + 1; i++) for(j = 0; j < smd->domain->amplify + 1; j++) for(k = 0; k < smd->domain->amplify + 1; k++) { index = smoke_get_index((smd->domain->amplify + 1)* cell[0] + i, bigres[0], (smd->domain->amplify + 1)* cell[1] + j, bigres[1], (smd->domain->amplify + 1)* cell[2] + k); bigdensity[index] = 0.f; } } } // particles loop } } else { /* for() { // no psys BVHTreeNearest nearest; nearest.index = -1; nearest.dist = FLT_MAX; BLI_bvhtree_find_nearest(sfs->bvh->tree, pco, &nearest, sfs->bvh->nearest_callback, sfs->bvh); }*/ } } } if(sds->fluid_group) go = go->next; else base= base->next; } } // do effectors { ListBase *effectors = pdInitEffectors(scene, ob, NULL, sds->effector_weights); if(effectors) { float *density = smoke_get_density(sds->fluid); float *force_x = smoke_get_force_x(sds->fluid); float *force_y = smoke_get_force_y(sds->fluid); float *force_z = smoke_get_force_z(sds->fluid); float *velocity_x = smoke_get_velocity_x(sds->fluid); float *velocity_y = smoke_get_velocity_y(sds->fluid); float *velocity_z = smoke_get_velocity_z(sds->fluid); int x, y, z; // precalculate wind forces for(x = 0; x < sds->res[0]; x++) for(y = 0; y < sds->res[1]; y++) for(z = 0; z < sds->res[2]; z++) { EffectedPoint epoint; float voxelCenter[3] = {0,0,0} , vel[3] = {0,0,0} , retvel[3] = {0,0,0}; unsigned int index = smoke_get_index(x, sds->res[0], y, sds->res[1], z); if(density[index] < FLT_EPSILON) continue; vel[0] = velocity_x[index]; vel[1] = velocity_y[index]; vel[2] = velocity_z[index]; voxelCenter[0] = sds->p0[0] + sds->dx * x + sds->dx * 0.5; voxelCenter[1] = sds->p0[1] + sds->dx * y + sds->dx * 0.5; voxelCenter[2] = sds->p0[2] + sds->dx * z + sds->dx * 0.5; pd_point_from_loc(scene, voxelCenter, vel, index, &epoint); pdDoEffectors(effectors, NULL, sds->effector_weights, &epoint, retvel, NULL); // TODO dg - do in force! force_x[index] = MIN2(MAX2(-1.0, retvel[0] * 0.2), 1.0); force_y[index] = MIN2(MAX2(-1.0, retvel[1] * 0.2), 1.0); force_z[index] = MIN2(MAX2(-1.0, retvel[2] * 0.2), 1.0); } } pdEndEffectors(&effectors); } // do collisions if(1) { Object *otherobj = NULL; ModifierData *md = NULL; if(sds->coll_group) // we use groups since we have 2 domains go = sds->coll_group->gobject.first; else base = scene->base.first; while(base || go) { otherobj = NULL; if(sds->coll_group) { if(go->ob) otherobj = go->ob; } else otherobj = base->object; if(!otherobj) { if(sds->coll_group) go = go->next; else base= base->next; continue; } md = modifiers_findByType(otherobj, eModifierType_Smoke); // check for active smoke modifier if(md && md->mode & (eModifierMode_Realtime | eModifierMode_Render)) { SmokeModifierData *smd2 = (SmokeModifierData *)md; if((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll && smd2->coll->points) { // we got nice collision object SmokeCollSettings *scs = smd2->coll; size_t i, j; unsigned char *obstacles = smoke_get_obstacle(smd->domain->fluid); for(i = 0; i < scs->numpoints; i++) { int badcell = 0; size_t index = 0; int cell[3]; // 1. get corresponding cell get_cell(smd->domain->p0, smd->domain->res, smd->domain->dx, &scs->points[3 * i], cell, 0); // check if cell is valid (in the domain boundary) for(j = 0; j < 3; j++) if((cell[j] > sds->res[j] - 1) || (cell[j] < 0)) { badcell = 1; break; } if(badcell) continue; // 2. set cell values (heat, density and velocity) index = smoke_get_index(cell[0], sds->res[0], cell[1], sds->res[1], cell[2]); // printf("cell[0]: %d, cell[1]: %d, cell[2]: %d\n", cell[0], cell[1], cell[2]); // printf("res[0]: %d, res[1]: %d, res[2]: %d, index: %d\n\n", sds->res[0], sds->res[1], sds->res[2], index); obstacles[index] = 1; // for moving gobstacles /* const LbmFloat maxVelVal = 0.1666; const LbmFloat maxusqr = maxVelVal*maxVelVal*3. *1.5; LbmVec objvel = vec2L((mMOIVertices[n]-mMOIVerticesOld[n]) /dvec); { const LbmFloat usqr = (objvel[0]*objvel[0]+objvel[1]*objvel[1]+objvel[2]*objvel[2])*1.5; USQRMAXCHECK(usqr, objvel[0],objvel[1],objvel[2], mMaxVlen, mMxvx,mMxvy,mMxvz); if(usqr>maxusqr) { // cutoff at maxVelVal for(int jj=0; jj<3; jj++) { if(objvel[jj]>0.) objvel[jj] = maxVelVal; if(objvel[jj]<0.) objvel[jj] = -maxVelVal; } } } const LbmFloat dp=dot(objvel, vec2L((*pNormals)[n]) ); const LbmVec oldov=objvel; // debug objvel = vec2L((*pNormals)[n]) *dp; */ } } } if(sds->coll_group) go = go->next; else base= base->next; } } }