Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/rigidbody.c')
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c320
1 files changed, 319 insertions, 1 deletions
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 359c46f2b0e..d4a7013fb8f 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -74,13 +74,23 @@
/* Free rigidbody world */
void BKE_rigidbody_free_world(RigidBodyWorld *rbw)
{
- GroupObject *go;
/* sanity check */
if (!rbw)
return;
if (rbw->physics_world) {
/* free physics references, we assume that all physics objects in will have been added to the world */
+ GroupObject *go;
+ if (rbw->constraints) {
+ for (go = rbw->constraints->gobject.first; go; go = go->next) {
+ if (go->ob && go->ob->rigidbody_constraint) {
+ RigidBodyCon *rbc = go->ob->rigidbody_constraint;
+
+ if (rbc->physics_constraint)
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ }
+ }
+ }
if (rbw->group) {
for (go = rbw->group->gobject.first; go; go = go->next) {
if (go->ob && go->ob->rigidbody_object) {
@@ -134,6 +144,26 @@ void BKE_rigidbody_free_object(Object *ob)
ob->rigidbody_object = NULL;
}
+/* Free RigidBody constraint and sim instance */
+void BKE_rigidbody_free_constraint(Object *ob)
+{
+ RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
+
+ /* sanity check */
+ if (rbc == NULL)
+ return;
+
+ /* free physics reference */
+ if (rbc->physics_constraint) {
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+
+ /* free data itself */
+ MEM_freeN(rbc);
+ ob->rigidbody_constraint = NULL;
+}
+
/* Copying Methods --------------------- */
/* These just copy the data, clearing out references to physics objects.
@@ -161,6 +191,27 @@ RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
return rboN;
}
+RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob)
+{
+ RigidBodyCon *rbcN = NULL;
+
+ if (ob->rigidbody_constraint) {
+ /* just duplicate the whole struct first (to catch all the settings) */
+ rbcN = MEM_dupallocN(ob->rigidbody_constraint);
+
+ // RB_TODO be more clever about copying constrained objects
+
+ /* tag object as needing to be verified */
+ rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE;
+
+ /* clear out all the fields which need to be revalidated later */
+ rbcN->physics_constraint = NULL;
+ }
+
+ /* return new copy of settings */
+ return rbcN;
+}
+
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
@@ -381,6 +432,7 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
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)
BKE_rigidbody_validate_sim_shape(ob, true);
@@ -428,6 +480,151 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
/* --------------------- */
+/* Create physics sim representation of constraint given rigid body constraint settings
+ * < rebuild: even if an instance already exists, replace it
+ */
+void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, short rebuild)
+{
+ RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
+ float loc[3];
+ float rot[4];
+ float lin_lower;
+ float lin_upper;
+ float ang_lower;
+ float ang_upper;
+
+ /* sanity checks:
+ * - object should have a rigid body constraint
+ * - rigid body constraint should have at least one constrained object
+ */
+ if (rbc == NULL) {
+ return;
+ }
+
+ if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
+ if (rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+ return;
+ }
+
+ if (rbc->physics_constraint) {
+ if (rebuild == false)
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ }
+ if (rbc->physics_constraint == NULL || rebuild) {
+ rbRigidBody *rb1 = rbc->ob1->rigidbody_object->physics_object;
+ rbRigidBody *rb2 = rbc->ob2->rigidbody_object->physics_object;
+
+ /* remove constraint if it already exists before creating a new one */
+ if (rbc->physics_constraint) {
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+
+ mat4_to_loc_quat(loc, rot, ob->obmat);
+
+ if (rb1 && rb2) {
+ switch (rbc->type) {
+ case RBC_TYPE_POINT:
+ rbc->physics_constraint = RB_constraint_new_point(loc, rb1, rb2);
+ break;
+ case RBC_TYPE_FIXED:
+ rbc->physics_constraint = RB_constraint_new_fixed(loc, rot, rb1, rb2);
+ break;
+ case RBC_TYPE_HINGE:
+ rbc->physics_constraint = RB_constraint_new_hinge(loc, rot, rb1, rb2);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) {
+ RB_constraint_set_limits_hinge(rbc->physics_constraint, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
+ }
+ else
+ RB_constraint_set_limits_hinge(rbc->physics_constraint, 0.0f, -1.0f);
+ break;
+ case RBC_TYPE_SLIDER:
+ rbc->physics_constraint = RB_constraint_new_slider(loc, rot, rb1, rb2);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
+ RB_constraint_set_limits_slider(rbc->physics_constraint, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
+ else
+ RB_constraint_set_limits_slider(rbc->physics_constraint, 0.0f, -1.0f);
+ break;
+ case RBC_TYPE_PISTON:
+ rbc->physics_constraint = RB_constraint_new_piston(loc, rot, rb1, rb2);
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) {
+ lin_lower = rbc->limit_lin_x_lower;
+ lin_upper = rbc->limit_lin_x_upper;
+ }
+ else {
+ lin_lower = 0.0f;
+ lin_upper = -1.0f;
+ }
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) {
+ ang_lower = rbc->limit_ang_x_lower;
+ ang_upper = rbc->limit_ang_x_upper;
+ }
+ else {
+ ang_lower = 0.0f;
+ ang_upper = -1.0f;
+ }
+ RB_constraint_set_limits_piston(rbc->physics_constraint, lin_lower, lin_upper, ang_lower, ang_upper);
+ break;
+ case RBC_TYPE_6DOF:
+ rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X)
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper);
+ else
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y)
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper);
+ else
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z)
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper);
+ else
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X)
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper);
+ else
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y)
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper);
+ else
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f);
+
+ if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z)
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper);
+ else
+ RB_constraint_set_limits_6dof(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f);
+ break;
+ }
+ }
+
+ RB_constraint_set_enabled(rbc->physics_constraint, rbc->flag & RBC_FLAG_ENABLED);
+
+ if (rbc->flag & RBC_FLAG_USE_BREAKING)
+ RB_constraint_set_breaking_threshold(rbc->physics_constraint, rbc->breaking_threshold);
+ else
+ RB_constraint_set_breaking_threshold(rbc->physics_constraint, FLT_MAX);
+
+ if (rbc->flag & RBC_FLAG_OVERRIDE_SOLVER_ITERATIONS)
+ RB_constraint_set_solver_iterations(rbc->physics_constraint, rbc->num_solver_iterations);
+ else
+ RB_constraint_set_solver_iterations(rbc->physics_constraint, -1);
+ }
+
+ if (rbw && rbw->physics_world && rbc->physics_constraint) {
+ RB_dworld_add_constraint(rbw->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS);
+ }
+}
+
+/* --------------------- */
+
/* Create physics sim world given RigidBody world settings */
// NOTE: this does NOT update object references that the scene uses, in case those aren't ready yet!
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, short rebuild)
@@ -536,6 +733,55 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
return rbo;
}
+/* Add rigid body constraint to the specified object */
+RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type)
+{
+ RigidBodyCon *rbc;
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ /* sanity checks
+ * - rigidbody world must exist
+ * - object must exist
+ * - cannot add constraint if it already exists
+ */
+ if (ob == NULL || (ob->rigidbody_constraint != NULL))
+ return NULL;
+
+ /* create new settings data, and link it up */
+ rbc = MEM_callocN(sizeof(RigidBodyCon), "RigidBodyCon");
+
+ /* set default settings */
+ rbc->type = type;
+
+ rbc->ob1 = NULL;
+ rbc->ob2 = NULL;
+
+ rbc->flag |= RBC_FLAG_ENABLED;
+ rbc->flag |= RBC_FLAG_DISABLE_COLLISIONS;
+
+ rbc->breaking_threshold = 10.0f; /* no good default here, just use 10 for now */
+ rbc->num_solver_iterations = 10; /* 10 is Bullet default */
+
+ rbc->limit_lin_x_lower = -1.0f;
+ rbc->limit_lin_x_upper = 1.0f;
+ rbc->limit_lin_y_lower = -1.0f;
+ rbc->limit_lin_y_upper = 1.0f;
+ rbc->limit_lin_z_lower = -1.0f;
+ rbc->limit_lin_z_upper = 1.0f;
+ rbc->limit_ang_x_lower = -M_PI_4;
+ rbc->limit_ang_x_upper = M_PI_4;
+ rbc->limit_ang_y_lower = -M_PI_4;
+ rbc->limit_ang_y_upper = M_PI_4;
+ rbc->limit_ang_z_lower = -M_PI_4;
+ rbc->limit_ang_z_upper = M_PI_4;
+
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
+
+ /* return this object */
+ return rbc;
+}
+
/* ************************************** */
/* Utilities API */
@@ -555,6 +801,7 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
RigidBodyOb *rbo = ob->rigidbody_object;
+ RigidBodyCon *rbc;
GroupObject *go;
int i;
@@ -572,9 +819,46 @@ void BKE_rigidbody_remove_object(Scene *scene, Object *ob)
}
}
}
+
+ /* remove object from rigid body constraints */
+ if (rbw->constraints) {
+ for (go = rbw->constraints->gobject.first; go; go = go->next) {
+ Object *obt = go->ob;
+ if (obt) {
+ rbc = obt->rigidbody_constraint;
+ if (rbc->ob1 == ob) {
+ rbc->ob1 = NULL;
+ rbc->flag |= RBC_FLAG_NEEDS_VALIDATE;
+ }
+ if (rbc->ob2 == ob) {
+ rbc->ob2 = NULL;
+ rbc->flag |= RBC_FLAG_NEEDS_VALIDATE;
+ }
+ }
+ }
+ }
}
+
/* remove object's settings */
BKE_rigidbody_free_object(ob);
+
+ /* flag cache as outdated */
+ BKE_rigidbody_cache_reset(rbw);
+}
+
+void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+
+ if (rbw) {
+ /* remove from rigidbody world, free object won't do this */
+ if (rbw && rbw->physics_world && rbc->physics_constraint)
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ }
+ /* remove object's settings */
+ BKE_rigidbody_free_constraint(ob);
+
/* flag cache as outdated */
BKE_rigidbody_cache_reset(rbw);
}
@@ -746,6 +1030,40 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
rigidbody_update_sim_ob(scene, rbw, ob, rbo);
}
}
+ /* update constraints */
+ if (rbw->constraints == NULL) /* no constraints, move on */
+ return;
+ for (go = rbw->constraints->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+
+ if (ob) {
+ /* validate that we've got valid object set up here... */
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ /* update transformation matrix of the object so we don't get a frame of lag for simple animations */
+ BKE_object_where_is_calc(scene, ob);
+
+ if (rbc == NULL) {
+ /* Since this object is included in the group but doesn't have
+ * constraint settings (perhaps it was added manually), add!
+ */
+ ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
+ BKE_rigidbody_validate_sim_constraint(rbw, ob, true);
+
+ rbc = ob->rigidbody_constraint;
+ }
+ else {
+ /* perform simulation data updates as tagged */
+ if (rebuild) {
+ /* World has been rebuilt so rebuild constraint */
+ BKE_rigidbody_validate_sim_constraint(rbw, ob, true);
+ }
+ else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
+ BKE_rigidbody_validate_sim_constraint(rbw, ob, false);
+ }
+ rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
+ }
+ }
+ }
}
/* Sync rigid body and object transformations */