hkResult DestructibleBridgeDemo::breakOffSubPart( const ContactImpulseLimitBreachedEvent& event, hkArray<hkpShapeKey>& keysBrokenOffOut, hkpPhysicsSystem& systemOut ) { // get the MOPP shape hkpRigidBody* body = event.m_breakingBody; hkpMoppBvTreeShape* moppShape; { const hkpShape* shape = body->getCollidable()->getShape(); HK_ASSERT2(0xafef4321, shape->getType() == HK_SHAPE_MOPP, "DestructibleMoppUtility can only be attached to MOPPs."); moppShape = const_cast<hkpMoppBvTreeShape*>(static_cast<const hkpMoppBvTreeShape*>(shape)); } // for (int p = 0; p < event.m_points.getSize(); p++) for (int p = 0; p < 1; p++) // use only one point ignore the others { const ContactImpulseLimitBreachedEvent::PointInfo& pointInfo = event.m_points[p]; // calc impact position in mopp space hkVector4 impactPosMoppSpace; impactPosMoppSpace.setTransformedInversePos( body->getTransform(), pointInfo.m_contactPoint->getPosition() ); hkReal impactRadius= 5.0f; hkBool keyAlreadyBrokenOff = false; for ( int keyIt = 0; keyIt < keysBrokenOffOut.getSize(); keyIt++ ) { if ( keysBrokenOffOut[keyIt] == pointInfo.m_brokenShapeKey ) { keyAlreadyBrokenOff = true; break; } } if ( keyAlreadyBrokenOff == true ) { //TODO: apply impulse from collision to the rigid body continue; } // // grep objects within a given impact sphere // hkArray<hkpShapeKey>& keys = keysBrokenOffOut; hkInplaceArray<DestructibleMoppUtility::ConvexShapeData,64> shapes; { DestructibleMoppUtility::collectAllConvexChildShapesWithinRadius( moppShape, impactPosMoppSpace, impactRadius, *m_world->getCollisionInput(), shapes, keys ); } // // remove those objects from mopp and display // { for (int i =0; i < keys.getSize();i++){ removeSubShapeFromDisplay( body, moppShape, keys[i] ); } DestructibleMoppUtility::removeKeysFromMopp( moppShape, impactPosMoppSpace, impactRadius, keys ); } // merge shapes which are further away to make things more interesting DestructibleMoppUtility::ShapeData mergedShape; { hkInplaceArray<DestructibleMoppUtility::ConvexShapeData,32> mergedShapes; // decide which shapes to merge for (int i = shapes.getSize()-1; i>=0; i-- ) { DestructibleMoppUtility::ConvexShapeData& data = shapes[i]; if ( data.m_contactDetails.getDistance() > 0.8f ) { mergedShapes.pushBack( data ); shapes.removeAt( i ); } } DestructibleMoppUtility::mergeShapes( mergedShapes, mergedShape ); } // // create new pieces from single and merged shape // for (int i = shapes.getSize()-1; i>=-1; i-- ) { const hkpShape* shape; hkReal massFactor = 1.0f; const hkTransform* transform; { if ( i >=0 ) { DestructibleMoppUtility::ConvexShapeData& data = shapes[i]; transform = &data.m_transform; shape = data.m_shape; } else { transform = &mergedShape.m_transform; shape = mergedShape.m_shape; if (!shape) { continue; } massFactor = 5.0f; } } hkTransform transformWorldSpace; transformWorldSpace.setMul(body->getTransform(), *transform); hkpRigidBodyCinfo info; { info.m_shape = shape; info.m_position = transformWorldSpace.getTranslation(); info.m_rotation . set(transformWorldSpace.getRotation()); info.m_motionType = hkpMotion::MOTION_DYNAMIC; info.m_qualityType = HK_COLLIDABLE_QUALITY_MOVING; info.m_restitution = 0.0f; info.m_angularDamping = 0.7f; info.m_maxAngularVelocity = 3.0f; hkpInertiaTensorComputer::setShapeVolumeMassProperties(info.m_shape, massFactor * 5.0f, info); hkpInertiaTensorComputer::clipInertia( 20.0f, info ); } hkReferencedObject::lockAll(); hkpRigidBody* newBody = new hkpRigidBody(info); hkpPropertyValue shapeKeyProperty; shapeKeyProperty.setInt( pointInfo.m_brokenShapeKey ); newBody->addProperty( HK_BROKEN_OFF_SHAPEKEY_PROP, shapeKeyProperty ); systemOut.addRigidBody(newBody); newBody->removeReference(); if ( i < 0 ) { // only remove reference to our newly created shape info.m_shape->removeReference(); } hkReferencedObject::unlockAll(); } } return HK_SUCCESS; }
hkResult BreakOffPartsDemo::breakOffSubPart( const ContactImpulseLimitBreachedEvent& event, hkArray<hkpShapeKey>& keysBrokenOffOut, hkpPhysicsSystem& systemOut ) { const BreakOffPartsVariant& variant = g_variants[m_variantId]; // // Remove the broken pieces from the car or landscape // hkpRigidBody* breakingBody = event.m_breakingBody; for (int p = 0; p < event.m_points.getSize(); p++) { const ContactImpulseLimitBreachedEvent::PointInfo& pointInfo = event.m_points[p]; hkpShapeKey brokenPieceKey = pointInfo.m_brokenShapeKey; const hkpShape* newShape = HK_NULL; { hkpShape* shape = const_cast<hkpShape*>(breakingBody->getCollidable()->getShape()); switch (shape->m_type ) { case HK_SHAPE_LIST: { hkpListShape* list = static_cast<hkpListShape*>(shape); newShape = list->m_childInfo[brokenPieceKey].m_shape; hkpBreakOffPartsUtil::removeKeysFromListShape( breakingBody, &brokenPieceKey, 1 ); removeSubShapeFromDisplay( event.m_breakingBody, list, brokenPieceKey ); keysBrokenOffOut.pushBack( brokenPieceKey ); break; } case HK_SHAPE_MOPP: { hkpMoppBvTreeShape* moppTree = static_cast<hkpMoppBvTreeShape*>(shape); hkpShapeCollection* collection = const_cast<hkpShapeCollection*>(moppTree->getShapeCollection()); HK_ASSERT2(0xad875a22, collection->getType() == HK_SHAPE_LIST, "The container must be a list shape.."); hkpListShape* list = static_cast<hkpListShape*>(collection); newShape = list->m_childInfo[brokenPieceKey].m_shape; hkpBreakOffPartsUtil::removeKeysFromListShape( breakingBody, &brokenPieceKey, 1 ); removeSubShapeFromDisplay( event.m_breakingBody, list, brokenPieceKey ); keysBrokenOffOut.pushBack( brokenPieceKey ); break; } default: HK_ASSERT2( 0xf03df569, 0, "This shape is not implemented yet" ); return HK_FAILURE; } } // // Create the new broken off piece // hkpRigidBodyCinfo rigidBodyCinfo; { rigidBodyCinfo.m_shape = newShape; rigidBodyCinfo.m_position = breakingBody->getPosition(); rigidBodyCinfo.m_rotation = breakingBody->getRotation(); rigidBodyCinfo.m_linearVelocity = breakingBody->getLinearVelocity(); rigidBodyCinfo.m_angularVelocity = breakingBody->getAngularVelocity(); rigidBodyCinfo.m_mass = 10.0f; rigidBodyCinfo.m_qualityType = (variant.m_type == BREAK_OFF_PARTS_DEMO_TOI) ? HK_COLLIDABLE_QUALITY_MOVING : HK_COLLIDABLE_QUALITY_DEBRIS; hkpInertiaTensorComputer::setShapeVolumeMassProperties( newShape, rigidBodyCinfo.m_mass, rigidBodyCinfo ); } hkReferencedObject::lockAll(); hkpRigidBody* newBody = new hkpRigidBody( rigidBodyCinfo ); systemOut.addRigidBody( newBody ); newBody->removeReference(); hkReferencedObject::unlockAll(); // if the original unbroken body was fixed, the colliding impulse is lost, simply apply the impulse to the new piece if ( breakingBody->isFixedOrKeyframed() ) { hkReal maxImpulse = pointInfo.m_properties->m_maxImpulse; hkVector4 impulse; impulse.setMul4( -maxImpulse, pointInfo.m_contactPoint->getNormal() ); newBody->applyPointImpulse( impulse, pointInfo.m_contactPoint->getPosition() ); } } return HK_SUCCESS; }