/* This function dynamically adds the collision shape of another controller to * the current controller shape provided it is a compound shape. * The idea is that dynamic parenting on a compound object will dynamically extend the shape */ void KX_BulletPhysicsController::AddCompoundChild(KX_IPhysicsController* child) { if (child == NULL || !IsCompound()) return; // other controller must be a bullet controller too // verify that body and shape exist and match KX_BulletPhysicsController* childCtrl = dynamic_cast<KX_BulletPhysicsController*>(child); btRigidBody* rootBody = GetRigidBody(); btRigidBody* childBody = childCtrl->GetRigidBody(); if (!rootBody || !childBody) return; const btCollisionShape* rootShape = rootBody->getCollisionShape(); const btCollisionShape* childShape = childBody->getCollisionShape(); if (!rootShape || !childShape || rootShape->getShapeType() != COMPOUND_SHAPE_PROXYTYPE || childShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) return; btCompoundShape* compoundShape = (btCompoundShape*)rootShape; // compute relative transformation between parent and child btTransform rootTrans; btTransform childTrans; rootBody->getMotionState()->getWorldTransform(rootTrans); childBody->getMotionState()->getWorldTransform(childTrans); btVector3 rootScale = rootShape->getLocalScaling(); rootScale[0] = 1.0/rootScale[0]; rootScale[1] = 1.0/rootScale[1]; rootScale[2] = 1.0/rootScale[2]; // relative scale = child_scale/parent_scale btVector3 relativeScale = childShape->getLocalScaling()*rootScale; btMatrix3x3 rootRotInverse = rootTrans.getBasis().transpose(); // relative pos = parent_rot^-1 * ((parent_pos-child_pos)/parent_scale) btVector3 relativePos = rootRotInverse*((childTrans.getOrigin()-rootTrans.getOrigin())*rootScale); // relative rot = parent_rot^-1 * child_rot btMatrix3x3 relativeRot = rootRotInverse*childTrans.getBasis(); // create a proxy shape info to store the transformation CcdShapeConstructionInfo* proxyShapeInfo = new CcdShapeConstructionInfo(); // store the transformation to this object shapeinfo proxyShapeInfo->m_childTrans.setOrigin(relativePos); proxyShapeInfo->m_childTrans.setBasis(relativeRot); proxyShapeInfo->m_childScale.setValue(relativeScale[0], relativeScale[1], relativeScale[2]); // we will need this to make sure that we remove the right proxy later when unparenting proxyShapeInfo->m_userData = childCtrl; proxyShapeInfo->SetProxy(childCtrl->GetShapeInfo()->AddRef()); // add to parent compound shapeinfo (increments ref count) GetShapeInfo()->AddShape(proxyShapeInfo); // create new bullet collision shape from the object shapeinfo and set scaling btCollisionShape* newChildShape = proxyShapeInfo->CreateBulletShape(childCtrl->GetMargin(), childCtrl->getConstructionInfo().m_bGimpact, true); newChildShape->setLocalScaling(relativeScale); // add bullet collision shape to parent compound collision shape compoundShape->addChildShape(proxyShapeInfo->m_childTrans,newChildShape); // proxyShapeInfo is not needed anymore, release it proxyShapeInfo->Release(); // remember we created this shape childCtrl->m_bulletChildShape = newChildShape; // recompute inertia of parent if (!rootBody->isStaticOrKinematicObject()) { btVector3 localInertia; float mass = 1.f/rootBody->getInvMass(); compoundShape->calculateLocalInertia(mass,localInertia); rootBody->setMassProps(mass,localInertia); } // must update the broadphase cache, GetPhysicsEnvironment()->refreshCcdPhysicsController(this); // remove the children GetPhysicsEnvironment()->disableCcdPhysicsController(childCtrl); }