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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Tönne <lukas.toenne@gmail.com>2014-07-11 14:06:13 +0400
committerLukas Tönne <lukas.toenne@gmail.com>2014-07-11 14:16:32 +0400
commit4633e655dc59b68d622e3319102d5050245a22eb (patch)
tree08982a589dd5a3e96fbf342c8319fe46ad65d642 /source/blender/blenkernel/intern/rigidbody.c
parent78d38a90332027609933be102e61438cb4c7f9f0 (diff)
Fix T41019: Calculate Mass does not calculate actual volume.
This was a ToDo item, for mesh-based rigid body shapes (trimesh, convex) the operator was simply using the bounding box volume, which can grossly overestimate the volume and mass. Calculating the actual volume of a mesh is not so difficult after all, see e.g. http://research.microsoft.com/en-us/um/people/chazhang/publications/icip01_ChaZhang.pdf This patch also allows calculating the center-of-mass in the same way. This is currently unused, because the rigid body system assumes the CoM to be the same as the geometric object center. This is fine most of the time, adding such user settings for "center-of-mass offset" would also add quite a bit of complexity in user space, but it could be necessary at some point. A number of other physical properties could be calculated using the same principle, e.g. the moment of inertia.
Diffstat (limited to 'source/blender/blenkernel/intern/rigidbody.c')
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c179
1 files changed, 179 insertions, 0 deletions
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 09293503ad5..2aaf8adea57 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -57,6 +57,7 @@
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
@@ -455,6 +456,182 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
/* --------------------- */
+/* helper function to calculate volume of rigidbody object */
+// 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 centralised 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 (ELEM3(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 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) {
+ DerivedMesh *dm = rigidbody_get_mesh(ob);
+ MVert *mvert;
+ MFace *mface;
+ int totvert, totface;
+
+ /* ensure mesh validity, then grab data */
+ if (dm == NULL)
+ return;
+
+ DM_ensure_tessface(dm);
+
+ mvert = (dm) ? dm->getVertArray(dm) : NULL;
+ totvert = (dm) ? dm->getNumVerts(dm) : 0;
+ mface = (dm) ? dm->getTessFaceArray(dm) : NULL;
+ totface = (dm) ? dm->getNumTessFaces(dm) : 0;
+
+ if (totvert > 0 && totface > 0) {
+ BKE_mesh_calc_volume(mvert, totvert, mface, totface, &volume, NULL);
+ }
+
+ /* cleanup temp data */
+ if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
+ dm->release(dm);
+ }
+ }
+ 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;
+ }
+
+#if 0 // XXX: not defined yet
+ case RB_SHAPE_COMPOUND:
+ volume = 0.0f;
+ break;
+#endif
+ }
+
+ /* return the volume calculated */
+ if (r_vol) *r_vol = volume;
+}
+
+void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_com[3])
+{
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ float size[3] = {1.0f, 1.0f, 1.0f};
+ float height = 1.0f;
+
+ zero_v3(r_com);
+
+ /* 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 centralised 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_com[2] = -0.25f * height;
+ break;
+
+ case RB_SHAPE_CONVEXH:
+ case RB_SHAPE_TRIMESH:
+ {
+ if (ob->type == OB_MESH) {
+ DerivedMesh *dm = rigidbody_get_mesh(ob);
+ MVert *mvert;
+ MFace *mface;
+ int totvert, totface;
+
+ /* ensure mesh validity, then grab data */
+ if (dm == NULL)
+ return;
+
+ DM_ensure_tessface(dm);
+
+ mvert = (dm) ? dm->getVertArray(dm) : NULL;
+ totvert = (dm) ? dm->getNumVerts(dm) : 0;
+ mface = (dm) ? dm->getTessFaceArray(dm) : NULL;
+ totface = (dm) ? dm->getNumTessFaces(dm) : 0;
+
+ if (totvert > 0 && totface > 0) {
+ BKE_mesh_calc_volume(mvert, totvert, mface, totface, NULL, r_com);
+ }
+
+ /* cleanup temp data */
+ if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
+ dm->release(dm);
+ }
+ }
+ break;
+ }
+
+#if 0 // XXX: not defined yet
+ case RB_SHAPE_COMPOUND:
+ volume = 0.0f;
+ break;
+#endif
+ }
+}
+
+/* --------------------- */
+
/**
* Create physics sim representation of object given RigidBody settings
*
@@ -1414,6 +1591,8 @@ struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; }
void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {}
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_com[3]) { zero_v3(r_com); }
struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; }
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {}