Esempio n. 1
0
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;
}