2020-03-09 18:19:08 +00:00
# ifndef COMMON_DEFORMABLE_BODY_SETUP_H
# define COMMON_DEFORMABLE_BODY_SETUP_H
# include "btBulletDynamicsCommon.h"
# include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h"
# include "BulletDynamics/Featherstone/btMultiBodyConstraintSolver.h"
# include "BulletDynamics/Featherstone/btMultiBodyPoint2Point.h"
# include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
# include "btBulletDynamicsCommon.h"
# include "CommonExampleInterface.h"
# include "CommonGUIHelperInterface.h"
# include "CommonRenderInterface.h"
# include "CommonGraphicsAppInterface.h"
# include "CommonWindowInterface.h"
# include "CommonCameraInterface.h"
# include "CommonMultiBodyBase.h"
2020-03-11 18:29:22 +00:00
# include "BulletSoftBody/btSoftBody.h"
2020-03-09 18:19:08 +00:00
struct CommonDeformableBodyBase : public CommonMultiBodyBase
{
btAlignedObjectArray < btDeformableLagrangianForce * > m_forces ;
btSoftBody * m_pickedSoftBody ;
btDeformableMousePickingForce * m_mouseForce ;
2020-06-25 00:48:43 +00:00
btScalar m_pickingForceElasticStiffness , m_pickingForceDampingStiffness , m_maxPickingForce ;
2020-03-09 18:19:08 +00:00
CommonDeformableBodyBase ( GUIHelperInterface * helper )
: CommonMultiBodyBase ( helper ) ,
m_pickedSoftBody ( 0 ) ,
m_mouseForce ( 0 ) ,
2020-06-25 00:48:43 +00:00
m_pickingForceElasticStiffness ( 100 ) ,
m_pickingForceDampingStiffness ( 0.0 ) ,
2020-03-09 18:19:08 +00:00
m_maxPickingForce ( 0.3 )
{
}
virtual btDeformableMultiBodyDynamicsWorld * getDeformableDynamicsWorld ( )
{
return ( btDeformableMultiBodyDynamicsWorld * ) m_dynamicsWorld ;
}
virtual const btDeformableMultiBodyDynamicsWorld * getDeformableDynamicsWorld ( ) const
{
return ( btDeformableMultiBodyDynamicsWorld * ) m_dynamicsWorld ;
}
2020-03-11 18:29:22 +00:00
struct ClosestRayResultCallbackWithInfo : public btCollisionWorld : : ClosestRayResultCallback
{
ClosestRayResultCallbackWithInfo ( const btVector3 & rayFromWorld , const btVector3 & rayToWorld )
: ClosestRayResultCallback ( rayFromWorld , rayToWorld )
{
}
int m_faceId ;
virtual btScalar addSingleResult ( btCollisionWorld : : LocalRayResult & rayResult , bool normalInWorldSpace )
{
//caller already does the filter on the m_closestHitFraction
btAssert ( rayResult . m_hitFraction < = m_closestHitFraction ) ;
m_closestHitFraction = rayResult . m_hitFraction ;
m_collisionObject = rayResult . m_collisionObject ;
if ( rayResult . m_localShapeInfo )
{
m_faceId = rayResult . m_localShapeInfo - > m_triangleIndex ;
}
else
{
m_faceId = - 1 ;
}
if ( normalInWorldSpace )
{
m_hitNormalWorld = rayResult . m_hitNormalLocal ;
}
else
{
///need to transform normal into worldspace
m_hitNormalWorld = m_collisionObject - > getWorldTransform ( ) . getBasis ( ) * rayResult . m_hitNormalLocal ;
}
m_hitPointWorld . setInterpolate3 ( m_rayFromWorld , m_rayToWorld , rayResult . m_hitFraction ) ;
return rayResult . m_hitFraction ;
}
} ;
2020-03-09 18:19:08 +00:00
virtual bool pickBody ( const btVector3 & rayFromWorld , const btVector3 & rayToWorld )
{
if ( getDeformableDynamicsWorld ( ) = = 0 )
return false ;
2020-03-11 18:29:22 +00:00
ClosestRayResultCallbackWithInfo rayCallback ( rayFromWorld , rayToWorld ) ;
2020-03-09 18:19:08 +00:00
getDeformableDynamicsWorld ( ) - > rayTest ( rayFromWorld , rayToWorld , rayCallback ) ;
if ( rayCallback . hasHit ( ) )
{
btVector3 pickPos = rayCallback . m_hitPointWorld ;
btRigidBody * body = ( btRigidBody * ) btRigidBody : : upcast ( rayCallback . m_collisionObject ) ;
btSoftBody * psb = ( btSoftBody * ) btSoftBody : : upcast ( rayCallback . m_collisionObject ) ;
2020-03-13 21:50:36 +00:00
m_oldPickingPos = rayToWorld ;
m_hitPos = pickPos ;
m_oldPickingDist = ( pickPos - rayFromWorld ) . length ( ) ;
2020-03-09 18:19:08 +00:00
if ( body )
{
if ( ! ( body - > isStaticObject ( ) | | body - > isKinematicObject ( ) ) )
{
m_pickedBody = body ;
m_pickedBody - > setActivationState ( DISABLE_DEACTIVATION ) ;
btVector3 localPivot = body - > getCenterOfMassTransform ( ) . inverse ( ) * pickPos ;
btPoint2PointConstraint * p2p = new btPoint2PointConstraint ( * body , localPivot ) ;
m_dynamicsWorld - > addConstraint ( p2p , true ) ;
m_pickedConstraint = p2p ;
btScalar mousePickClamping = 30.f ;
p2p - > m_setting . m_impulseClamp = mousePickClamping ;
//very weak constraint for picking
p2p - > m_setting . m_tau = 0.001f ;
}
}
else if ( psb )
{
2020-03-11 18:29:22 +00:00
int face_id = rayCallback . m_faceId ;
if ( face_id > = 0 & & face_id < psb - > m_faces . size ( ) )
{
m_pickedSoftBody = psb ;
psb - > setActivationState ( DISABLE_DEACTIVATION ) ;
const btSoftBody : : Face & f = psb - > m_faces [ face_id ] ;
2020-06-25 00:48:43 +00:00
btDeformableMousePickingForce * mouse_force = new btDeformableMousePickingForce ( m_pickingForceElasticStiffness , m_pickingForceDampingStiffness , f , m_hitPos , m_maxPickingForce ) ;
2020-03-11 18:29:22 +00:00
m_mouseForce = mouse_force ;
getDeformableDynamicsWorld ( ) - > addForce ( psb , mouse_force ) ;
}
2020-03-09 18:19:08 +00:00
}
else
{
btMultiBodyLinkCollider * multiCol = ( btMultiBodyLinkCollider * ) btMultiBodyLinkCollider : : upcast ( rayCallback . m_collisionObject ) ;
if ( multiCol & & multiCol - > m_multiBody )
{
m_prevCanSleep = multiCol - > m_multiBody - > getCanSleep ( ) ;
multiCol - > m_multiBody - > setCanSleep ( false ) ;
btVector3 pivotInA = multiCol - > m_multiBody - > worldPosToLocal ( multiCol - > m_link , pickPos ) ;
btMultiBodyPoint2Point * p2p = new btMultiBodyPoint2Point ( multiCol - > m_multiBody , multiCol - > m_link , 0 , pivotInA , pickPos ) ;
//if you add too much energy to the system, causing high angular velocities, simulation 'explodes'
//see also http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=4&t=949
//so we try to avoid it by clamping the maximum impulse (force) that the mouse pick can apply
//it is not satisfying, hopefully we find a better solution (higher order integrator, using joint friction using a zero-velocity target motor with limited force etc?)
btScalar scaling = 1 ;
p2p - > setMaxAppliedImpulse ( 2 * scaling ) ;
btMultiBodyDynamicsWorld * world = ( btMultiBodyDynamicsWorld * ) m_dynamicsWorld ;
world - > addMultiBodyConstraint ( p2p ) ;
m_pickingMultiBodyPoint2Point = p2p ;
}
}
}
return false ;
}
virtual bool movePickedBody ( const btVector3 & rayFromWorld , const btVector3 & rayToWorld )
{
if ( m_pickedBody & & m_pickedConstraint )
{
btPoint2PointConstraint * pickCon = static_cast < btPoint2PointConstraint * > ( m_pickedConstraint ) ;
if ( pickCon )
{
//keep it at the same picking distance
btVector3 newPivotB ;
btVector3 dir = rayToWorld - rayFromWorld ;
dir . normalize ( ) ;
dir * = m_oldPickingDist ;
newPivotB = rayFromWorld + dir ;
pickCon - > setPivotB ( newPivotB ) ;
return true ;
}
}
if ( m_pickingMultiBodyPoint2Point )
{
//keep it at the same picking distance
btVector3 dir = rayToWorld - rayFromWorld ;
dir . normalize ( ) ;
dir * = m_oldPickingDist ;
btVector3 newPivotB = rayFromWorld + dir ;
m_pickingMultiBodyPoint2Point - > setPivotInB ( newPivotB ) ;
}
if ( m_pickedSoftBody & & m_mouseForce )
{
btVector3 newPivot ;
btVector3 dir = rayToWorld - rayFromWorld ;
dir . normalize ( ) ;
dir * = m_oldPickingDist ;
newPivot = rayFromWorld + dir ;
m_mouseForce - > setMousePos ( newPivot ) ;
}
return false ;
}
virtual void removePickingConstraint ( )
{
if ( m_pickedConstraint )
{
m_dynamicsWorld - > removeConstraint ( m_pickedConstraint ) ;
if ( m_pickedBody )
{
m_pickedBody - > forceActivationState ( ACTIVE_TAG ) ;
m_pickedBody - > activate ( true ) ;
}
delete m_pickedConstraint ;
m_pickedConstraint = 0 ;
m_pickedBody = 0 ;
}
if ( m_pickingMultiBodyPoint2Point )
{
m_pickingMultiBodyPoint2Point - > getMultiBodyA ( ) - > setCanSleep ( m_prevCanSleep ) ;
btMultiBodyDynamicsWorld * world = ( btMultiBodyDynamicsWorld * ) m_dynamicsWorld ;
world - > removeMultiBodyConstraint ( m_pickingMultiBodyPoint2Point ) ;
delete m_pickingMultiBodyPoint2Point ;
m_pickingMultiBodyPoint2Point = 0 ;
}
if ( m_pickedSoftBody )
{
getDeformableDynamicsWorld ( ) - > removeForce ( m_pickedSoftBody , m_mouseForce ) ;
delete m_mouseForce ;
m_mouseForce = 0 ;
m_pickedSoftBody = 0 ;
}
}
} ;
# endif //COMMON_MULTI_BODY_SETUP_H