diff options
11 files changed, 284 insertions, 40 deletions
diff --git a/extern/bullet2/patches/btPolyhedralConvexShape_Inertia_fix.patch b/extern/bullet2/patches/btPolyhedralConvexShape_Inertia_fix.patch new file mode 100644 index 00000000000..abafb5855dd --- /dev/null +++ b/extern/bullet2/patches/btPolyhedralConvexShape_Inertia_fix.patch @@ -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++) diff --git a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp index e8c8c336cd2..1e7f36e0a17 100644 --- a/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp +++ b/extern/bullet2/src/BulletCollision/CollisionShapes/btCompoundShape.cpp @@ -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); 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++) diff --git a/intern/rigidbody/RBI_api.h b/intern/rigidbody/RBI_api.h index d46cb5a7eed..199e9f6f197 100644 --- a/intern/rigidbody/RBI_api.h +++ b/intern/rigidbody/RBI_api.h @@ -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); diff --git a/intern/rigidbody/rb_bullet_api.cpp b/intern/rigidbody/rb_bullet_api.cpp index a8bf1420523..db8c062990c 100644 --- a/intern/rigidbody/rb_bullet_api.cpp +++ b/intern/rigidbody/rb_bullet_api.cpp @@ -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])); diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index b03f80bd600..a55bd89ca18 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -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)) diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 4b09f7542c7..c2c5b42dbb0 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -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); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 4752782eaeb..481a643229e 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -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) { @@ -555,18 +550,69 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild) 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; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 8932d875776..5ae71dd1792 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -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. */ diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index 7ad50dc04de..facf4c6636f 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -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 { diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 325c4e3caa9..450d148d8a3 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -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}, }; |