/* Used when canceling transforms - return rigidbody and object to initial states */ void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) { RigidBodyOb *rbo = ob->rigidbody_object; /* return rigid body and object to their initial states */ copy_v3_v3(rbo->pos, ob->loc); copy_v3_v3(ob->loc, loc); if (ob->rotmode > 0) { eulO_to_quat(rbo->orn, ob->rot, ob->rotmode); copy_v3_v3(ob->rot, rot); } else if (ob->rotmode == ROT_MODE_AXISANGLE) { axis_angle_to_quat(rbo->orn, ob->rotAxis, ob->rotAngle); copy_v3_v3(ob->rotAxis, rotAxis); ob->rotAngle = rotAngle; } else { copy_qt_qt(rbo->orn, ob->quat); copy_qt_qt(ob->quat, quat); } if (rbo->physics_object) { /* allow passive objects to return to original transform */ if (rbo->type == RBO_TYPE_PASSIVE) RB_body_set_kinematic_state(rbo->physics_object, TRUE); RB_body_set_loc_rot(rbo->physics_object, rbo->pos, rbo->orn); } // RB_TODO update rigid body physics object's loc/rot for dynamic objects here as well (needs to be done outside bullet's update loop) }
/* Create physics sim representation of object given RigidBody settings * < rebuild: even if an instance already exists, replace it */ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool rebuild) { RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL; float loc[3]; float rot[4]; /* sanity checks: * - object doesn't have RigidBody info already: then why is it here? */ if (rbo == NULL) return; /* make sure collision shape exists */ /* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */ if (rbo->physics_shape == NULL || rebuild) rigidbody_validate_sim_shape(ob, true); if (rbo->physics_object && rebuild == false) { RB_dworld_remove_body(rbw->physics_world, rbo->physics_object); } if (!rbo->physics_object || rebuild) { /* remove rigid body if it already exists before creating a new one */ if (rbo->physics_object) { RB_body_delete(rbo->physics_object); } mat4_to_loc_quat(loc, rot, ob->obmat); rbo->physics_object = RB_body_new(rbo->physics_shape, loc, rot); RB_body_set_friction(rbo->physics_object, rbo->friction); RB_body_set_restitution(rbo->physics_object, rbo->restitution); RB_body_set_damping(rbo->physics_object, rbo->lin_damping, rbo->ang_damping); RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh); RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION); if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED) RB_body_deactivate(rbo->physics_object); RB_body_set_linear_factor(rbo->physics_object, (ob->protectflag & OB_LOCK_LOCX) == 0, (ob->protectflag & OB_LOCK_LOCY) == 0, (ob->protectflag & OB_LOCK_LOCZ) == 0); RB_body_set_angular_factor(rbo->physics_object, (ob->protectflag & OB_LOCK_ROTX) == 0, (ob->protectflag & OB_LOCK_ROTY) == 0, (ob->protectflag & OB_LOCK_ROTZ) == 0); RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); } if (rbw && rbw->physics_world) RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups); }
static void rna_RigidBodyOb_kinematic_state_set(PointerRNA *ptr, int value) { RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; RB_FLAG_SET(rbo->flag, value, RBO_FLAG_KINEMATIC); #ifdef WITH_BULLET /* update kinematic state if necessary */ if (rbo->physics_object) { RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); RB_body_set_kinematic_state(rbo->physics_object, value); rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; } #endif }
static void rna_RigidBodyOb_disabled_set(PointerRNA *ptr, int value) { RigidBodyOb *rbo = (RigidBodyOb *)ptr->data; RB_FLAG_SET(rbo->flag, !value, RBO_FLAG_DISABLED); #ifdef WITH_BULLET /* update kinematic state if necessary - only needed for active bodies */ if ((rbo->physics_object) && (rbo->type == RBO_TYPE_ACTIVE)) { RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); RB_body_set_kinematic_state(rbo->physics_object, !value); rbo->flag |= RBO_FLAG_NEEDS_VALIDATE; } #endif }
static void rigidbody_update_simulation_post_step(RigidBodyWorld *rbw) { GroupObject *go; for (go = rbw->group->gobject.first; go; go = go->next) { Object *ob = go->ob; if (ob) { RigidBodyOb *rbo = ob->rigidbody_object; /* reset kinematic state for transformed objects */ if (rbo && (ob->flag & SELECT) && (G.moving & G_TRANSFORM_OBJ)) { RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo)); /* deactivate passive objects so they don't interfere with deactivation of active objects */ if (rbo->type == RBO_TYPE_PASSIVE) RB_body_deactivate(rbo->physics_object); } } } }
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 :) */ }