diff options
Diffstat (limited to 'source/blender/blenkernel/intern/rigidbody.c')
-rw-r--r-- | source/blender/blenkernel/intern/rigidbody.c | 3068 |
1 files changed, 1587 insertions, 1481 deletions
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 745c17c0919..78639b4ddb9 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -80,126 +80,136 @@ static CLG_LogRef LOG = {"bke.rigidbody"}; static void rigidbody_update_ob_array(RigidBodyWorld *rbw); #else -static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {} -static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {} -static void RB_dworld_delete(void *UNUSED(world)) {} -static void RB_body_delete(void *UNUSED(body)) {} -static void RB_shape_delete(void *UNUSED(shape)) {} -static void RB_constraint_delete(void *UNUSED(con)) {} +static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) +{ +} +static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) +{ +} +static void RB_dworld_delete(void *UNUSED(world)) +{ +} +static void RB_body_delete(void *UNUSED(body)) +{ +} +static void RB_shape_delete(void *UNUSED(shape)) +{ +} +static void RB_constraint_delete(void *UNUSED(con)) +{ +} #endif /* Free rigidbody world */ void BKE_rigidbody_free_world(Scene *scene) { - bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; - RigidBodyWorld *rbw = scene->rigidbody_world; - scene->rigidbody_world = NULL; - - /* sanity check */ - if (!rbw) - return; - - if (is_orig && rbw->shared->physics_world) { - /* free physics references, we assume that all physics objects in will have been added to the world */ - if (rbw->constraints) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) - { - if (object->rigidbody_constraint) { - RigidBodyCon *rbc = object->rigidbody_constraint; - if (rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); - } - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - - if (rbw->group) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - BKE_rigidbody_free_object(object, rbw); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - /* free dynamics world */ - RB_dworld_delete(rbw->shared->physics_world); - } - if (rbw->objects) - free(rbw->objects); - - if (is_orig) { - /* free cache */ - BKE_ptcache_free_list(&(rbw->shared->ptcaches)); - rbw->shared->pointcache = NULL; - - MEM_freeN(rbw->shared); - } - - /* free effector weights */ - if (rbw->effector_weights) - MEM_freeN(rbw->effector_weights); - - /* free rigidbody world itself */ - MEM_freeN(rbw); + bool is_orig = (scene->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; + RigidBodyWorld *rbw = scene->rigidbody_world; + scene->rigidbody_world = NULL; + + /* sanity check */ + if (!rbw) + return; + + if (is_orig && rbw->shared->physics_world) { + /* free physics references, we assume that all physics objects in will have been added to the world */ + if (rbw->constraints) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { + if (object->rigidbody_constraint) { + RigidBodyCon *rbc = object->rigidbody_constraint; + if (rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + + if (rbw->group) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + BKE_rigidbody_free_object(object, rbw); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + /* free dynamics world */ + RB_dworld_delete(rbw->shared->physics_world); + } + if (rbw->objects) + free(rbw->objects); + + if (is_orig) { + /* free cache */ + BKE_ptcache_free_list(&(rbw->shared->ptcaches)); + rbw->shared->pointcache = NULL; + + MEM_freeN(rbw->shared); + } + + /* free effector weights */ + if (rbw->effector_weights) + MEM_freeN(rbw->effector_weights); + + /* free rigidbody world itself */ + MEM_freeN(rbw); } /* Free RigidBody settings and sim instances */ void BKE_rigidbody_free_object(Object *ob, RigidBodyWorld *rbw) { - bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; - RigidBodyOb *rbo = ob->rigidbody_object; - - /* sanity check */ - if (rbo == NULL) - return; - - /* free physics references */ - if (is_orig) { - if (rbo->shared->physics_object) { - BLI_assert(rbw); - if (rbw) { - /* We can only remove the body from the world if the world is known. - * The world is generally only unknown if it's an evaluated copy of - * an object that's being freed, in which case this code isn't run anyway. */ - RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); - } - - RB_body_delete(rbo->shared->physics_object); - rbo->shared->physics_object = NULL; - } - - if (rbo->shared->physics_shape) { - RB_shape_delete(rbo->shared->physics_shape); - rbo->shared->physics_shape = NULL; - } - - MEM_freeN(rbo->shared); - } - - /* free data itself */ - MEM_freeN(rbo); - ob->rigidbody_object = NULL; + bool is_orig = (ob->id.tag & LIB_TAG_COPIED_ON_WRITE) == 0; + RigidBodyOb *rbo = ob->rigidbody_object; + + /* sanity check */ + if (rbo == NULL) + return; + + /* free physics references */ + if (is_orig) { + if (rbo->shared->physics_object) { + BLI_assert(rbw); + if (rbw) { + /* We can only remove the body from the world if the world is known. + * The world is generally only unknown if it's an evaluated copy of + * an object that's being freed, in which case this code isn't run anyway. */ + RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); + } + + RB_body_delete(rbo->shared->physics_object); + rbo->shared->physics_object = NULL; + } + + if (rbo->shared->physics_shape) { + RB_shape_delete(rbo->shared->physics_shape); + rbo->shared->physics_shape = NULL; + } + + MEM_freeN(rbo->shared); + } + + /* free data itself */ + MEM_freeN(rbo); + ob->rigidbody_object = NULL; } /* Free RigidBody constraint and sim instance */ void BKE_rigidbody_free_constraint(Object *ob) { - RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL; + RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL; - /* sanity check */ - if (rbc == NULL) - return; + /* sanity check */ + if (rbc == NULL) + return; - /* free physics reference */ - if (rbc->physics_constraint) { - RB_constraint_delete(rbc->physics_constraint); - rbc->physics_constraint = NULL; - } + /* 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; + /* free data itself */ + MEM_freeN(rbc); + ob->rigidbody_constraint = NULL; } #ifdef WITH_BULLET @@ -213,42 +223,42 @@ void BKE_rigidbody_free_constraint(Object *ob) RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { - RigidBodyOb *rboN = NULL; + RigidBodyOb *rboN = NULL; - if (ob->rigidbody_object) { - /* just duplicate the whole struct first (to catch all the settings) */ - rboN = MEM_dupallocN(ob->rigidbody_object); + if (ob->rigidbody_object) { + /* just duplicate the whole struct first (to catch all the settings) */ + rboN = MEM_dupallocN(ob->rigidbody_object); - if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { - /* This is a regular copy, and not a CoW copy for depsgraph evaluation */ - rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared"); - } + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + /* This is a regular copy, and not a CoW copy for depsgraph evaluation */ + rboN->shared = MEM_callocN(sizeof(*rboN->shared), "RigidBodyOb_Shared"); + } - /* tag object as needing to be verified */ - rboN->flag |= RBO_FLAG_NEEDS_VALIDATE; - } + /* tag object as needing to be verified */ + rboN->flag |= RBO_FLAG_NEEDS_VALIDATE; + } - /* return new copy of settings */ - return rboN; + /* return new copy of settings */ + return rboN; } RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(flag)) { - RigidBodyCon *rbcN = NULL; + RigidBodyCon *rbcN = NULL; - if (ob->rigidbody_constraint) { - /* just duplicate the whole struct first (to catch all the settings) */ - rbcN = MEM_dupallocN(ob->rigidbody_constraint); + if (ob->rigidbody_constraint) { + /* just duplicate the whole struct first (to catch all the settings) */ + rbcN = MEM_dupallocN(ob->rigidbody_constraint); - /* tag object as needing to be verified */ - rbcN->flag |= RBC_FLAG_NEEDS_VALIDATE; + /* 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; - } + /* clear out all the fields which need to be revalidated later */ + rbcN->physics_constraint = NULL; + } - /* return new copy of settings */ - return rbcN; + /* return new copy of settings */ + return rbcN; } /* ************************************** */ @@ -257,49 +267,51 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int UNUSED(f /* get the appropriate evaluated mesh based on rigid body mesh source */ static Mesh *rigidbody_get_mesh(Object *ob) { - switch (ob->rigidbody_object->mesh_source) { - case RBO_MESH_DEFORM: - return ob->runtime.mesh_deform_eval; - case RBO_MESH_FINAL: - return ob->runtime.mesh_eval; - case RBO_MESH_BASE: - /* This mesh may be used for computing looptris, which should be done - * on the original; otherwise every time the CoW is recreated it will - * have to be recomputed. */ - BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE); - return ob->runtime.mesh_orig; - } - - /* Just return something sensible so that at least Blender won't crash. */ - BLI_assert(!"Unknown mesh source"); - return ob->runtime.mesh_eval; + switch (ob->rigidbody_object->mesh_source) { + case RBO_MESH_DEFORM: + return ob->runtime.mesh_deform_eval; + case RBO_MESH_FINAL: + return ob->runtime.mesh_eval; + case RBO_MESH_BASE: + /* This mesh may be used for computing looptris, which should be done + * on the original; otherwise every time the CoW is recreated it will + * have to be recomputed. */ + BLI_assert(ob->rigidbody_object->mesh_source == RBO_MESH_BASE); + return ob->runtime.mesh_orig; + } + + /* Just return something sensible so that at least Blender won't crash. */ + BLI_assert(!"Unknown mesh source"); + return ob->runtime.mesh_eval; } /* create collision shape of mesh - convex hull */ -static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed) +static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, + float margin, + bool *can_embed) { - rbCollisionShape *shape = NULL; - Mesh *mesh = NULL; - MVert *mvert = NULL; - int totvert = 0; - - if (ob->type == OB_MESH && ob->data) { - mesh = rigidbody_get_mesh(ob); - mvert = (mesh) ? mesh->mvert : NULL; - totvert = (mesh) ? mesh->totvert : 0; - } - else { - CLOG_ERROR(&LOG, "cannot make Convex Hull collision shape for non-Mesh object"); - } - - if (totvert) { - shape = RB_shape_new_convex_hull((float *)mvert, sizeof(MVert), totvert, margin, can_embed); - } - else { - CLOG_ERROR(&LOG, "no vertices to define Convex Hull collision shape with"); - } - - return shape; + rbCollisionShape *shape = NULL; + Mesh *mesh = NULL; + MVert *mvert = NULL; + int totvert = 0; + + if (ob->type == OB_MESH && ob->data) { + mesh = rigidbody_get_mesh(ob); + mvert = (mesh) ? mesh->mvert : NULL; + totvert = (mesh) ? mesh->totvert : 0; + } + else { + CLOG_ERROR(&LOG, "cannot make Convex Hull collision shape for non-Mesh object"); + } + + if (totvert) { + shape = RB_shape_new_convex_hull((float *)mvert, sizeof(MVert), totvert, margin, can_embed); + } + else { + CLOG_ERROR(&LOG, "no vertices to define Convex Hull collision shape with"); + } + + return shape; } /* create collision shape of mesh - triangulated mesh @@ -307,82 +319,83 @@ static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, fl */ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) { - rbCollisionShape *shape = NULL; - - if (ob->type == OB_MESH) { - Mesh *mesh = NULL; - MVert *mvert; - const MLoopTri *looptri; - int totvert; - int tottri; - const MLoop *mloop; - - mesh = rigidbody_get_mesh(ob); - - /* ensure mesh validity, then grab data */ - if (mesh == NULL) - return NULL; - - mvert = mesh->mvert; - totvert = mesh->totvert; - looptri = BKE_mesh_runtime_looptri_ensure(mesh); - tottri = mesh->runtime.looptris.len; - mloop = mesh->mloop; - - /* sanity checking - potential case when no data will be present */ - if ((totvert == 0) || (tottri == 0)) { - CLOG_WARN(&LOG, "no geometry data converted for Mesh Collision Shape (ob = %s)", ob->id.name + 2); - } - else { - rbMeshData *mdata; - int i; - - /* init mesh data for collision shape */ - mdata = RB_trimesh_data_new(tottri, totvert); - - RB_trimesh_add_vertices(mdata, (float *)mvert, totvert, sizeof(MVert)); - - /* loop over all faces, adding them as triangles to the collision shape - * (so for some faces, more than triangle will get added) - */ - if (mvert && looptri) { - for (i = 0; i < tottri; i++) { - /* add first triangle - verts 1,2,3 */ - const MLoopTri *lt = &looptri[i]; - int vtri[3]; - - vtri[0] = mloop[lt->tri[0]].v; - vtri[1] = mloop[lt->tri[1]].v; - vtri[2] = mloop[lt->tri[2]].v; - - RB_trimesh_add_triangle_indices(mdata, i, UNPACK3(vtri)); - } - } - - RB_trimesh_finish(mdata); - - /* construct collision shape - * - * These have been chosen to get better speed/accuracy tradeoffs with regards - * to limitations of each: - * - BVH-Triangle Mesh: for passive objects only. Despite having greater - * speed/accuracy, they cannot be used for moving objects. - * - GImpact Mesh: for active objects. These are slower and less stable, - * but are more flexible for general usage. - */ - if (ob->rigidbody_object->type == RBO_TYPE_PASSIVE) { - shape = RB_shape_new_trimesh(mdata); - } - else { - shape = RB_shape_new_gimpact_mesh(mdata); - } - } - } - else { - CLOG_ERROR(&LOG, "cannot make Triangular Mesh collision shape for non-Mesh object"); - } - - return shape; + rbCollisionShape *shape = NULL; + + if (ob->type == OB_MESH) { + Mesh *mesh = NULL; + MVert *mvert; + const MLoopTri *looptri; + int totvert; + int tottri; + const MLoop *mloop; + + mesh = rigidbody_get_mesh(ob); + + /* ensure mesh validity, then grab data */ + if (mesh == NULL) + return NULL; + + mvert = mesh->mvert; + totvert = mesh->totvert; + looptri = BKE_mesh_runtime_looptri_ensure(mesh); + tottri = mesh->runtime.looptris.len; + mloop = mesh->mloop; + + /* sanity checking - potential case when no data will be present */ + if ((totvert == 0) || (tottri == 0)) { + CLOG_WARN( + &LOG, "no geometry data converted for Mesh Collision Shape (ob = %s)", ob->id.name + 2); + } + else { + rbMeshData *mdata; + int i; + + /* init mesh data for collision shape */ + mdata = RB_trimesh_data_new(tottri, totvert); + + RB_trimesh_add_vertices(mdata, (float *)mvert, totvert, sizeof(MVert)); + + /* loop over all faces, adding them as triangles to the collision shape + * (so for some faces, more than triangle will get added) + */ + if (mvert && looptri) { + for (i = 0; i < tottri; i++) { + /* add first triangle - verts 1,2,3 */ + const MLoopTri *lt = &looptri[i]; + int vtri[3]; + + vtri[0] = mloop[lt->tri[0]].v; + vtri[1] = mloop[lt->tri[1]].v; + vtri[2] = mloop[lt->tri[2]].v; + + RB_trimesh_add_triangle_indices(mdata, i, UNPACK3(vtri)); + } + } + + RB_trimesh_finish(mdata); + + /* construct collision shape + * + * These have been chosen to get better speed/accuracy tradeoffs with regards + * to limitations of each: + * - BVH-Triangle Mesh: for passive objects only. Despite having greater + * speed/accuracy, they cannot be used for moving objects. + * - GImpact Mesh: for active objects. These are slower and less stable, + * but are more flexible for general usage. + */ + if (ob->rigidbody_object->type == RBO_TYPE_PASSIVE) { + shape = RB_shape_new_trimesh(mdata); + } + else { + shape = RB_shape_new_gimpact_mesh(mdata); + } + } + } + else { + CLOG_ERROR(&LOG, "cannot make Triangular Mesh collision shape for non-Mesh object"); + } + + return shape; } /* Create new physics sim collision shape for object and store it, @@ -390,97 +403,99 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob) */ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) { - RigidBodyOb *rbo = ob->rigidbody_object; - rbCollisionShape *new_shape = NULL; - BoundBox *bb = NULL; - float size[3] = {1.0f, 1.0f, 1.0f}; - float radius = 1.0f; - float height = 1.0f; - float capsule_height; - float hull_margin = 0.0f; - bool can_embed = true; - bool has_volume; - - /* sanity check */ - if (rbo == NULL) - return; - - /* don't create a new shape if we already have one and don't want to rebuild it */ - if (rbo->shared->physics_shape && !rebuild) - return; - - /* if automatically determining dimensions, use the Object's boundbox - * - assume that all quadrics are standing upright on local z-axis - * - assume even distribution of mass around the Object's pivot - * (i.e. Object pivot is centralized in boundbox) - */ - // XXX: all dimensions are auto-determined now... later can add stored settings for this - /* get object dimensions without scaling */ - bb = BKE_object_boundbox_get(ob); - if (bb) { - size[0] = (bb->vec[4][0] - bb->vec[0][0]); - size[1] = (bb->vec[2][1] - bb->vec[0][1]); - size[2] = (bb->vec[1][2] - bb->vec[0][2]); - } - mul_v3_fl(size, 0.5f); - - if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { - /* take radius as largest x/y dimension, and height as z-dimension */ - radius = MAX2(size[0], size[1]); - height = size[2]; - } - else if (rbo->shape == RB_SHAPE_SPHERE) { - /* take radius to the largest dimension to try and encompass everything */ - radius = MAX3(size[0], size[1], size[2]); - } - - /* create new shape */ - switch (rbo->shape) { - case RB_SHAPE_BOX: - new_shape = RB_shape_new_box(size[0], size[1], size[2]); - break; - - case RB_SHAPE_SPHERE: - new_shape = RB_shape_new_sphere(radius); - break; - - case RB_SHAPE_CAPSULE: - capsule_height = (height - radius) * 2.0f; - new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f); - break; - case RB_SHAPE_CYLINDER: - new_shape = RB_shape_new_cylinder(radius, height); - break; - case RB_SHAPE_CONE: - new_shape = RB_shape_new_cone(radius, height * 2.0f); - break; - - case RB_SHAPE_CONVEXH: - /* try to emged collision margin */ - has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f); - - if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume) - hull_margin = 0.04f; - new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed); - if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) - rbo->margin = (can_embed && has_volume) ? 0.04f : 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */ - break; - case RB_SHAPE_TRIMESH: - new_shape = rigidbody_get_shape_trimesh_from_mesh(ob); - break; - } - /* use box shape if we can't fall back to old shape */ - if (new_shape == NULL && rbo->shared->physics_shape == NULL) { - new_shape = RB_shape_new_box(size[0], size[1], size[2]); - } - /* assign new collision shape if creation was successful */ - if (new_shape) { - if (rbo->shared->physics_shape) { - RB_shape_delete(rbo->shared->physics_shape); - } - rbo->shared->physics_shape = new_shape; - RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo)); - } + RigidBodyOb *rbo = ob->rigidbody_object; + rbCollisionShape *new_shape = NULL; + BoundBox *bb = NULL; + float size[3] = {1.0f, 1.0f, 1.0f}; + float radius = 1.0f; + float height = 1.0f; + float capsule_height; + float hull_margin = 0.0f; + bool can_embed = true; + bool has_volume; + + /* sanity check */ + if (rbo == NULL) + return; + + /* don't create a new shape if we already have one and don't want to rebuild it */ + if (rbo->shared->physics_shape && !rebuild) + return; + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralized in boundbox) + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + /* get object dimensions without scaling */ + bb = BKE_object_boundbox_get(ob); + if (bb) { + size[0] = (bb->vec[4][0] - bb->vec[0][0]); + size[1] = (bb->vec[2][1] - bb->vec[0][1]); + size[2] = (bb->vec[1][2] - bb->vec[0][2]); + } + mul_v3_fl(size, 0.5f); + + if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + /* take radius as largest x/y dimension, and height as z-dimension */ + radius = MAX2(size[0], size[1]); + height = size[2]; + } + else if (rbo->shape == RB_SHAPE_SPHERE) { + /* take radius to the largest dimension to try and encompass everything */ + radius = MAX3(size[0], size[1], size[2]); + } + + /* create new shape */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + new_shape = RB_shape_new_box(size[0], size[1], size[2]); + break; + + case RB_SHAPE_SPHERE: + new_shape = RB_shape_new_sphere(radius); + break; + + case RB_SHAPE_CAPSULE: + capsule_height = (height - radius) * 2.0f; + new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f); + break; + case RB_SHAPE_CYLINDER: + new_shape = RB_shape_new_cylinder(radius, height); + break; + case RB_SHAPE_CONE: + new_shape = RB_shape_new_cone(radius, height * 2.0f); + break; + + case RB_SHAPE_CONVEXH: + /* try to emged collision margin */ + has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f); + + if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume) + hull_margin = 0.04f; + new_shape = rigidbody_get_shape_convexhull_from_mesh(ob, hull_margin, &can_embed); + if (!(rbo->flag & RBO_FLAG_USE_MARGIN)) + rbo->margin = (can_embed && has_volume) ? + 0.04f : + 0.0f; /* RB_TODO ideally we shouldn't directly change the margin here */ + break; + case RB_SHAPE_TRIMESH: + new_shape = rigidbody_get_shape_trimesh_from_mesh(ob); + break; + } + /* use box shape if we can't fall back to old shape */ + if (new_shape == NULL && rbo->shared->physics_shape == NULL) { + new_shape = RB_shape_new_box(size[0], size[1], size[2]); + } + /* assign new collision shape if creation was successful */ + if (new_shape) { + if (rbo->shared->physics_shape) { + RB_shape_delete(rbo->shared->physics_shape); + } + rbo->shared->physics_shape = new_shape; + RB_shape_set_margin(rbo->shared->physics_shape, RBO_GET_MARGIN(rbo)); + } } /* --------------------- */ @@ -489,152 +504,151 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) // TODO: allow a parameter to specify method used to calculate this? void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { - RigidBodyOb *rbo = ob->rigidbody_object; - - float size[3] = {1.0f, 1.0f, 1.0f}; - float radius = 1.0f; - float height = 1.0f; - - float volume = 0.0f; - - /* if automatically determining dimensions, use the Object's boundbox - * - assume that all quadrics are standing upright on local z-axis - * - assume even distribution of mass around the Object's pivot - * (i.e. Object pivot is centralized in boundbox) - * - boundbox gives full width - */ - // XXX: all dimensions are auto-determined now... later can add stored settings for this - BKE_object_dimensions_get(ob, size); - - if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { - /* take radius as largest x/y dimension, and height as z-dimension */ - radius = MAX2(size[0], size[1]) * 0.5f; - height = size[2]; - } - else if (rbo->shape == RB_SHAPE_SPHERE) { - /* take radius to the largest dimension to try and encompass everything */ - radius = max_fff(size[0], size[1], size[2]) * 0.5f; - } - - /* calculate volume as appropriate */ - switch (rbo->shape) { - case RB_SHAPE_BOX: - volume = size[0] * size[1] * size[2]; - break; - - case RB_SHAPE_SPHERE: - volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius; - break; - - /* for now, assume that capsule is close enough to a cylinder... */ - case RB_SHAPE_CAPSULE: - case RB_SHAPE_CYLINDER: - volume = (float)M_PI * radius * radius * height; - break; - - case RB_SHAPE_CONE: - volume = (float)M_PI / 3.0f * radius * radius * height; - break; - - case RB_SHAPE_CONVEXH: - case RB_SHAPE_TRIMESH: - { - if (ob->type == OB_MESH) { - Mesh *mesh = rigidbody_get_mesh(ob); - MVert *mvert; - const MLoopTri *lt = NULL; - int totvert, tottri = 0; - const MLoop *mloop = NULL; - - /* ensure mesh validity, then grab data */ - if (mesh == NULL) - return; - - mvert = mesh->mvert; - totvert = mesh->totvert; - lt = BKE_mesh_runtime_looptri_ensure(mesh); - tottri = mesh->runtime.looptris.len; - mloop = mesh->mloop; - - if (totvert > 0 && tottri > 0) { - BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL); - } - } - else { - /* rough estimate from boundbox as fallback */ - /* XXX could implement other types of geometry here (curves, etc.) */ - volume = size[0] * size[1] * size[2]; - } - break; - } - } - - /* return the volume calculated */ - if (r_vol) *r_vol = volume; + RigidBodyOb *rbo = ob->rigidbody_object; + + float size[3] = {1.0f, 1.0f, 1.0f}; + float radius = 1.0f; + float height = 1.0f; + + float volume = 0.0f; + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralized in boundbox) + * - boundbox gives full width + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + BKE_object_dimensions_get(ob, size); + + if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) { + /* take radius as largest x/y dimension, and height as z-dimension */ + radius = MAX2(size[0], size[1]) * 0.5f; + height = size[2]; + } + else if (rbo->shape == RB_SHAPE_SPHERE) { + /* take radius to the largest dimension to try and encompass everything */ + radius = max_fff(size[0], size[1], size[2]) * 0.5f; + } + + /* calculate volume as appropriate */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + volume = size[0] * size[1] * size[2]; + break; + + case RB_SHAPE_SPHERE: + volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius; + break; + + /* for now, assume that capsule is close enough to a cylinder... */ + case RB_SHAPE_CAPSULE: + case RB_SHAPE_CYLINDER: + volume = (float)M_PI * radius * radius * height; + break; + + case RB_SHAPE_CONE: + volume = (float)M_PI / 3.0f * radius * radius * height; + break; + + case RB_SHAPE_CONVEXH: + case RB_SHAPE_TRIMESH: { + if (ob->type == OB_MESH) { + Mesh *mesh = rigidbody_get_mesh(ob); + MVert *mvert; + const MLoopTri *lt = NULL; + int totvert, tottri = 0; + const MLoop *mloop = NULL; + + /* ensure mesh validity, then grab data */ + if (mesh == NULL) + return; + + mvert = mesh->mvert; + totvert = mesh->totvert; + lt = BKE_mesh_runtime_looptri_ensure(mesh); + tottri = mesh->runtime.looptris.len; + mloop = mesh->mloop; + + if (totvert > 0 && tottri > 0) { + BKE_mesh_calc_volume(mvert, totvert, lt, tottri, mloop, &volume, NULL); + } + } + else { + /* rough estimate from boundbox as fallback */ + /* XXX could implement other types of geometry here (curves, etc.) */ + volume = size[0] * size[1] * size[2]; + } + break; + } + } + + /* return the volume calculated */ + if (r_vol) + *r_vol = volume; } void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { - RigidBodyOb *rbo = ob->rigidbody_object; - - float size[3] = {1.0f, 1.0f, 1.0f}; - float height = 1.0f; - - zero_v3(r_center); - - /* if automatically determining dimensions, use the Object's boundbox - * - assume that all quadrics are standing upright on local z-axis - * - assume even distribution of mass around the Object's pivot - * (i.e. Object pivot is centralized in boundbox) - * - boundbox gives full width - */ - // XXX: all dimensions are auto-determined now... later can add stored settings for this - BKE_object_dimensions_get(ob, size); - - /* calculate volume as appropriate */ - switch (rbo->shape) { - case RB_SHAPE_BOX: - case RB_SHAPE_SPHERE: - case RB_SHAPE_CAPSULE: - case RB_SHAPE_CYLINDER: - break; - - case RB_SHAPE_CONE: - /* take radius as largest x/y dimension, and height as z-dimension */ - height = size[2]; - /* cone is geometrically centered on the median, - * center of mass is 1/4 up from the base - */ - r_center[2] = -0.25f * height; - break; - - case RB_SHAPE_CONVEXH: - case RB_SHAPE_TRIMESH: - { - if (ob->type == OB_MESH) { - Mesh *mesh = rigidbody_get_mesh(ob); - MVert *mvert; - const MLoopTri *looptri; - int totvert, tottri; - const MLoop *mloop; - - /* ensure mesh validity, then grab data */ - if (mesh == NULL) - return; - - mvert = mesh->mvert; - totvert = mesh->totvert; - looptri = BKE_mesh_runtime_looptri_ensure(mesh); - tottri = mesh->runtime.looptris.len; - mloop = mesh->mloop; - - if (totvert > 0 && tottri > 0) { - BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center); - } - } - break; - } - } + RigidBodyOb *rbo = ob->rigidbody_object; + + float size[3] = {1.0f, 1.0f, 1.0f}; + float height = 1.0f; + + zero_v3(r_center); + + /* if automatically determining dimensions, use the Object's boundbox + * - assume that all quadrics are standing upright on local z-axis + * - assume even distribution of mass around the Object's pivot + * (i.e. Object pivot is centralized in boundbox) + * - boundbox gives full width + */ + // XXX: all dimensions are auto-determined now... later can add stored settings for this + BKE_object_dimensions_get(ob, size); + + /* calculate volume as appropriate */ + switch (rbo->shape) { + case RB_SHAPE_BOX: + case RB_SHAPE_SPHERE: + case RB_SHAPE_CAPSULE: + case RB_SHAPE_CYLINDER: + break; + + case RB_SHAPE_CONE: + /* take radius as largest x/y dimension, and height as z-dimension */ + height = size[2]; + /* cone is geometrically centered on the median, + * center of mass is 1/4 up from the base + */ + r_center[2] = -0.25f * height; + break; + + case RB_SHAPE_CONVEXH: + case RB_SHAPE_TRIMESH: { + if (ob->type == OB_MESH) { + Mesh *mesh = rigidbody_get_mesh(ob); + MVert *mvert; + const MLoopTri *looptri; + int totvert, tottri; + const MLoop *mloop; + + /* ensure mesh validity, then grab data */ + if (mesh == NULL) + return; + + mvert = mesh->mvert; + totvert = mesh->totvert; + looptri = BKE_mesh_runtime_looptri_ensure(mesh); + tottri = mesh->runtime.looptris.len; + mloop = mesh->mloop; + + if (totvert > 0 && tottri > 0) { + BKE_mesh_calc_volume(mvert, totvert, looptri, tottri, mloop, NULL, r_center); + } + } + break; + } + } } /* --------------------- */ @@ -646,125 +660,134 @@ void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) */ 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->shared->physics_shape == NULL || rebuild) - rigidbody_validate_sim_shape(ob, true); - - if (rbo->shared->physics_object) { - RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); - } - if (!rbo->shared->physics_object || rebuild) { - /* remove rigid body if it already exists before creating a new one */ - if (rbo->shared->physics_object) { - RB_body_delete(rbo->shared->physics_object); - } - - mat4_to_loc_quat(loc, rot, ob->obmat); - - rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot); - - RB_body_set_friction(rbo->shared->physics_object, rbo->friction); - RB_body_set_restitution(rbo->shared->physics_object, rbo->restitution); - - RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping); - RB_body_set_sleep_thresh(rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh); - RB_body_set_activation_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION); - - if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED) - RB_body_deactivate(rbo->shared->physics_object); - - - RB_body_set_linear_factor(rbo->shared->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->shared->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->shared->physics_object, RBO_GET_MASS(rbo)); - RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); - } - - if (rbw && rbw->shared->physics_world) - RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups); + 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->shared->physics_shape == NULL || rebuild) + rigidbody_validate_sim_shape(ob, true); + + if (rbo->shared->physics_object) { + RB_dworld_remove_body(rbw->shared->physics_world, rbo->shared->physics_object); + } + if (!rbo->shared->physics_object || rebuild) { + /* remove rigid body if it already exists before creating a new one */ + if (rbo->shared->physics_object) { + RB_body_delete(rbo->shared->physics_object); + } + + mat4_to_loc_quat(loc, rot, ob->obmat); + + rbo->shared->physics_object = RB_body_new(rbo->shared->physics_shape, loc, rot); + + RB_body_set_friction(rbo->shared->physics_object, rbo->friction); + RB_body_set_restitution(rbo->shared->physics_object, rbo->restitution); + + RB_body_set_damping(rbo->shared->physics_object, rbo->lin_damping, rbo->ang_damping); + RB_body_set_sleep_thresh( + rbo->shared->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh); + RB_body_set_activation_state(rbo->shared->physics_object, + rbo->flag & RBO_FLAG_USE_DEACTIVATION); + + if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED) + RB_body_deactivate(rbo->shared->physics_object); + + RB_body_set_linear_factor(rbo->shared->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->shared->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->shared->physics_object, RBO_GET_MASS(rbo)); + RB_body_set_kinematic_state(rbo->shared->physics_object, + rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + } + + if (rbw && rbw->shared->physics_world) + RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups); } /* --------------------- */ -static void rigidbody_constraint_init_spring( - RigidBodyCon *rbc, void (*set_spring)(rbConstraint *, int, int), - void (*set_stiffness)(rbConstraint *, int, float), void (*set_damping)(rbConstraint *, int, float)) +static void rigidbody_constraint_init_spring(RigidBodyCon *rbc, + void (*set_spring)(rbConstraint *, int, int), + void (*set_stiffness)(rbConstraint *, int, float), + void (*set_damping)(rbConstraint *, int, float)) { - set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X); - set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x); - set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x); + set_spring(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->flag & RBC_FLAG_USE_SPRING_X); + set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_stiffness_x); + set_damping(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->spring_damping_x); - set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y); - set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y); - set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y); + set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->flag & RBC_FLAG_USE_SPRING_Y); + set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_stiffness_y); + set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->spring_damping_y); - set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z); - set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); - set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); + set_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->flag & RBC_FLAG_USE_SPRING_Z); + set_stiffness(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); + set_damping(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); - set_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X); - set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x); - set_damping(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x); + set_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X); + set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x); + set_damping(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x); - set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y); - set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y); - set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y); + set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y); + set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y); + set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y); - set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z); - set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z); - set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); + set_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z); + set_stiffness(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z); + set_damping(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); } -static void rigidbody_constraint_set_limits( - RigidBodyCon *rbc, void (*set_limits)(rbConstraint *, int, float, float)) +static void rigidbody_constraint_set_limits(RigidBodyCon *rbc, + void (*set_limits)(rbConstraint *, int, float, float)) { - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) - set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); - else - set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) - set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); - else - set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) - set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); - else - set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) - set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); - else - set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) - set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); - else - set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); - - if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) - set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); - else - set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_X) + set_limits( + rbc->physics_constraint, RB_LIMIT_LIN_X, rbc->limit_lin_x_lower, rbc->limit_lin_x_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Y) + set_limits( + rbc->physics_constraint, RB_LIMIT_LIN_Y, rbc->limit_lin_y_lower, rbc->limit_lin_y_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_LIN_Z) + set_limits( + rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->limit_lin_z_lower, rbc->limit_lin_z_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_LIN_Z, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_X) + set_limits( + rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->limit_ang_x_lower, rbc->limit_ang_x_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_X, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Y) + set_limits( + rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->limit_ang_y_lower, rbc->limit_ang_y_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Y, 0.0f, -1.0f); + + if (rbc->flag & RBC_FLAG_USE_LIMIT_ANG_Z) + set_limits( + rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->limit_ang_z_lower, rbc->limit_ang_z_upper); + else + set_limits(rbc->physics_constraint, RB_LIMIT_ANG_Z, 0.0f, -1.0f); } /** @@ -774,143 +797,159 @@ static void rigidbody_constraint_set_limits( */ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, bool 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 (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { - if (rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); - RB_constraint_delete(rbc->physics_constraint); - rbc->physics_constraint = NULL; - } - return; - } - - if (rbc->physics_constraint && rebuild == false) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); - } - if (rbc->physics_constraint == NULL || rebuild) { - rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object; - rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->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_SPRING: - if (rbc->spring_type == RBC_SPRING_TYPE2) { - rbc->physics_constraint = RB_constraint_new_6dof_spring2(loc, rot, rb1, rb2); - - rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring2, RB_constraint_set_stiffness_6dof_spring2, RB_constraint_set_damping_6dof_spring2); - - RB_constraint_set_equilibrium_6dof_spring2(rbc->physics_constraint); - - rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring2); - } - else { - rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2); - - rigidbody_constraint_init_spring(rbc, RB_constraint_set_spring_6dof_spring, RB_constraint_set_stiffness_6dof_spring, RB_constraint_set_damping_6dof_spring); - - RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); - - rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); - } - break; - case RBC_TYPE_6DOF: - rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); - - rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); - break; - case RBC_TYPE_MOTOR: - rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2); - - RB_constraint_set_enable_motor(rbc->physics_constraint, rbc->flag & RBC_FLAG_USE_MOTOR_LIN, rbc->flag & RBC_FLAG_USE_MOTOR_ANG); - RB_constraint_set_max_impulse_motor(rbc->physics_constraint, rbc->motor_lin_max_impulse, rbc->motor_ang_max_impulse); - RB_constraint_set_target_velocity_motor(rbc->physics_constraint, rbc->motor_lin_target_velocity, rbc->motor_ang_target_velocity); - break; - } - } - else { /* can't create constraint without both rigid bodies */ - return; - } - - 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->shared->physics_world && rbc->physics_constraint) { - RB_dworld_add_constraint(rbw->shared->physics_world, rbc->physics_constraint, rbc->flag & RBC_FLAG_DISABLE_COLLISIONS); - } + 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 (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) { + if (rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + return; + } + + if (rbc->physics_constraint && rebuild == false) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + } + if (rbc->physics_constraint == NULL || rebuild) { + rbRigidBody *rb1 = rbc->ob1->rigidbody_object->shared->physics_object; + rbRigidBody *rb2 = rbc->ob2->rigidbody_object->shared->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_SPRING: + if (rbc->spring_type == RBC_SPRING_TYPE2) { + rbc->physics_constraint = RB_constraint_new_6dof_spring2(loc, rot, rb1, rb2); + + rigidbody_constraint_init_spring(rbc, + RB_constraint_set_spring_6dof_spring2, + RB_constraint_set_stiffness_6dof_spring2, + RB_constraint_set_damping_6dof_spring2); + + RB_constraint_set_equilibrium_6dof_spring2(rbc->physics_constraint); + + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof_spring2); + } + else { + rbc->physics_constraint = RB_constraint_new_6dof_spring(loc, rot, rb1, rb2); + + rigidbody_constraint_init_spring(rbc, + RB_constraint_set_spring_6dof_spring, + RB_constraint_set_stiffness_6dof_spring, + RB_constraint_set_damping_6dof_spring); + + RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); + + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); + } + break; + case RBC_TYPE_6DOF: + rbc->physics_constraint = RB_constraint_new_6dof(loc, rot, rb1, rb2); + + rigidbody_constraint_set_limits(rbc, RB_constraint_set_limits_6dof); + break; + case RBC_TYPE_MOTOR: + rbc->physics_constraint = RB_constraint_new_motor(loc, rot, rb1, rb2); + + RB_constraint_set_enable_motor(rbc->physics_constraint, + rbc->flag & RBC_FLAG_USE_MOTOR_LIN, + rbc->flag & RBC_FLAG_USE_MOTOR_ANG); + RB_constraint_set_max_impulse_motor( + rbc->physics_constraint, rbc->motor_lin_max_impulse, rbc->motor_ang_max_impulse); + RB_constraint_set_target_velocity_motor(rbc->physics_constraint, + rbc->motor_lin_target_velocity, + rbc->motor_ang_target_velocity); + break; + } + } + else { /* can't create constraint without both rigid bodies */ + return; + } + + 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->shared->physics_world && rbc->physics_constraint) { + RB_dworld_add_constraint(rbw->shared->physics_world, + rbc->physics_constraint, + rbc->flag & RBC_FLAG_DISABLE_COLLISIONS); + } } /* --------------------- */ @@ -919,19 +958,19 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b // 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, bool rebuild) { - /* sanity checks */ - if (rbw == NULL) - return; - - /* create new sim world */ - if (rebuild || rbw->shared->physics_world == NULL) { - if (rbw->shared->physics_world) - RB_dworld_delete(rbw->shared->physics_world); - rbw->shared->physics_world = RB_dworld_new(scene->physics_settings.gravity); - } - - RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations); - RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE); + /* sanity checks */ + if (rbw == NULL) + return; + + /* create new sim world */ + if (rebuild || rbw->shared->physics_world == NULL) { + if (rbw->shared->physics_world) + RB_dworld_delete(rbw->shared->physics_world); + rbw->shared->physics_world = RB_dworld_new(scene->physics_settings.gravity); + } + + RB_dworld_set_solver_iterations(rbw->shared->physics_world, rbw->num_solver_iterations); + RB_dworld_set_split_impulse(rbw->shared->physics_world, rbw->flag & RBW_FLAG_USE_SPLIT_IMPULSE); } /* ************************************** */ @@ -940,255 +979,255 @@ void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool re /* Set up RigidBody world */ RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { - /* try to get whatever RigidBody world that might be representing this already */ - RigidBodyWorld *rbw; + /* try to get whatever RigidBody world that might be representing this already */ + RigidBodyWorld *rbw; - /* sanity checks - * - there must be a valid scene to add world to - * - there mustn't be a sim world using this group already - */ - if (scene == NULL) - return NULL; + /* sanity checks + * - there must be a valid scene to add world to + * - there mustn't be a sim world using this group already + */ + if (scene == NULL) + return NULL; - /* create a new sim world */ - rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld"); - rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared"); + /* create a new sim world */ + rbw = MEM_callocN(sizeof(RigidBodyWorld), "RigidBodyWorld"); + rbw->shared = MEM_callocN(sizeof(*rbw->shared), "RigidBodyWorld_Shared"); - /* set default settings */ - rbw->effector_weights = BKE_effector_add_weights(NULL); + /* set default settings */ + rbw->effector_weights = BKE_effector_add_weights(NULL); - rbw->ltime = PSFRA; + rbw->ltime = PSFRA; - rbw->time_scale = 1.0f; + rbw->time_scale = 1.0f; - rbw->steps_per_second = 60; /* Bullet default (60 Hz) */ - rbw->num_solver_iterations = 10; /* 10 is bullet default */ + rbw->steps_per_second = 60; /* Bullet default (60 Hz) */ + rbw->num_solver_iterations = 10; /* 10 is bullet default */ - rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); - rbw->shared->pointcache->step = 1; + rbw->shared->pointcache = BKE_ptcache_add(&(rbw->shared->ptcaches)); + rbw->shared->pointcache->step = 1; - /* return this sim world */ - return rbw; + /* return this sim world */ + return rbw; } RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { - RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw); - - if (rbw->effector_weights) { - rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights); - } - if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { - id_us_plus((ID *)rbw_copy->group); - id_us_plus((ID *)rbw_copy->constraints); - } - - if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { - /* This is a regular copy, and not a CoW copy for depsgraph evaluation */ - rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared"); - BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES); - rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first; - } - - rbw_copy->objects = NULL; - rbw_copy->numbodies = 0; - rigidbody_update_ob_array(rbw_copy); - - return rbw_copy; + RigidBodyWorld *rbw_copy = MEM_dupallocN(rbw); + + if (rbw->effector_weights) { + rbw_copy->effector_weights = MEM_dupallocN(rbw->effector_weights); + } + if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { + id_us_plus((ID *)rbw_copy->group); + id_us_plus((ID *)rbw_copy->constraints); + } + + if ((flag & LIB_ID_CREATE_NO_MAIN) == 0) { + /* This is a regular copy, and not a CoW copy for depsgraph evaluation */ + rbw_copy->shared = MEM_callocN(sizeof(*rbw_copy->shared), "RigidBodyWorld_Shared"); + BKE_ptcache_copy_list(&rbw_copy->shared->ptcaches, &rbw->shared->ptcaches, LIB_ID_COPY_CACHES); + rbw_copy->shared->pointcache = rbw_copy->shared->ptcaches.first; + } + + rbw_copy->objects = NULL; + rbw_copy->numbodies = 0; + rigidbody_update_ob_array(rbw_copy); + + return rbw_copy; } void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) { - ID_NEW_REMAP(rbw->group); - ID_NEW_REMAP(rbw->constraints); - ID_NEW_REMAP(rbw->effector_weights->group); + ID_NEW_REMAP(rbw->group); + ID_NEW_REMAP(rbw->constraints); + ID_NEW_REMAP(rbw->effector_weights->group); } void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) { - func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP); - func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP); - func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP); - - if (rbw->objects) { - int i; - for (i = 0; i < rbw->numbodies; i++) { - func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP); - } - } + func(rbw, (ID **)&rbw->group, userdata, IDWALK_CB_NOP); + func(rbw, (ID **)&rbw->constraints, userdata, IDWALK_CB_NOP); + func(rbw, (ID **)&rbw->effector_weights->group, userdata, IDWALK_CB_NOP); + + if (rbw->objects) { + int i; + for (i = 0; i < rbw->numbodies; i++) { + func(rbw, (ID **)&rbw->objects[i], userdata, IDWALK_CB_NOP); + } + } } /* Add rigid body settings to the specified object */ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { - RigidBodyOb *rbo; - RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyOb *rbo; + RigidBodyWorld *rbw = scene->rigidbody_world; - /* sanity checks - * - rigidbody world must exist - * - object must exist - * - cannot add rigid body if it already exists - */ - if (ob == NULL || (ob->rigidbody_object != NULL)) - return NULL; + /* sanity checks + * - rigidbody world must exist + * - object must exist + * - cannot add rigid body if it already exists + */ + if (ob == NULL || (ob->rigidbody_object != NULL)) + return NULL; - /* create new settings data, and link it up */ - rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb"); - rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared"); + /* create new settings data, and link it up */ + rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb"); + rbo->shared = MEM_callocN(sizeof(*rbo->shared), "RigidBodyOb_Shared"); - /* set default settings */ - rbo->type = type; + /* set default settings */ + rbo->type = type; - rbo->mass = 1.0f; + rbo->mass = 1.0f; - rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */ - rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */ + rbo->friction = 0.5f; /* best when non-zero. 0.5 is Bullet default */ + rbo->restitution = 0.0f; /* best when zero. 0.0 is Bullet default */ - rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */ + rbo->margin = 0.04f; /* 0.04 (in meters) is Bullet default */ - rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */ - rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */ + rbo->lin_sleep_thresh = 0.4f; /* 0.4 is half of Bullet default */ + rbo->ang_sleep_thresh = 0.5f; /* 0.5 is half of Bullet default */ - rbo->lin_damping = 0.04f; - rbo->ang_damping = 0.1f; + rbo->lin_damping = 0.04f; + rbo->ang_damping = 0.1f; - rbo->col_groups = 1; + rbo->col_groups = 1; - /* use triangle meshes for passive objects - * use convex hulls for active objects since dynamic triangle meshes are very unstable - */ - if (type == RBO_TYPE_ACTIVE) - rbo->shape = RB_SHAPE_CONVEXH; - else - rbo->shape = RB_SHAPE_TRIMESH; + /* use triangle meshes for passive objects + * use convex hulls for active objects since dynamic triangle meshes are very unstable + */ + if (type == RBO_TYPE_ACTIVE) + rbo->shape = RB_SHAPE_CONVEXH; + else + rbo->shape = RB_SHAPE_TRIMESH; - rbo->mesh_source = RBO_MESH_DEFORM; + rbo->mesh_source = RBO_MESH_DEFORM; - /* set initial transform */ - mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + /* set initial transform */ + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); - /* flag cache as outdated */ - BKE_rigidbody_cache_reset(rbw); - rbo->flag |= (RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); + rbo->flag |= (RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); - /* return this object */ - return rbo; + /* return this object */ + 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->flag |= RBC_FLAG_NEEDS_VALIDATE; - - rbc->spring_type = RBC_SPRING_TYPE2; - - 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; - - rbc->spring_damping_x = 0.5f; - rbc->spring_damping_y = 0.5f; - rbc->spring_damping_z = 0.5f; - rbc->spring_damping_ang_x = 0.5f; - rbc->spring_damping_ang_y = 0.5f; - rbc->spring_damping_ang_z = 0.5f; - rbc->spring_stiffness_x = 10.0f; - rbc->spring_stiffness_y = 10.0f; - rbc->spring_stiffness_z = 10.0f; - rbc->spring_stiffness_ang_x = 10.0f; - rbc->spring_stiffness_ang_y = 10.0f; - rbc->spring_stiffness_ang_z = 10.0f; - - rbc->motor_lin_max_impulse = 1.0f; - rbc->motor_lin_target_velocity = 1.0f; - rbc->motor_ang_max_impulse = 1.0f; - rbc->motor_ang_target_velocity = 1.0f; - - /* flag cache as outdated */ - BKE_rigidbody_cache_reset(rbw); - - /* return this object */ - return rbc; + 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->flag |= RBC_FLAG_NEEDS_VALIDATE; + + rbc->spring_type = RBC_SPRING_TYPE2; + + 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; + + rbc->spring_damping_x = 0.5f; + rbc->spring_damping_y = 0.5f; + rbc->spring_damping_z = 0.5f; + rbc->spring_damping_ang_x = 0.5f; + rbc->spring_damping_ang_y = 0.5f; + rbc->spring_damping_ang_z = 0.5f; + rbc->spring_stiffness_x = 10.0f; + rbc->spring_stiffness_y = 10.0f; + rbc->spring_stiffness_z = 10.0f; + rbc->spring_stiffness_ang_x = 10.0f; + rbc->spring_stiffness_ang_y = 10.0f; + rbc->spring_stiffness_ang_z = 10.0f; + + rbc->motor_lin_max_impulse = 1.0f; + rbc->motor_lin_target_velocity = 1.0f; + rbc->motor_ang_max_impulse = 1.0f; + rbc->motor_ang_target_velocity = 1.0f; + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); + + /* return this object */ + return rbc; } void BKE_rigidbody_objects_collection_validate(Scene *scene, RigidBodyWorld *rbw) { - if (rbw->group != NULL) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - if (object->type != OB_MESH || object->rigidbody_object != NULL) { - continue; - } - object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } + if (rbw->group != NULL) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + if (object->type != OB_MESH || object->rigidbody_object != NULL) { + continue; + } + object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } } void BKE_rigidbody_constraints_collection_validate(Scene *scene, RigidBodyWorld *rbw) { - if (rbw->constraints != NULL) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, object) - { - if (object->rigidbody_constraint != NULL) { - continue; - } - object->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, object, RBC_TYPE_FIXED); - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } + if (rbw->constraints != NULL) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, object) { + if (object->rigidbody_constraint != NULL) { + continue; + } + object->rigidbody_constraint = BKE_rigidbody_create_constraint( + scene, object, RBC_TYPE_FIXED); + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } } void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collection, Object *object) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { - RigidBodyWorld *rbw = scene->rigidbody_world; - - if (rbw == NULL) { - continue; - } - - if (rbw->group == collection && object->type == OB_MESH && object->rigidbody_object == NULL) { - object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE); - } - if (rbw->constraints == collection && object->rigidbody_constraint == NULL) { - object->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, object, RBC_TYPE_FIXED); - } - } + for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + RigidBodyWorld *rbw = scene->rigidbody_world; + + if (rbw == NULL) { + continue; + } + + if (rbw->group == collection && object->type == OB_MESH && object->rigidbody_object == NULL) { + object->rigidbody_object = BKE_rigidbody_create_object(scene, object, RBO_TYPE_ACTIVE); + } + if (rbw->constraints == collection && object->rigidbody_constraint == NULL) { + object->rigidbody_constraint = BKE_rigidbody_create_constraint( + scene, object, RBC_TYPE_FIXED); + } + } } /* ************************************** */ @@ -1200,207 +1239,216 @@ void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collectio */ RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { - /* sanity check */ - if (scene == NULL) - return NULL; + /* sanity check */ + if (scene == NULL) + return NULL; - return scene->rigidbody_world; + return scene->rigidbody_world; } void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) { - RigidBodyWorld *rbw = scene->rigidbody_world; - RigidBodyCon *rbc; - int i; - - if (rbw) { - - /* remove object from array */ - if (rbw && rbw->objects) { - for (i = 0; i < rbw->numbodies; i++) { - if (rbw->objects[i] == ob) { - rbw->objects[i] = NULL; - break; - } - } - } - - /* remove object from rigid body constraints */ - if (rbw->constraints) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, obt) - { - if (obt && obt->rigidbody_constraint) { - rbc = obt->rigidbody_constraint; - if (ELEM(ob, rbc->ob1, rbc->ob2)) { - BKE_rigidbody_remove_constraint(scene, obt); - } - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - BKE_collection_object_remove(bmain, rbw->group, ob, false); - } - - /* remove object's settings */ - BKE_rigidbody_free_object(ob, rbw); - - /* flag cache as outdated */ - BKE_rigidbody_cache_reset(rbw); + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyCon *rbc; + int i; + + if (rbw) { + + /* remove object from array */ + if (rbw && rbw->objects) { + for (i = 0; i < rbw->numbodies; i++) { + if (rbw->objects[i] == ob) { + rbw->objects[i] = NULL; + break; + } + } + } + + /* remove object from rigid body constraints */ + if (rbw->constraints) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, obt) { + if (obt && obt->rigidbody_constraint) { + rbc = obt->rigidbody_constraint; + if (ELEM(ob, rbc->ob1, rbc->ob2)) { + BKE_rigidbody_remove_constraint(scene, obt); + } + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + BKE_collection_object_remove(bmain, rbw->group, ob, false); + } + + /* remove object's settings */ + BKE_rigidbody_free_object(ob, rbw); + + /* 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; - - /* remove from rigidbody world, free object won't do this */ - if (rbw && rbw->shared->physics_world && rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); - } - /* remove object's settings */ - BKE_rigidbody_free_constraint(ob); - - /* flag cache as outdated */ - BKE_rigidbody_cache_reset(rbw); + RigidBodyWorld *rbw = scene->rigidbody_world; + RigidBodyCon *rbc = ob->rigidbody_constraint; + + /* remove from rigidbody world, free object won't do this */ + if (rbw && rbw->shared->physics_world && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + } + /* remove object's settings */ + BKE_rigidbody_free_constraint(ob); + + /* flag cache as outdated */ + BKE_rigidbody_cache_reset(rbw); } - /* ************************************** */ /* Simulation Interface - Bullet */ /* Update object array and rigid body count so they're in sync with the rigid body group */ static void rigidbody_update_ob_array(RigidBodyWorld *rbw) { - if (rbw->group == NULL) { - rbw->numbodies = 0; - rbw->objects = realloc(rbw->objects, 0); - return; - } - - int n = 0; - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - (void)object; - n++; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - if (rbw->numbodies != n) { - rbw->numbodies = n; - rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies); - } - - int i = 0; - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - rbw->objects[i] = object; - i++; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + if (rbw->group == NULL) { + rbw->numbodies = 0; + rbw->objects = realloc(rbw->objects, 0); + return; + } + + int n = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + (void)object; + n++; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + if (rbw->numbodies != n) { + rbw->numbodies = n; + rbw->objects = realloc(rbw->objects, sizeof(Object *) * rbw->numbodies); + } + + int i = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + rbw->objects[i] = object; + i++; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } static void rigidbody_update_sim_world(Scene *scene, RigidBodyWorld *rbw) { - float adj_gravity[3]; - - /* adjust gravity to take effector weights into account */ - if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { - copy_v3_v3(adj_gravity, scene->physics_settings.gravity); - mul_v3_fl(adj_gravity, rbw->effector_weights->global_gravity * rbw->effector_weights->weight[0]); - } - else { - zero_v3(adj_gravity); - } - - /* update gravity, since this RNA setting is not part of RigidBody settings */ - RB_dworld_set_gravity(rbw->shared->physics_world, adj_gravity); - - /* update object array in case there are changes */ - rigidbody_update_ob_array(rbw); -} - -static void rigidbody_update_sim_ob(Depsgraph *depsgraph, 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->shared->physics_object == NULL) - return; - - if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { - Mesh *mesh = ob->runtime.mesh_deform_eval; - if (mesh) { - MVert *mvert = mesh->mvert; - int totvert = mesh->totvert; - BoundBox *bb = BKE_object_boundbox_get(ob); - - RB_shape_trimesh_update(rbo->shared->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->shared->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->shared->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->shared->physics_object, true); - RB_body_set_mass(rbo->shared->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->shared->physics_object); - RB_body_set_loc_rot(rbo->shared->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 = BKE_effectors_create(depsgraph, 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->shared->physics_object, eff_loc); - RB_body_get_linear_velocity(rbo->shared->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... - */ - BKE_effectors_apply(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->shared->physics_object); - RB_body_apply_central_force(rbo->shared->physics_object, eff_force); - } - else if (G.f & G_DEBUG) - printf("\tno forces to apply to '%s'\n", ob->id.name + 2); - - /* cleanup */ - BKE_effectors_free(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 :) - */ + float adj_gravity[3]; + + /* adjust gravity to take effector weights into account */ + if (scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) { + copy_v3_v3(adj_gravity, scene->physics_settings.gravity); + mul_v3_fl(adj_gravity, + rbw->effector_weights->global_gravity * rbw->effector_weights->weight[0]); + } + else { + zero_v3(adj_gravity); + } + + /* update gravity, since this RNA setting is not part of RigidBody settings */ + RB_dworld_set_gravity(rbw->shared->physics_world, adj_gravity); + + /* update object array in case there are changes */ + rigidbody_update_ob_array(rbw); +} + +static void rigidbody_update_sim_ob( + Depsgraph *depsgraph, 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->shared->physics_object == NULL) + return; + + if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) { + Mesh *mesh = ob->runtime.mesh_deform_eval; + if (mesh) { + MVert *mvert = mesh->mvert; + int totvert = mesh->totvert; + BoundBox *bb = BKE_object_boundbox_get(ob); + + RB_shape_trimesh_update(rbo->shared->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->shared->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->shared->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->shared->physics_object, true); + RB_body_set_mass(rbo->shared->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->shared->physics_object); + RB_body_set_loc_rot(rbo->shared->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 = BKE_effectors_create(depsgraph, 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->shared->physics_object, eff_loc); + RB_body_get_linear_velocity(rbo->shared->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... + */ + BKE_effectors_apply(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->shared->physics_object); + RB_body_apply_central_force(rbo->shared->physics_object, eff_force); + } + else if (G.f & G_DEBUG) + printf("\tno forces to apply to '%s'\n", ob->id.name + 2); + + /* cleanup */ + BKE_effectors_free(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 :) + */ } /** @@ -1408,250 +1456,252 @@ static void rigidbody_update_sim_ob(Depsgraph *depsgraph, Scene *scene, RigidBod * * \param rebuild: Rebuild entire simulation */ -static void rigidbody_update_simulation(Depsgraph *depsgraph, Scene *scene, RigidBodyWorld *rbw, bool rebuild) -{ - float ctime = DEG_get_ctime(depsgraph); - - /* update world */ - if (rebuild) - BKE_rigidbody_validate_sim_world(scene, rbw, true); - rigidbody_update_sim_world(scene, rbw); - - /* XXX TODO For rebuild: remove all constraints first. - * Otherwise we can end up deleting objects that are still - * referenced by constraints, corrupting bullet's internal list. - * - * Memory management needs redesign here, this is just a dirty workaround. - */ - if (rebuild && rbw->constraints) { - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, ob) - { - RigidBodyCon *rbc = ob->rigidbody_constraint; - if (rbc && rbc->physics_constraint) { - RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); - RB_constraint_delete(rbc->physics_constraint); - rbc->physics_constraint = NULL; - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - } - - /* update objects */ - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob) - { - if (ob->type == OB_MESH) { - /* validate that we've got valid object set up here... */ - RigidBodyOb *rbo = ob->rigidbody_object; - /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ - BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime); - - /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ - /* This cannot be done in CoW evaluation context anymore... */ - if (rbo == NULL) { - BLI_assert(!"CoW object part of RBW object collection without RB object data, should not happen.\n"); - /* Since this object is included in the sim group but doesn't have - * rigid body settings (perhaps it was added manually), add! - * - assume object to be active? That is the default for newly added settings... - */ - ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE); - rigidbody_validate_sim_object(rbw, ob, true); - - rbo = ob->rigidbody_object; - } - else { - /* perform simulation data updates as tagged */ - /* refresh object... */ - if (rebuild) { - /* World has been rebuilt so rebuild object */ - /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(), - * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape(). - * This results in the collision shape being created twice, which is unnecessary. */ - rigidbody_validate_sim_object(rbw, ob, true); - } - else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) { - rigidbody_validate_sim_object(rbw, ob, false); - } - /* refresh shape... */ - if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) { - /* mesh/shape data changed, so force shape refresh */ - rigidbody_validate_sim_shape(ob, true); - /* now tell RB sim about it */ - // XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies - RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape); - } - } - rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); - - /* update simulation object... */ - rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo); - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - /* update constraints */ - if (rbw->constraints == NULL) /* no constraints, move on */ - return; - - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->constraints, 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_time(depsgraph, scene, ob, ctime); - - /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ - /* This cannot be done in CoW evaluation context anymore... */ - if (rbc == NULL) { - BLI_assert(!"CoW object part of RBW constraints collection without RB constraint data, should not happen.\n"); - /* 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); - 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 */ - rigidbody_validate_sim_constraint(rbw, ob, true); - } - else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { - rigidbody_validate_sim_constraint(rbw, ob, false); - } - } - rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; +static void rigidbody_update_simulation(Depsgraph *depsgraph, + Scene *scene, + RigidBodyWorld *rbw, + bool rebuild) +{ + float ctime = DEG_get_ctime(depsgraph); + + /* update world */ + if (rebuild) + BKE_rigidbody_validate_sim_world(scene, rbw, true); + rigidbody_update_sim_world(scene, rbw); + + /* XXX TODO For rebuild: remove all constraints first. + * Otherwise we can end up deleting objects that are still + * referenced by constraints, corrupting bullet's internal list. + * + * Memory management needs redesign here, this is just a dirty workaround. + */ + if (rebuild && rbw->constraints) { + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, ob) { + RigidBodyCon *rbc = ob->rigidbody_constraint; + if (rbc && rbc->physics_constraint) { + RB_dworld_remove_constraint(rbw->shared->physics_world, rbc->physics_constraint); + RB_constraint_delete(rbc->physics_constraint); + rbc->physics_constraint = NULL; + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + } + + /* update objects */ + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { + if (ob->type == OB_MESH) { + /* validate that we've got valid object set up here... */ + RigidBodyOb *rbo = ob->rigidbody_object; + /* update transformation matrix of the object so we don't get a frame of lag for simple animations */ + BKE_object_where_is_calc_time(depsgraph, scene, ob, ctime); + + /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ + /* This cannot be done in CoW evaluation context anymore... */ + if (rbo == NULL) { + BLI_assert(!"CoW object part of RBW object collection without RB object data, should not happen.\n"); + /* Since this object is included in the sim group but doesn't have + * rigid body settings (perhaps it was added manually), add! + * - assume object to be active? That is the default for newly added settings... + */ + ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE); + rigidbody_validate_sim_object(rbw, ob, true); + + rbo = ob->rigidbody_object; + } + else { + /* perform simulation data updates as tagged */ + /* refresh object... */ + if (rebuild) { + /* World has been rebuilt so rebuild object */ + /* TODO(Sybren): rigidbody_validate_sim_object() can call rigidbody_validate_sim_shape(), + * but neither resets the RBO_FLAG_NEEDS_RESHAPE flag nor calls RB_body_set_collision_shape(). + * This results in the collision shape being created twice, which is unnecessary. */ + rigidbody_validate_sim_object(rbw, ob, true); + } + else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) { + rigidbody_validate_sim_object(rbw, ob, false); + } + /* refresh shape... */ + if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) { + /* mesh/shape data changed, so force shape refresh */ + rigidbody_validate_sim_shape(ob, true); + /* now tell RB sim about it */ + // XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies + RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape); + } + } + rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE); + + /* update simulation object... */ + rigidbody_update_sim_ob(depsgraph, scene, rbw, ob, rbo); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + /* update constraints */ + if (rbw->constraints == NULL) /* no constraints, move on */ + return; + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->constraints, 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_time(depsgraph, scene, ob, ctime); + + /* TODO remove this whole block once we are sure we never get NULL rbo here anymore. */ + /* This cannot be done in CoW evaluation context anymore... */ + if (rbc == NULL) { + BLI_assert(!"CoW object part of RBW constraints collection without RB constraint data, should not happen.\n"); + /* 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); + 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 */ + rigidbody_validate_sim_constraint(rbw, ob, true); + } + else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) { + rigidbody_validate_sim_constraint(rbw, ob, false); + } + } + rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBodyWorld *rbw) { - ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); - - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, ob) - { - Base *base = BKE_view_layer_base_find(view_layer, ob); - RigidBodyOb *rbo = ob->rigidbody_object; - /* Reset kinematic state for transformed objects. */ - if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) { - RB_body_set_kinematic_state(rbo->shared->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); - RB_body_set_mass(rbo->shared->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->shared->physics_object); - } - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, ob) { + Base *base = BKE_view_layer_base_find(view_layer, ob); + RigidBodyOb *rbo = ob->rigidbody_object; + /* Reset kinematic state for transformed objects. */ + if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ)) { + RB_body_set_kinematic_state(rbo->shared->physics_object, + rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED); + RB_body_set_mass(rbo->shared->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->shared->physics_object); + } + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; } bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { - return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe); + return (rbw && (rbw->flag & RBW_FLAG_MUTED) == 0 && ctime > rbw->shared->pointcache->startframe); } /* Sync rigid body and object transformations */ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) { - RigidBodyOb *rbo = ob->rigidbody_object; - - /* keep original transform for kinematic and passive objects */ - if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE) - return; - - /* use rigid body transform after cache start frame if objects is not being transformed */ - if (BKE_rigidbody_check_sim_running(rbw, ctime) && !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { - float mat[4][4], size_mat[4][4], size[3]; - - normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point - quat_to_mat4(mat, rbo->orn); - copy_v3_v3(mat[3], rbo->pos); - - mat4_to_size(size, ob->obmat); - size_to_mat4(size_mat, size); - mul_m4_m4m4(mat, mat, size_mat); - - copy_m4_m4(ob->obmat, mat); - } - /* otherwise set rigid body transform to current obmat */ - else { - mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); - } + RigidBodyOb *rbo = ob->rigidbody_object; + + /* keep original transform for kinematic and passive objects */ + if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE) + return; + + /* use rigid body transform after cache start frame if objects is not being transformed */ + if (BKE_rigidbody_check_sim_running(rbw, ctime) && + !(ob->flag & SELECT && G.moving & G_TRANSFORM_OBJ)) { + float mat[4][4], size_mat[4][4], size[3]; + + normalize_qt(rbo->orn); // RB_TODO investigate why quaternion isn't normalized at this point + quat_to_mat4(mat, rbo->orn); + copy_v3_v3(mat[3], rbo->pos); + + mat4_to_size(size, ob->obmat); + size_to_mat4(size_mat, size); + mul_m4_m4m4(mat, mat, size_mat); + + copy_m4_m4(ob->obmat, mat); + } + /* otherwise set rigid body transform to current obmat */ + else { + mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat); + } } /* 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; - bool correct_delta = !(rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE); - - /* return rigid body and object to their initial states */ - copy_v3_v3(rbo->pos, ob->loc); - copy_v3_v3(ob->loc, loc); - - if (correct_delta) { - add_v3_v3(rbo->pos, ob->dloc); - } - - if (ob->rotmode > 0) { - float qt[4]; - eulO_to_quat(qt, ob->rot, ob->rotmode); - - if (correct_delta) { - float dquat[4]; - eulO_to_quat(dquat, ob->drot, ob->rotmode); - - mul_qt_qtqt(rbo->orn, dquat, qt); - } - else { - copy_qt_qt(rbo->orn, qt); - } - - copy_v3_v3(ob->rot, rot); - } - else if (ob->rotmode == ROT_MODE_AXISANGLE) { - float qt[4]; - axis_angle_to_quat(qt, ob->rotAxis, ob->rotAngle); - - if (correct_delta) { - float dquat[4]; - axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle); - - mul_qt_qtqt(rbo->orn, dquat, qt); - } - else { - copy_qt_qt(rbo->orn, qt); - } - - copy_v3_v3(ob->rotAxis, rotAxis); - ob->rotAngle = rotAngle; - } - else { - if (correct_delta) { - mul_qt_qtqt(rbo->orn, ob->dquat, ob->quat); - } - else { - copy_qt_qt(rbo->orn, ob->quat); - } - - copy_qt_qt(ob->quat, quat); - } - - if (rbo->shared->physics_object) { - /* allow passive objects to return to original transform */ - if (rbo->type == RBO_TYPE_PASSIVE) - RB_body_set_kinematic_state(rbo->shared->physics_object, true); - RB_body_set_loc_rot(rbo->shared->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) +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; + bool correct_delta = !(rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE); + + /* return rigid body and object to their initial states */ + copy_v3_v3(rbo->pos, ob->loc); + copy_v3_v3(ob->loc, loc); + + if (correct_delta) { + add_v3_v3(rbo->pos, ob->dloc); + } + + if (ob->rotmode > 0) { + float qt[4]; + eulO_to_quat(qt, ob->rot, ob->rotmode); + + if (correct_delta) { + float dquat[4]; + eulO_to_quat(dquat, ob->drot, ob->rotmode); + + mul_qt_qtqt(rbo->orn, dquat, qt); + } + else { + copy_qt_qt(rbo->orn, qt); + } + + copy_v3_v3(ob->rot, rot); + } + else if (ob->rotmode == ROT_MODE_AXISANGLE) { + float qt[4]; + axis_angle_to_quat(qt, ob->rotAxis, ob->rotAngle); + + if (correct_delta) { + float dquat[4]; + axis_angle_to_quat(dquat, ob->drotAxis, ob->drotAngle); + + mul_qt_qtqt(rbo->orn, dquat, qt); + } + else { + copy_qt_qt(rbo->orn, qt); + } + + copy_v3_v3(ob->rotAxis, rotAxis); + ob->rotAngle = rotAngle; + } + else { + if (correct_delta) { + mul_qt_qtqt(rbo->orn, ob->dquat, ob->quat); + } + else { + copy_qt_qt(rbo->orn, ob->quat); + } + + copy_qt_qt(ob->quat, quat); + } + + if (rbo->shared->physics_object) { + /* allow passive objects to return to original transform */ + if (rbo->type == RBO_TYPE_PASSIVE) + RB_body_set_kinematic_state(rbo->shared->physics_object, true); + RB_body_set_loc_rot(rbo->shared->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) } void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) { - if (rbw) { - rbw->shared->pointcache->flag |= PTCACHE_OUTDATED; - } + if (rbw) { + rbw->shared->pointcache->flag |= PTCACHE_OUTDATED; + } } /* ------------------ */ @@ -1660,183 +1710,239 @@ void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) /* NOTE: this needs to be called before frame update to work correctly */ void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) { - RigidBodyWorld *rbw = scene->rigidbody_world; - PointCache *cache; - PTCacheID pid; - int startframe, endframe; - - BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); - BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); - cache = rbw->shared->pointcache; - - /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */ - int n = 0; - FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN(rbw->group, object) - { - (void)object; - n++; - } - FOREACH_COLLECTION_OBJECT_RECURSIVE_END; - - if (rbw->shared->physics_world == NULL || rbw->numbodies != n) { - cache->flag |= PTCACHE_OUTDATED; - } - - if (ctime == startframe + 1 && rbw->ltime == startframe) { - if (cache->flag & PTCACHE_OUTDATED) { - BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); - rigidbody_update_simulation(depsgraph, scene, rbw, true); - BKE_ptcache_validate(cache, (int)ctime); - cache->last_exact = 0; - cache->flag &= ~PTCACHE_REDO_NEEDED; - } - } + RigidBodyWorld *rbw = scene->rigidbody_world; + PointCache *cache; + PTCacheID pid; + int startframe, endframe; + + BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); + BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); + cache = rbw->shared->pointcache; + + /* flag cache as outdated if we don't have a world or number of objects in the simulation has changed */ + int n = 0; + FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) { + (void)object; + n++; + } + FOREACH_COLLECTION_OBJECT_RECURSIVE_END; + + if (rbw->shared->physics_world == NULL || rbw->numbodies != n) { + cache->flag |= PTCACHE_OUTDATED; + } + + if (ctime == startframe + 1 && rbw->ltime == startframe) { + if (cache->flag & PTCACHE_OUTDATED) { + BKE_ptcache_id_reset(scene, &pid, PTCACHE_RESET_OUTDATED); + rigidbody_update_simulation(depsgraph, scene, rbw, true); + BKE_ptcache_validate(cache, (int)ctime); + cache->last_exact = 0; + cache->flag &= ~PTCACHE_REDO_NEEDED; + } + } } /* Run RigidBody simulation for the specified physics world */ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) { - float timestep; - RigidBodyWorld *rbw = scene->rigidbody_world; - PointCache *cache; - PTCacheID pid; - int startframe, endframe; - - BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); - BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); - cache = rbw->shared->pointcache; - - if (ctime <= startframe) { - rbw->ltime = startframe; - return; - } - /* make sure we don't go out of cache frame range */ - else if (ctime > endframe) { - ctime = endframe; - } - - /* don't try to run the simulation if we don't have a world yet but allow reading baked cache */ - if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED)) - return; - else if (rbw->objects == NULL) - rigidbody_update_ob_array(rbw); - - /* try to read from cache */ - // RB_TODO deal with interpolated, old and baked results - bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED); - - if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) { - BKE_ptcache_validate(cache, (int)ctime); - rbw->ltime = ctime; - return; - } - - if (!DEG_is_active(depsgraph)) { - /* When the depsgraph is inactive we should neither write to the cache - * nor run the simulation. */ - return; - } - - /* advance simulation, we can only step one frame forward */ - if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) { - /* write cache for first frame when on second frame */ - if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { - BKE_ptcache_write(&pid, startframe); - } - - /* update and validate simulation */ - rigidbody_update_simulation(depsgraph, scene, rbw, false); - - /* calculate how much time elapsed since last step in seconds */ - timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale; - /* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */ - RB_dworld_step_simulation(rbw->shared->physics_world, timestep, INT_MAX, 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f)); - - rigidbody_update_simulation_post_step(depsgraph, rbw); - - /* write cache for current frame */ - BKE_ptcache_validate(cache, (int)ctime); - BKE_ptcache_write(&pid, (unsigned int)ctime); - - rbw->ltime = ctime; - } + float timestep; + RigidBodyWorld *rbw = scene->rigidbody_world; + PointCache *cache; + PTCacheID pid; + int startframe, endframe; + + BKE_ptcache_id_from_rigidbody(&pid, NULL, rbw); + BKE_ptcache_id_time(&pid, scene, ctime, &startframe, &endframe, NULL); + cache = rbw->shared->pointcache; + + if (ctime <= startframe) { + rbw->ltime = startframe; + return; + } + /* make sure we don't go out of cache frame range */ + else if (ctime > endframe) { + ctime = endframe; + } + + /* don't try to run the simulation if we don't have a world yet but allow reading baked cache */ + if (rbw->shared->physics_world == NULL && !(cache->flag & PTCACHE_BAKED)) + return; + else if (rbw->objects == NULL) + rigidbody_update_ob_array(rbw); + + /* try to read from cache */ + // RB_TODO deal with interpolated, old and baked results + bool can_simulate = (ctime == rbw->ltime + 1) && !(cache->flag & PTCACHE_BAKED); + + if (BKE_ptcache_read(&pid, ctime, can_simulate) == PTCACHE_READ_EXACT) { + BKE_ptcache_validate(cache, (int)ctime); + rbw->ltime = ctime; + return; + } + + if (!DEG_is_active(depsgraph)) { + /* When the depsgraph is inactive we should neither write to the cache + * nor run the simulation. */ + return; + } + + /* advance simulation, we can only step one frame forward */ + if (compare_ff_relative(ctime, rbw->ltime + 1, FLT_EPSILON, 64)) { + /* write cache for first frame when on second frame */ + if (rbw->ltime == startframe && (cache->flag & PTCACHE_OUTDATED || cache->last_exact == 0)) { + BKE_ptcache_write(&pid, startframe); + } + + /* update and validate simulation */ + rigidbody_update_simulation(depsgraph, scene, rbw, false); + + /* calculate how much time elapsed since last step in seconds */ + timestep = 1.0f / (float)FPS * (ctime - rbw->ltime) * rbw->time_scale; + /* step simulation by the requested timestep, steps per second are adjusted to take time scale into account */ + RB_dworld_step_simulation(rbw->shared->physics_world, + timestep, + INT_MAX, + 1.0f / (float)rbw->steps_per_second * min_ff(rbw->time_scale, 1.0f)); + + rigidbody_update_simulation_post_step(depsgraph, rbw); + + /* write cache for current frame */ + BKE_ptcache_validate(cache, (int)ctime); + BKE_ptcache_write(&pid, (unsigned int)ctime); + + rbw->ltime = ctime; + } } /* ************************************** */ -#else /* WITH_BULLET */ +#else /* WITH_BULLET */ /* stubs */ -#if defined(__GNUC__) || defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wunused-parameter" -#endif +# if defined(__GNUC__) || defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-parameter" +# endif -struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) { return NULL; } -struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag) { return NULL; } -void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {} -void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; } -void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); } -struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; } -struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) { return NULL; } -void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {} -void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) {} -struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) { return NULL; } -struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) { return NULL; } -struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) { return NULL; } -void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) {} -void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) {} -void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) {} -void BKE_rigidbody_aftertrans_update(Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) {} -bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) { return false; } -void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) {} -void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) {} -void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) {} -void BKE_rigidbody_objects_collection_validate(Scene *scene, RigidBodyWorld *rbw) {} -void BKE_rigidbody_constraints_collection_validate(Scene *scene, RigidBodyWorld *rbw) {} -void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collection, Object *object) {} - -#if defined(__GNUC__) || defined(__clang__) -# pragma GCC diagnostic pop -#endif - -#endif /* WITH_BULLET */ +struct RigidBodyOb *BKE_rigidbody_copy_object(const Object *ob, const int flag) +{ + return NULL; +} +struct RigidBodyCon *BKE_rigidbody_copy_constraint(const Object *ob, const int flag) +{ + return NULL; +} +void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) +{ +} +void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) +{ + if (r_vol) + *r_vol = 0.0f; +} +void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) +{ + zero_v3(r_center); +} +struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) +{ + return NULL; +} +struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw, const int flag) +{ + return NULL; +} +void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) +{ +} +void BKE_rigidbody_world_id_loop(struct RigidBodyWorld *rbw, + RigidbodyWorldIDFunc func, + void *userdata) +{ +} +struct RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type) +{ + return NULL; +} +struct RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short type) +{ + return NULL; +} +struct RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene) +{ + return NULL; +} +void BKE_rigidbody_remove_object(struct Main *bmain, Scene *scene, Object *ob) +{ +} +void BKE_rigidbody_remove_constraint(Scene *scene, Object *ob) +{ +} +void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime) +{ +} +void BKE_rigidbody_aftertrans_update( + Object *ob, float loc[3], float rot[3], float quat[4], float rotAxis[3], float rotAngle) +{ +} +bool BKE_rigidbody_check_sim_running(RigidBodyWorld *rbw, float ctime) +{ + return false; +} +void BKE_rigidbody_cache_reset(RigidBodyWorld *rbw) +{ +} +void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime) +{ +} +void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime) +{ +} +void BKE_rigidbody_objects_collection_validate(Scene *scene, RigidBodyWorld *rbw) +{ +} +void BKE_rigidbody_constraints_collection_validate(Scene *scene, RigidBodyWorld *rbw) +{ +} +void BKE_rigidbody_main_collection_object_add(Main *bmain, Collection *collection, Object *object) +{ +} +# if defined(__GNUC__) || defined(__clang__) +# pragma GCC diagnostic pop +# endif +#endif /* WITH_BULLET */ /* -------------------- */ /* Depsgraph evaluation */ -void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph, - Scene *scene) +void BKE_rigidbody_rebuild_sim(Depsgraph *depsgraph, Scene *scene) { - float ctime = DEG_get_ctime(depsgraph); - DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime); - /* rebuild sim data (i.e. after resetting to start of timeline) */ - if (BKE_scene_check_rigidbody_active(scene)) { - BKE_rigidbody_rebuild_world(depsgraph, scene, ctime); - } + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime); + /* rebuild sim data (i.e. after resetting to start of timeline) */ + if (BKE_scene_check_rigidbody_active(scene)) { + BKE_rigidbody_rebuild_world(depsgraph, scene, ctime); + } } -void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph, - Scene *scene) +void BKE_rigidbody_eval_simulation(Depsgraph *depsgraph, Scene *scene) { - float ctime = DEG_get_ctime(depsgraph); - DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime); - - /* evaluate rigidbody sim */ - if (!BKE_scene_check_rigidbody_active(scene)) { - return; - } - BKE_rigidbody_do_simulation(depsgraph, scene, ctime); + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval_time(depsgraph, __func__, scene->id.name, scene, ctime); + + /* evaluate rigidbody sim */ + if (!BKE_scene_check_rigidbody_active(scene)) { + return; + } + BKE_rigidbody_do_simulation(depsgraph, scene, ctime); } -void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph, - Scene *scene, - Object *ob) +void BKE_rigidbody_object_sync_transforms(Depsgraph *depsgraph, Scene *scene, Object *ob) { - RigidBodyWorld *rbw = scene->rigidbody_world; - float ctime = DEG_get_ctime(depsgraph); - DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime); - /* read values pushed into RBO from sim/cache... */ - BKE_rigidbody_sync_transforms(rbw, ob, ctime); + RigidBodyWorld *rbw = scene->rigidbody_world; + float ctime = DEG_get_ctime(depsgraph); + DEG_debug_print_eval_time(depsgraph, __func__, ob->id.name, ob, ctime); + /* read values pushed into RBO from sim/cache... */ + BKE_rigidbody_sync_transforms(rbw, ob, ctime); } |