hkDemo::Result BreakOffPartsAndSpuDemo::stepDemo() { hkpListShape* lists[] = {m_list0, m_list1}; hkpRigidBody* bodies[] = {m_body0, m_body1}; for (int i = 0; i < 2; i++) { hkpListShape* list = lists[i]; if (list)// && list->getNumChildShapes() > 1) { hkpShapeKey key = list->getFirstKey(); if (i) { key = list->getNextKey(key); // leave the first key in. on one shape -- for testing. } if (key < hkpListShape::MAX_DISABLED_CHILDREN) { list->disableChild(key); if (bodies[i]->isFixed()) { // update aabbs this way: // bodies[i]->markForWrite(); hkpBreakOffPartsUtil::removeKeysFromListShape( bodies[i], &key, 1 ); bodies[i]->unmarkForWrite(); // // or this way: // // m_world->markForWrite(); // hkpEntityAabbUtil::entityBatchRecalcAabb(m_world->getCollisionInput(), (hkpEntity**)bodies+i, 1); // m_world->unmarkForWrite(); } // remove child from graphics bodies[i]->markForWrite(); removeSubShapeFromDisplay( bodies[i], list, key ); bodies[i]->unmarkForWrite(); } } } return hkDefaultPhysicsDemo::stepDemo(); }
void DestructibleHierarchy::breakOffNode(int nodeIdx, hkArray<DestructibleHierarchyCollisionEvent>& collisionEvents) { Node* node = &m_nodes[nodeIdx]; int immediateParent = node->m_parentIdx; HK_ASSERT2(0xad78d9dd, immediateParent != INVALID_NODE_INDEX, "where's the parent?"); // detach from parent Node* immediateParentNode = &m_nodes[immediateParent]; HK_ON_DEBUG( int initChildCount = immediateParentNode->m_childrenIdx.getSize() ); for (int c = 0; c < immediateParentNode->m_childrenIdx.getSize(); c++) { if (immediateParentNode->m_childrenIdx[c] == nodeIdx) { immediateParentNode->m_childrenIdx.removeAtAndCopy(c); break; } } HK_ASSERT2(0xad78ddaa, initChildCount-1 == immediateParentNode->m_childrenIdx.getSize(), "child not detached!" ); hkTransform accumulatedTransform = immediateParentNode->m_transform; // Find parent rigid body.. int parentIdx = immediateParent; Node* parentNode = immediateParentNode; while(parentNode->m_body == HK_NULL) { parentIdx = parentNode->m_parentIdx; parentNode = &m_nodes[parentIdx]; hkTransform tmp; tmp.setMul(parentNode->m_transform, accumulatedTransform); accumulatedTransform = tmp; HK_ASSERT2(0xad678daa, parentNode, "No parent rigid body found!"); } // Create new body hkpRigidBody* newBody; { hkpShape* shape = buildShape(nodeIdx); hkpShape* flatShape = hkFlattenShapeHierarchyUtil::flattenHierarchy(shape); shape->removeReference(); newBody = DestructibleHierarchy::buildRigidBody(flatShape, this, nodeIdx); flatShape->removeReference(); const hkSmallArray< hkpCollisionListener* >& listeners = parentNode->m_body->getCollisionListeners(); for (int i = 0; i < listeners.getSize(); i++) { newBody->addCollisionListener(listeners[i]); } } // init velocites for new body { // reposition the body hkTransform parentTransform; if (parentNode->m_initialTransformOfHierarchy) { parentTransform = *parentNode->m_initialTransformOfHierarchy; } else { parentTransform = parentNode->m_body->getTransform(); } hkTransform newBodyTransform; newBodyTransform.setMul( parentTransform, accumulatedTransform ); newBody->setTransform(newBodyTransform); // compute velocities hkVector4 linVel = parentNode->m_body->getLinearVelocity(); hkVector4 angVel = parentNode->m_body->getAngularVelocity(); hkVector4 relCm; relCm.setSub4(newBody->getCenterOfMassInWorld(), parentNode->m_body->getCenterOfMassInWorld()); hkVector4 extraLin; extraLin.setCross(angVel, relCm); linVel.add4(extraLin); newBody->setLinearVelocity( linVel ); newBody->setAngularVelocity( angVel ); } // set newBody position parentNode->m_body->getWorld()->addEntity(newBody); newBody->removeReference(); newBody = HK_NULL; // Update shape of parent body if (!parentNode->m_body->isFixed()) { hkpShape* shape = buildShape(parentIdx); if (shape) { hkVector4 oldCm = parentNode->m_body->getCenterOfMassInWorld(); hkpShape* flatShape = hkFlattenShapeHierarchyUtil::flattenHierarchy(shape); updateShapeOfRigidBody(flatShape, parentNode->m_body); shape->removeReference(); flatShape->removeReference(); hkVector4 relCm; relCm.setSub4(parentNode->m_body->getCenterOfMassInWorld(), oldCm); hkVector4 extraLin; extraLin.setCross(parentNode->m_body->getAngularVelocity(), relCm); hkVector4 linVel; linVel.setAdd4(parentNode->m_body->getLinearVelocity(), extraLin); parentNode->m_body->setLinearVelocity(linVel); } else { parentNode->m_body->getWorld()->removeEntity(parentNode->m_body); parentNode->m_body->removeReference(); parentNode->m_body = HK_NULL; } } else // if (!parentNode->m_body->isFixed()) { // if we're breaking off of a fixed shape -- this must be the one fixed mopp shape const hkpShape* shape = parentNode->m_body->getCollidable()->getShape(); HK_ASSERT2(0xad1788dd, shape->getType() == HK_SHAPE_MOPP, "The fixed body must have a mopp."); const hkpMoppBvTreeShape* mopp = static_cast<const hkpMoppBvTreeShape*>(shape); // Remove shapeKeys from mopp HK_ACCESS_CHECK_OBJECT(parentNode->m_body->getWorld(), HK_ACCESS_RW ); hkArray<hkpShapeKey> brokenOffShapeKeys; collectShapeKeys(nodeIdx, brokenOffShapeKeys); for (int i = brokenOffShapeKeys.getSize()-1; i >=0; i--) { if(brokenOffShapeKeys[i] == HK_INVALID_SHAPE_KEY) { brokenOffShapeKeys.removeAt(i); } else { const hkpMoppBvTreeShape* moppShape = static_cast<const hkpMoppBvTreeShape*>( parentNode->m_body->getCollidable()->getShape() ); removeSubShapeFromDisplay(parentNode->m_body, const_cast<hkpMoppBvTreeShape*>(moppShape), brokenOffShapeKeys[i]); } } hkpRemoveTerminalsMoppModifier modifier(mopp->getMoppCode(), mopp->getShapeCollection(), brokenOffShapeKeys); modifier.applyRemoveTerminals( const_cast<hkpMoppCode*>(mopp->getMoppCode()) ); // disable contact points for the removed shapes.. hkPointerMap<hkpShapeKey, int> shapeKeyMap; shapeKeyMap.reserve(brokenOffShapeKeys.getSize()); for (int k = 0; k < brokenOffShapeKeys.getSize(); k++) { shapeKeyMap.insert(brokenOffShapeKeys[k], 0); } for (int e = 0; e < collisionEvents.getSize(); e++) { if (collisionEvents[e].m_contactMgr) { hkpShapeKey key = collisionEvents[e].m_shapeKey; hkPointerMap<hkpShapeKey, int>::Iterator it = shapeKeyMap.findKey(key); if (shapeKeyMap.isValid(it) && collisionEvents[e].m_body == parentNode->m_body) { static_cast<hkpDynamicsContactMgr*>(collisionEvents[e].m_contactMgr)->getContactPoint(collisionEvents[e].m_contactPointId)->setDistance(100000.0f); collisionEvents.removeAt(e); e--; } } else { collisionEvents.removeAt(e); e--; } } } }
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; }