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