Add compound shape for rigid body simulation

This patch adds a new compound shape entry to the shape selection
dropdown. It also corrects wrong inertia calculation for convex hulls,
that resulted in strange behavior for small objects.

The compound shape take the collision shapes from its object children
and combines them. This makes it possible to create concave shapes from
primitive shapes. Using this instead of the mesh collision shape is
often many times faster.

Reviewed By: Sergey, Sebastian Parborg

Differential Revision: http://developer.blender.org/D5797
This commit is contained in:
David Vogel 2020-07-30 18:35:34 +02:00 committed by Sebastian Parborg
parent d3944940f9
commit 820ca419e0
Notes: blender-bot 2023-02-14 08:07:50 +01:00
Referenced by issue #73255, Crash entering editmode on an object with particles and ridgidbody parented to another rigidbody
11 changed files with 284 additions and 40 deletions

View File

@ -0,0 +1,41 @@
diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
index 9095c592d87..b831e20c2f9 100644
--- a/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp
@@ -406,17 +406,17 @@ void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& ine
#ifndef __SPU__
//not yet, return box inertia
- btScalar margin = getMargin();
+ //btScalar margin = getMargin();
btTransform ident;
ident.setIdentity();
btVector3 aabbMin,aabbMax;
- getAabb(ident,aabbMin,aabbMax);
+ getAabb(ident,aabbMin,aabbMax); // This already contains the margin
btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5);
- btScalar lx=btScalar(2.)*(halfExtents.x()+margin);
- btScalar ly=btScalar(2.)*(halfExtents.y()+margin);
- btScalar lz=btScalar(2.)*(halfExtents.z()+margin);
+ btScalar lx=btScalar(2.)*(halfExtents.x());
+ btScalar ly=btScalar(2.)*(halfExtents.y());
+ btScalar lz=btScalar(2.)*(halfExtents.z());
const btScalar x2 = lx*lx;
const btScalar y2 = ly*ly;
const btScalar z2 = lz*lz;
@@ -476,10 +476,10 @@ void btPolyhedralConvexAabbCachingShape::recalcLocalAabb()
for ( int i = 0; i < 3; ++i )
{
- m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
- m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
+ m_localAabbMax[i] = _supporting[i][i];
+ m_localAabbMin[i] = _supporting[i + 3][i];
}
-
+
#else
for (int i=0;i<3;i++)

View File

@ -180,7 +180,7 @@ void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVect
localHalfExtents += btVector3(getMargin(),getMargin(),getMargin());
btMatrix3x3 abs_b = trans.getBasis().absolute();
btMatrix3x3 abs_b = trans.getBasis().absolute();
btVector3 center = trans(localCenter);

View File

@ -406,17 +406,17 @@ void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& ine
#ifndef __SPU__
//not yet, return box inertia
btScalar margin = getMargin();
//btScalar margin = getMargin();
btTransform ident;
ident.setIdentity();
btVector3 aabbMin,aabbMax;
getAabb(ident,aabbMin,aabbMax);
getAabb(ident,aabbMin,aabbMax); // This already contains the margin
btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5);
btScalar lx=btScalar(2.)*(halfExtents.x()+margin);
btScalar ly=btScalar(2.)*(halfExtents.y()+margin);
btScalar lz=btScalar(2.)*(halfExtents.z()+margin);
btScalar lx=btScalar(2.)*(halfExtents.x());
btScalar ly=btScalar(2.)*(halfExtents.y());
btScalar lz=btScalar(2.)*(halfExtents.z());
const btScalar x2 = lx*lx;
const btScalar y2 = ly*ly;
const btScalar z2 = lz*lz;
@ -476,10 +476,10 @@ void btPolyhedralConvexAabbCachingShape::recalcLocalAabb()
for ( int i = 0; i < 3; ++i )
{
m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin;
m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin;
m_localAabbMax[i] = _supporting[i][i];
m_localAabbMin[i] = _supporting[i + 3][i];
}
#else
for (int i=0;i<3;i++)

View File

@ -238,6 +238,14 @@ rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh);
/* 2b - GImpact Meshes */
rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh);
/* Compound Shape ---------------- */
rbCollisionShape *RB_shape_new_compound();
void RB_compound_add_child_shape(rbCollisionShape *collisionShape,
rbCollisionShape *shape,
const float loc[3],
const float rot[4]);
/* Cleanup --------------------------- */
void RB_shape_delete(rbCollisionShape *shape);

View File

@ -98,6 +98,8 @@ struct rbMeshData {
struct rbCollisionShape {
btCollisionShape *cshape;
rbMeshData *mesh;
rbCollisionShape **compoundChildShapes;
int compoundChilds;
};
struct rbFilterCallback : public btOverlapFilterCallback {
@ -331,6 +333,7 @@ rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const floa
rbRigidBody *object = new rbRigidBody;
/* current transform */
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(loc[0], loc[1], loc[2]));
trans.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
@ -413,6 +416,10 @@ void RB_body_set_mass(rbRigidBody *object, float value)
shape->calculateLocalInertia(value, localInertia);
}
btVector3 minAabb, maxAabb;
btTransform ident;
ident.setIdentity();
body->getCollisionShape()->getAabb(ident, minAabb, maxAabb);
body->setMassProps(value, localInertia);
body->updateInertiaTensor();
}
@ -597,6 +604,7 @@ void RB_body_set_loc_rot(rbRigidBody *object, const float loc[3], const float ro
/* set transform matrix */
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(loc[0], loc[1], loc[2]));
trans.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
@ -655,6 +663,8 @@ rbCollisionShape *RB_shape_new_box(float x, float y, float z)
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btBoxShape(btVector3(x, y, z));
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -663,6 +673,8 @@ rbCollisionShape *RB_shape_new_sphere(float radius)
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btSphereShape(radius);
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -671,6 +683,8 @@ rbCollisionShape *RB_shape_new_capsule(float radius, float height)
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btCapsuleShapeZ(radius, height);
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -679,6 +693,8 @@ rbCollisionShape *RB_shape_new_cone(float radius, float height)
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btConeShapeZ(radius, height);
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -687,6 +703,8 @@ rbCollisionShape *RB_shape_new_cylinder(float radius, float height)
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btCylinderShapeZ(btVector3(radius, radius, height));
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -709,6 +727,8 @@ rbCollisionShape *RB_shape_new_convex_hull(
shape->cshape = hull_shape;
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -773,6 +793,8 @@ rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh)
shape->cshape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f));
shape->mesh = mesh;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
@ -813,9 +835,46 @@ rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh)
shape->cshape = gimpactShape;
shape->mesh = mesh;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
/* Compound Shape ---------------- */
rbCollisionShape *RB_shape_new_compound()
{
rbCollisionShape *shape = new rbCollisionShape;
btCompoundShape *compoundShape = new btCompoundShape();
shape->cshape = compoundShape;
shape->mesh = NULL;
shape->compoundChilds = 0;
shape->compoundChildShapes = NULL;
return shape;
}
void RB_compound_add_child_shape(rbCollisionShape *parentShape,
rbCollisionShape *shape,
const float loc[3],
const float rot[4])
{
/* set transform matrix */
btTransform trans;
trans.setIdentity();
trans.setOrigin(btVector3(loc[0], loc[1], loc[2]));
trans.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
btCompoundShape *compoundShape = (btCompoundShape *)(parentShape->cshape);
compoundShape->addChildShape(trans, shape->cshape);
/* Store shapes for deletion later */
parentShape->compoundChildShapes = (rbCollisionShape **)(realloc(
parentShape->compoundChildShapes,
sizeof(rbCollisionShape *) * (++parentShape->compoundChilds)));
parentShape->compoundChildShapes[parentShape->compoundChilds - 1] = shape;
}
/* Cleanup --------------------------- */
void RB_shape_delete(rbCollisionShape *shape)
@ -829,6 +888,15 @@ void RB_shape_delete(rbCollisionShape *shape)
if (shape->mesh)
RB_trimesh_data_delete(shape->mesh);
delete shape->cshape;
/* Delete compound child shapes if there are any */
for (int i = 0; i < shape->compoundChilds; i++) {
RB_shape_delete(shape->compoundChildShapes[i]);
}
if (shape->compoundChildShapes != NULL) {
free(shape->compoundChildShapes);
}
delete shape;
}
@ -873,6 +941,7 @@ static void make_constraint_transforms(btTransform &transform1,
float orn[4])
{
btTransform pivot_transform = btTransform();
pivot_transform.setIdentity();
pivot_transform.setOrigin(btVector3(pivot[0], pivot[1], pivot[2]));
pivot_transform.setRotation(btQuaternion(orn[1], orn[2], orn[3], orn[0]));

View File

@ -23,10 +23,10 @@ from bpy.types import (
)
def rigid_body_warning(layout):
def rigid_body_warning(layout, text):
row = layout.row(align=True)
row.alignment = 'RIGHT'
row.label(text="Object does not have a Rigid Body")
row.label(text=text, icon='ERROR')
class PHYSICS_PT_rigidbody_panel:
@ -49,13 +49,24 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
layout.use_property_split = True
ob = context.object
parent = ob.parent
rbo = ob.rigid_body
if rbo is None:
rigid_body_warning(layout)
rigid_body_warning(layout, "Object does not have a Rigid Body")
return
layout.prop(rbo, "type", text="Type")
if parent is not None and parent.rigid_body is not None:
if parent.rigid_body.collision_shape == 'COMPOUND':
row = layout.row(align=True)
row.alignment = 'RIGHT'
row.label(text="This object is part of a compound shape", icon='INFO')
else:
rigid_body_warning(layout, "Rigid Body can't be child of a non compound Rigid Body")
return
if parent is None or parent.rigid_body is None:
layout.prop(rbo, "type", text="Type")
class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel):
@ -66,6 +77,8 @@ class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel):
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
@ -76,7 +89,7 @@ class PHYSICS_PT_rigid_body_settings(PHYSICS_PT_rigidbody_panel, Panel):
rbo = ob.rigid_body
if rbo is None:
rigid_body_warning(layout)
rigid_body_warning(layout, "Object does not have a Rigid Body")
return
col = layout.column()
@ -96,17 +109,32 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None and not obj.parent.rigid_body.collision_shape == 'COMPOUND':
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
ob = context.object
parent = ob.parent
rbo = ob.rigid_body
layout.use_property_split = True
layout.prop(rbo, "collision_shape", text="Shape")
if rbo.collision_shape == 'COMPOUND':
if parent is not None and parent.rigid_body is not None and parent.rigid_body.collision_shape == 'COMPOUND':
rigid_body_warning(layout, "Sub compound shapes are not allowed")
else:
found = False
for child in ob.children:
if child.rigid_body is not None:
found = True
break
if not found:
rigid_body_warning(layout, "There are no child rigid bodies")
if rbo.collision_shape in {'MESH', 'CONVEX_HULL'}:
layout.prop(rbo, "mesh_source", text="Source")
@ -123,6 +151,8 @@ class PHYSICS_PT_rigid_body_collisions_surface(PHYSICS_PT_rigidbody_panel, Panel
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
@ -149,6 +179,8 @@ class PHYSICS_PT_rigid_body_collisions_sensitivity(PHYSICS_PT_rigidbody_panel, P
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None and not obj.parent.rigid_body.collision_shape == 'COMPOUND':
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
@ -180,6 +212,8 @@ class PHYSICS_PT_rigid_body_collisions_collections(PHYSICS_PT_rigidbody_panel, P
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and (context.engine in cls.COMPAT_ENGINES))
def draw(self, context):
@ -200,6 +234,8 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
@classmethod
def poll(cls, context):
obj = context.object
if obj.parent is not None and obj.parent.rigid_body is not None:
return False
return (obj and obj.rigid_body and obj.rigid_body.type == 'ACTIVE'
and (context.engine in cls.COMPAT_ENGINES))

View File

@ -1511,7 +1511,7 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUSE
if (ob && ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo->type == RBO_TYPE_ACTIVE) {
if (rbo->type == RBO_TYPE_ACTIVE && rbo->shared->physics_object != NULL) {
#ifdef WITH_BULLET
RB_body_get_position(rbo->shared->physics_object, rbo->pos);
RB_body_get_orientation(rbo->shared->physics_object, rbo->orn);

View File

@ -466,10 +466,10 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
return shape;
}
/* Create new physics sim collision shape for object and store it,
* or remove the existing one first and replace...
/* Helper function to create physics collision shape for object.
* Returns a new collision shape.
*/
static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
static rbCollisionShape *rigidbody_validate_sim_shape_helper(RigidBodyWorld *rbw, Object *ob)
{
RigidBodyOb *rbo = ob->rigidbody_object;
rbCollisionShape *new_shape = NULL;
@ -484,12 +484,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
/* 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;
return NULL;
}
/* if automatically determining dimensions, use the Object's boundbox
@ -539,7 +534,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
break;
case RB_SHAPE_CONVEXH:
/* try to emged collision margin */
/* try to embed collision margin */
has_volume = (MIN3(size[0], size[1], size[2]) > 0.0f);
if (!(rbo->flag & RBO_FLAG_USE_MARGIN) && has_volume) {
@ -554,19 +549,70 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
break;
case RB_SHAPE_TRIMESH:
new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
break;
case RB_SHAPE_COMPOUND:
new_shape = RB_shape_new_compound(radius);
rbCollisionShape *childShape = NULL;
float loc[3], rot[4];
float mat[4][4];
/* Add children to the compound shape */
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, childObject) {
if (childObject->parent == ob) {
childShape = rigidbody_validate_sim_shape_helper(rbw, childObject);
if (childShape) {
BKE_object_matrix_local_get(childObject, mat);
mat4_to_loc_quat(loc, rot, mat);
RB_compound_add_child_shape(new_shape, childShape, loc, rot);
}
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
break;
}
/* use box shape if we can't fall back to old shape */
if (new_shape == NULL && rbo->shared->physics_shape == NULL) {
/* use box shape if it failed to create new shape */
if (new_shape == NULL) {
new_shape = RB_shape_new_box(size[0], size[1], size[2]);
}
if (new_shape) {
RB_shape_set_margin(new_shape, RBO_GET_MARGIN(rbo));
}
return new_shape;
}
/* Create new physics sim collision shape for object and store it,
* or remove the existing one first and replace...
*/
static void rigidbody_validate_sim_shape(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
RigidBodyOb *rbo = ob->rigidbody_object;
rbCollisionShape *new_shape = NULL;
/* 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;
}
/* Also don't create a shape if this object is parent of a compound shape */
if (ob->parent != NULL && ob->parent->rigidbody_object != NULL &&
ob->parent->rigidbody_object->shape == RB_SHAPE_COMPOUND) {
return;
}
new_shape = rigidbody_validate_sim_shape_helper(rbw, ob);
/* 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));
}
}
@ -750,7 +796,7 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* 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);
rigidbody_validate_sim_shape(rbw, ob, true);
}
if (rbo->shared->physics_object) {
@ -760,6 +806,12 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* remove rigid body if it already exists before creating a new one */
if (rbo->shared->physics_object) {
RB_body_delete(rbo->shared->physics_object);
rbo->shared->physics_object = NULL;
}
/* Don't create rigid body object if the parent is a compound shape */
if (ob->parent != NULL && ob->parent->rigidbody_object != NULL &&
ob->parent->rigidbody_object->shape == RB_SHAPE_COMPOUND) {
return;
}
mat4_to_loc_quat(loc, rot, ob->obmat);
@ -793,7 +845,7 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
}
if (rbw && rbw->shared->physics_world) {
if (rbw && rbw->shared->physics_world && rbo->shared->physics_object) {
RB_dworld_add_body(rbw->shared->physics_world, rbo->shared->physics_object, rbo->col_groups);
}
}
@ -1179,9 +1231,12 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
* - object must exist
* - cannot add rigid body if it already exists
*/
if (ob == NULL || (ob->rigidbody_object != NULL)) {
if (ob == NULL) {
return NULL;
}
if (ob->rigidbody_object != NULL) {
return ob->rigidbody_object;
}
/* create new settings data, and link it up */
rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
@ -1530,7 +1585,11 @@ static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
int n = 0;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
(void)object;
n++;
/* Ignore if this object is the direct child of an object with a compound shape */
if (object->parent == NULL || object->parent->rigidbody_object == NULL ||
object->parent->rigidbody_object->shape != RB_SHAPE_COMPOUND) {
n++;
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
@ -1541,8 +1600,12 @@ static void rigidbody_update_ob_array(RigidBodyWorld *rbw)
int i = 0;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
rbw->objects[i] = object;
i++;
/* Ignore if this object is the direct child of an object with a compound shape */
if (object->parent == NULL || object->parent->rigidbody_object == NULL ||
object->parent->rigidbody_object->shape != RB_SHAPE_COMPOUND) {
rbw->objects[i] = object;
i++;
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
@ -1754,11 +1817,13 @@ static void rigidbody_update_simulation(Depsgraph *depsgraph,
/* refresh shape... */
if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) {
/* mesh/shape data changed, so force shape refresh */
rigidbody_validate_sim_shape(ob, true);
rigidbody_validate_sim_shape(rbw, 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);
if (rbo->shared->physics_object != NULL && rbo->shared->physics_shape != NULL) {
RB_body_set_collision_shape(rbo->shared->physics_object, rbo->shared->physics_shape);
}
}
}
rbo->flag &= ~(RBO_FLAG_NEEDS_VALIDATE | RBO_FLAG_NEEDS_RESHAPE);
@ -1817,7 +1882,8 @@ static void rigidbody_update_simulation_post_step(Depsgraph *depsgraph, RigidBod
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)) {
if (rbo && base && (base->flag & BASE_SELECTED) && (G.moving & G_TRANSFORM_OBJ) &&
rbo->shared->physics_object) {
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));
@ -1840,8 +1906,13 @@ void BKE_rigidbody_sync_transforms(RigidBodyWorld *rbw, Object *ob, float ctime)
{
RigidBodyOb *rbo = ob->rigidbody_object;
/* True if the shape of this object's parent is of type compound */
bool obCompoundParent = (ob->parent != NULL && ob->parent->rigidbody_object != NULL &&
ob->parent->rigidbody_object->shape == RB_SHAPE_COMPOUND);
/* keep original transform for kinematic and passive objects */
if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE) {
if (ELEM(NULL, rbw, rbo) || rbo->flag & RBO_FLAG_KINEMATIC || rbo->type == RBO_TYPE_PASSIVE ||
obCompoundParent) {
return;
}
@ -1963,7 +2034,11 @@ void BKE_rigidbody_rebuild_world(Depsgraph *depsgraph, Scene *scene, float ctime
int n = 0;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (rbw->group, object) {
(void)object;
n++;
/* Ignore if this object is the direct child of an object with a compound shape */
if (object->parent == NULL || object->parent->rigidbody_object == NULL ||
object->parent->rigidbody_object->shape != RB_SHAPE_COMPOUND) {
n++;
}
}
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;

View File

@ -1704,6 +1704,16 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
if (object->rigidbody_object->type == RBO_TYPE_PASSIVE) {
continue;
}
if (object->parent != nullptr && object->parent->rigidbody_object != nullptr &&
object->parent->rigidbody_object->shape == RB_SHAPE_COMPOUND) {
/* If we are a child of a compound shape object, the transforms and sim evaluation will be
* handled by the parent compound shape object. Do not add any evaluation triggers
* for the child objects.
*/
continue;
}
OperationKey rb_transform_copy_key(
&object->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_TRANSFORM_COPY);
/* Rigid body synchronization depends on the actual simulation. */

View File

@ -214,7 +214,7 @@ typedef enum eRigidBody_Shape {
RB_SHAPE_TRIMESH = 6,
/* concave mesh approximated using primitives */
// RB_SHAPE_COMPOUND,
RB_SHAPE_COMPOUND = 7,
} eRigidBody_Shape;
typedef enum eRigidBody_MeshSource {

View File

@ -75,6 +75,11 @@ const EnumPropertyItem rna_enum_rigidbody_object_shape_items[] = {
"Mesh",
"Mesh consisting of triangles only, allowing for more detailed interactions than convex "
"hulls"},
{RB_SHAPE_COMPOUND,
"COMPOUND",
ICON_MESH_DATA,
"Compound Parent",
"Combines all of its direct rigid body children into one rigid object."},
{0, NULL, 0, NULL, NULL},
};