2022-03-17 23:20:34 +01:00
# ifndef _BT_SOFT_BODY_INTERNALS_H
# define _BT_SOFT_BODY_INTERNALS_H
2022-03-15 13:29:32 +01:00
/*
Bullet Continuous Collision Detection and Physics Library
Copyright ( c ) 2003 - 2006 Erwin Coumans https : //bulletphysics.org
This software is provided ' as - is ' , without any express or implied warranty .
In no event will the authors be held liable for any damages arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it freely ,
subject to the following restrictions :
1. The origin of this software must not be misrepresented ; you must not claim that you wrote the original software . If you use this software in a product , an acknowledgment in the product documentation would be appreciated but is not required .
2. Altered source versions must be plainly marked as such , and must not be misrepresented as being the original software .
3. This notice may not be removed or altered from any source distribution .
*/
///btSoftBody implementation by Nathanael Presson
2022-03-17 23:20:34 +01:00
2022-03-15 13:29:32 +01:00
# include "btSoftBody.h"
# include "LinearMath/btQuickprof.h"
# include "LinearMath/btPolarDecomposition.h"
# include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h"
# include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h"
# include "BulletCollision/CollisionShapes/btConvexInternalShape.h"
# include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h"
# include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
# include "BulletDynamics/Featherstone/btMultiBodyConstraint.h"
# include <string.h> //for memset
# include <cmath>
# include "poly34.h"
// Given a multibody link, a contact point and a contact direction, fill in the jacobian data needed to calculate the velocity change given an impulse in the contact direction
static SIMD_FORCE_INLINE void findJacobian ( const btMultiBodyLinkCollider * multibodyLinkCol ,
btMultiBodyJacobianData & jacobianData ,
const btVector3 & contact_point ,
const btVector3 & dir )
{
const int ndof = multibodyLinkCol - > m_multiBody - > getNumDofs ( ) + 6 ;
jacobianData . m_jacobians . resize ( ndof ) ;
jacobianData . m_deltaVelocitiesUnitImpulse . resize ( ndof ) ;
btScalar * jac = & jacobianData . m_jacobians [ 0 ] ;
multibodyLinkCol - > m_multiBody - > fillContactJacobianMultiDof ( multibodyLinkCol - > m_link , contact_point , dir , jac , jacobianData . scratch_r , jacobianData . scratch_v , jacobianData . scratch_m ) ;
multibodyLinkCol - > m_multiBody - > calcAccelerationDeltasMultiDof ( & jacobianData . m_jacobians [ 0 ] , & jacobianData . m_deltaVelocitiesUnitImpulse [ 0 ] , jacobianData . scratch_r , jacobianData . scratch_v ) ;
}
static SIMD_FORCE_INLINE btVector3 generateUnitOrthogonalVector ( const btVector3 & u )
{
btScalar ux = u . getX ( ) ;
btScalar uy = u . getY ( ) ;
btScalar uz = u . getZ ( ) ;
btScalar ax = std : : abs ( ux ) ;
btScalar ay = std : : abs ( uy ) ;
btScalar az = std : : abs ( uz ) ;
btVector3 v ;
if ( ax < = ay & & ax < = az )
v = btVector3 ( 0 , - uz , uy ) ;
else if ( ay < = ax & & ay < = az )
v = btVector3 ( - uz , 0 , ux ) ;
else
v = btVector3 ( - uy , ux , 0 ) ;
v . normalize ( ) ;
return v ;
}
static SIMD_FORCE_INLINE bool proximityTest ( const btVector3 & x1 , const btVector3 & x2 , const btVector3 & x3 , const btVector3 & x4 , const btVector3 & normal , const btScalar & mrg , btVector3 & bary )
{
btVector3 x43 = x4 - x3 ;
if ( std : : abs ( x43 . dot ( normal ) ) > mrg )
return false ;
btVector3 x13 = x1 - x3 ;
btVector3 x23 = x2 - x3 ;
btScalar a11 = x13 . length2 ( ) ;
btScalar a22 = x23 . length2 ( ) ;
btScalar a12 = x13 . dot ( x23 ) ;
btScalar b1 = x13 . dot ( x43 ) ;
btScalar b2 = x23 . dot ( x43 ) ;
btScalar det = a11 * a22 - a12 * a12 ;
if ( det < SIMD_EPSILON )
return false ;
btScalar w1 = ( b1 * a22 - b2 * a12 ) / det ;
btScalar w2 = ( b2 * a11 - b1 * a12 ) / det ;
btScalar w3 = 1 - w1 - w2 ;
btScalar delta = mrg / std : : sqrt ( 0.5 * std : : abs ( x13 . cross ( x23 ) . safeNorm ( ) ) ) ;
bary = btVector3 ( w1 , w2 , w3 ) ;
for ( int i = 0 ; i < 3 ; + + i )
{
if ( bary [ i ] < - delta | | bary [ i ] > 1 + delta )
return false ;
}
return true ;
}
static const int KDOP_COUNT = 13 ;
static btVector3 dop [ KDOP_COUNT ] = { btVector3 ( 1 , 0 , 0 ) ,
btVector3 ( 0 , 1 , 0 ) ,
btVector3 ( 0 , 0 , 1 ) ,
btVector3 ( 1 , 1 , 0 ) ,
btVector3 ( 1 , 0 , 1 ) ,
btVector3 ( 0 , 1 , 1 ) ,
btVector3 ( 1 , - 1 , 0 ) ,
btVector3 ( 1 , 0 , - 1 ) ,
btVector3 ( 0 , 1 , - 1 ) ,
btVector3 ( 1 , 1 , 1 ) ,
btVector3 ( 1 , - 1 , 1 ) ,
btVector3 ( 1 , 1 , - 1 ) ,
btVector3 ( 1 , - 1 , - 1 ) } ;
static inline int getSign ( const btVector3 & n , const btVector3 & x )
{
btScalar d = n . dot ( x ) ;
if ( d > SIMD_EPSILON )
return 1 ;
if ( d < - SIMD_EPSILON )
return - 1 ;
return 0 ;
}
static SIMD_FORCE_INLINE bool hasSeparatingPlane ( const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt )
{
btVector3 hex [ 6 ] = { face - > m_n [ 0 ] - > m_x - node - > m_x ,
face - > m_n [ 1 ] - > m_x - node - > m_x ,
face - > m_n [ 2 ] - > m_x - node - > m_x ,
face - > m_n [ 0 ] - > m_x + dt * face - > m_n [ 0 ] - > m_v - node - > m_x ,
face - > m_n [ 1 ] - > m_x + dt * face - > m_n [ 1 ] - > m_v - node - > m_x ,
face - > m_n [ 2 ] - > m_x + dt * face - > m_n [ 2 ] - > m_v - node - > m_x } ;
btVector3 segment = dt * node - > m_v ;
for ( int i = 0 ; i < KDOP_COUNT ; + + i )
{
int s = getSign ( dop [ i ] , segment ) ;
int j = 0 ;
for ( ; j < 6 ; + + j )
{
if ( getSign ( dop [ i ] , hex [ j ] ) = = s )
break ;
}
if ( j = = 6 )
return true ;
}
return false ;
}
static SIMD_FORCE_INLINE bool nearZero ( const btScalar & a )
{
return ( a > - SAFE_EPSILON & & a < SAFE_EPSILON ) ;
}
static SIMD_FORCE_INLINE bool sameSign ( const btScalar & a , const btScalar & b )
{
return ( nearZero ( a ) | | nearZero ( b ) | | ( a > SAFE_EPSILON & & b > SAFE_EPSILON ) | | ( a < - SAFE_EPSILON & & b < - SAFE_EPSILON ) ) ;
}
static SIMD_FORCE_INLINE bool diffSign ( const btScalar & a , const btScalar & b )
{
return ! sameSign ( a , b ) ;
}
inline btScalar evaluateBezier2 ( const btScalar & p0 , const btScalar & p1 , const btScalar & p2 , const btScalar & t , const btScalar & s )
{
btScalar s2 = s * s ;
btScalar t2 = t * t ;
return p0 * s2 + p1 * btScalar ( 2.0 ) * s * t + p2 * t2 ;
}
inline btScalar evaluateBezier ( const btScalar & p0 , const btScalar & p1 , const btScalar & p2 , const btScalar & p3 , const btScalar & t , const btScalar & s )
{
btScalar s2 = s * s ;
btScalar s3 = s2 * s ;
btScalar t2 = t * t ;
btScalar t3 = t2 * t ;
return p0 * s3 + p1 * btScalar ( 3.0 ) * s2 * t + p2 * btScalar ( 3.0 ) * s * t2 + p3 * t3 ;
}
static SIMD_FORCE_INLINE bool getSigns ( bool type_c , const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & t0 , const btScalar & t1 , btScalar & lt0 , btScalar & lt1 )
{
if ( sameSign ( t0 , t1 ) )
{
lt0 = t0 ;
lt1 = t0 ;
return true ;
}
if ( type_c | | diffSign ( k0 , k3 ) )
{
btScalar ft = evaluateBezier ( k0 , k1 , k2 , k3 , t0 , - t1 ) ;
if ( t0 < - 0 )
ft = - ft ;
if ( sameSign ( ft , k0 ) )
{
lt0 = t1 ;
lt1 = t1 ;
}
else
{
lt0 = t0 ;
lt1 = t0 ;
}
return true ;
}
if ( ! type_c )
{
btScalar ft = evaluateBezier ( k0 , k1 , k2 , k3 , t0 , - t1 ) ;
if ( t0 < - 0 )
ft = - ft ;
if ( diffSign ( ft , k0 ) )
{
lt0 = t0 ;
lt1 = t1 ;
return true ;
}
btScalar fk = evaluateBezier2 ( k1 - k0 , k2 - k1 , k3 - k2 , t0 , - t1 ) ;
if ( sameSign ( fk , k1 - k0 ) )
lt0 = lt1 = t1 ;
else
lt0 = lt1 = t0 ;
return true ;
}
return false ;
}
static SIMD_FORCE_INLINE void getBernsteinCoeff ( const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt , btScalar & k0 , btScalar & k1 , btScalar & k2 , btScalar & k3 )
{
const btVector3 & n0 = face - > m_n0 ;
const btVector3 & n1 = face - > m_n1 ;
btVector3 n_hat = n0 + n1 - face - > m_vn ;
btVector3 p0ma0 = node - > m_x - face - > m_n [ 0 ] - > m_x ;
btVector3 p1ma1 = node - > m_q - face - > m_n [ 0 ] - > m_q ;
k0 = ( p0ma0 ) . dot ( n0 ) * 3.0 ;
k1 = ( p0ma0 ) . dot ( n_hat ) + ( p1ma1 ) . dot ( n0 ) ;
k2 = ( p1ma1 ) . dot ( n_hat ) + ( p0ma0 ) . dot ( n1 ) ;
k3 = ( p1ma1 ) . dot ( n1 ) * 3.0 ;
}
static SIMD_FORCE_INLINE void polyDecomposition ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & j0 , const btScalar & j1 , const btScalar & j2 , btScalar & u0 , btScalar & u1 , btScalar & v0 , btScalar & v1 )
{
btScalar denom = 4.0 * ( j1 - j2 ) * ( j1 - j0 ) + ( j2 - j0 ) * ( j2 - j0 ) ;
u0 = ( 2.0 * ( j1 - j2 ) * ( 3.0 * k1 - 2.0 * k0 - k3 ) - ( j0 - j2 ) * ( 3.0 * k2 - 2.0 * k3 - k0 ) ) / denom ;
u1 = ( 2.0 * ( j1 - j0 ) * ( 3.0 * k2 - 2.0 * k3 - k0 ) - ( j2 - j0 ) * ( 3.0 * k1 - 2.0 * k0 - k3 ) ) / denom ;
v0 = k0 - u0 * j0 ;
v1 = k3 - u1 * j2 ;
}
static SIMD_FORCE_INLINE bool rootFindingLemma ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 )
{
btScalar u0 , u1 , v0 , v1 ;
btScalar j0 = 3.0 * ( k1 - k0 ) ;
btScalar j1 = 3.0 * ( k2 - k1 ) ;
btScalar j2 = 3.0 * ( k3 - k2 ) ;
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( sameSign ( v0 , v1 ) )
{
btScalar Ypa = j0 * ( 1.0 - v0 ) * ( 1.0 - v0 ) + 2.0 * j1 * v0 * ( 1.0 - v0 ) + j2 * v0 * v0 ; // Y'(v0)
if ( sameSign ( Ypa , j0 ) )
{
return ( diffSign ( k0 , v1 ) ) ;
}
}
return diffSign ( k0 , v0 ) ;
}
static SIMD_FORCE_INLINE void getJs ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btSoftBody : : Node * a , const btSoftBody : : Node * b , const btSoftBody : : Node * c , const btSoftBody : : Node * p , const btScalar & dt , btScalar & j0 , btScalar & j1 , btScalar & j2 )
{
const btVector3 & a0 = a - > m_x ;
const btVector3 & b0 = b - > m_x ;
const btVector3 & c0 = c - > m_x ;
const btVector3 & va = a - > m_v ;
const btVector3 & vb = b - > m_v ;
const btVector3 & vc = c - > m_v ;
const btVector3 a1 = a0 + dt * va ;
const btVector3 b1 = b0 + dt * vb ;
const btVector3 c1 = c0 + dt * vc ;
btVector3 n0 = ( b0 - a0 ) . cross ( c0 - a0 ) ;
btVector3 n1 = ( b1 - a1 ) . cross ( c1 - a1 ) ;
btVector3 n_hat = n0 + n1 - dt * dt * ( vb - va ) . cross ( vc - va ) ;
const btVector3 & p0 = p - > m_x ;
const btVector3 & vp = p - > m_v ;
btVector3 p1 = p0 + dt * vp ;
btVector3 m0 = ( b0 - p0 ) . cross ( c0 - p0 ) ;
btVector3 m1 = ( b1 - p1 ) . cross ( c1 - p1 ) ;
btVector3 m_hat = m0 + m1 - dt * dt * ( vb - vp ) . cross ( vc - vp ) ;
btScalar l0 = m0 . dot ( n0 ) ;
btScalar l1 = 0.25 * ( m0 . dot ( n_hat ) + m_hat . dot ( n0 ) ) ;
btScalar l2 = btScalar ( 1 ) / btScalar ( 6 ) * ( m0 . dot ( n1 ) + m_hat . dot ( n_hat ) + m1 . dot ( n0 ) ) ;
btScalar l3 = 0.25 * ( m_hat . dot ( n1 ) + m1 . dot ( n_hat ) ) ;
btScalar l4 = m1 . dot ( n1 ) ;
btScalar k1p = 0.25 * k0 + 0.75 * k1 ;
btScalar k2p = 0.5 * k1 + 0.5 * k2 ;
btScalar k3p = 0.75 * k2 + 0.25 * k3 ;
btScalar s0 = ( l1 * k0 - l0 * k1p ) * 4.0 ;
btScalar s1 = ( l2 * k0 - l0 * k2p ) * 2.0 ;
btScalar s2 = ( l3 * k0 - l0 * k3p ) * btScalar ( 4 ) / btScalar ( 3 ) ;
btScalar s3 = l4 * k0 - l0 * k3 ;
j0 = ( s1 * k0 - s0 * k1 ) * 3.0 ;
j1 = ( s2 * k0 - s0 * k2 ) * 1.5 ;
j2 = ( s3 * k0 - s0 * k3 ) ;
}
static SIMD_FORCE_INLINE bool signDetermination1Internal ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & u0 , const btScalar & u1 , const btScalar & v0 , const btScalar & v1 )
{
btScalar Yu0 = k0 * ( 1.0 - u0 ) * ( 1.0 - u0 ) * ( 1.0 - u0 ) + 3.0 * k1 * u0 * ( 1.0 - u0 ) * ( 1.0 - u0 ) + 3.0 * k2 * u0 * u0 * ( 1.0 - u0 ) + k3 * u0 * u0 * u0 ; // Y(u0)
btScalar Yv0 = k0 * ( 1.0 - v0 ) * ( 1.0 - v0 ) * ( 1.0 - v0 ) + 3.0 * k1 * v0 * ( 1.0 - v0 ) * ( 1.0 - v0 ) + 3.0 * k2 * v0 * v0 * ( 1.0 - v0 ) + k3 * v0 * v0 * v0 ; // Y(v0)
btScalar sign_Ytp = ( u0 > u1 ) ? Yu0 : - Yu0 ;
btScalar L = sameSign ( sign_Ytp , k0 ) ? u1 : u0 ;
sign_Ytp = ( v0 > v1 ) ? Yv0 : - Yv0 ;
btScalar K = ( sameSign ( sign_Ytp , k0 ) ) ? v1 : v0 ;
return diffSign ( L , K ) ;
}
static SIMD_FORCE_INLINE bool signDetermination2Internal ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & j0 , const btScalar & j1 , const btScalar & j2 , const btScalar & u0 , const btScalar & u1 , const btScalar & v0 , const btScalar & v1 )
{
btScalar Yu0 = k0 * ( 1.0 - u0 ) * ( 1.0 - u0 ) * ( 1.0 - u0 ) + 3.0 * k1 * u0 * ( 1.0 - u0 ) * ( 1.0 - u0 ) + 3.0 * k2 * u0 * u0 * ( 1.0 - u0 ) + k3 * u0 * u0 * u0 ; // Y(u0)
btScalar sign_Ytp = ( u0 > u1 ) ? Yu0 : - Yu0 , L1 , L2 ;
if ( diffSign ( sign_Ytp , k0 ) )
{
L1 = u0 ;
L2 = u1 ;
}
else
{
btScalar Yp_u0 = j0 * ( 1.0 - u0 ) * ( 1.0 - u0 ) + 2.0 * j1 * ( 1.0 - u0 ) * u0 + j2 * u0 * u0 ;
if ( sameSign ( Yp_u0 , j0 ) )
{
L1 = u1 ;
L2 = u1 ;
}
else
{
L1 = u0 ;
L2 = u0 ;
}
}
btScalar Yv0 = k0 * ( 1.0 - v0 ) * ( 1.0 - v0 ) * ( 1.0 - v0 ) + 3.0 * k1 * v0 * ( 1.0 - v0 ) * ( 1.0 - v0 ) + 3.0 * k2 * v0 * v0 * ( 1.0 - v0 ) + k3 * v0 * v0 * v0 ; // Y(uv0)
sign_Ytp = ( v0 > v1 ) ? Yv0 : - Yv0 ;
btScalar K1 , K2 ;
if ( diffSign ( sign_Ytp , k0 ) )
{
K1 = v0 ;
K2 = v1 ;
}
else
{
btScalar Yp_v0 = j0 * ( 1.0 - v0 ) * ( 1.0 - v0 ) + 2.0 * j1 * ( 1.0 - v0 ) * v0 + j2 * v0 * v0 ;
if ( sameSign ( Yp_v0 , j0 ) )
{
K1 = v1 ;
K2 = v1 ;
}
else
{
K1 = v0 ;
K2 = v0 ;
}
}
return ( diffSign ( K1 , L1 ) | | diffSign ( L2 , K2 ) ) ;
}
static SIMD_FORCE_INLINE bool signDetermination1 ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt )
{
btScalar j0 , j1 , j2 , u0 , u1 , v0 , v1 ;
// p1
getJs ( k0 , k1 , k2 , k3 , face - > m_n [ 0 ] , face - > m_n [ 1 ] , face - > m_n [ 2 ] , node , dt , j0 , j1 , j2 ) ;
if ( nearZero ( j0 + j2 - j1 * 2.0 ) )
{
btScalar lt0 , lt1 ;
getSigns ( true , k0 , k1 , k2 , k3 , j0 , j2 , lt0 , lt1 ) ;
if ( lt0 < - SAFE_EPSILON )
return false ;
}
else
{
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( ! signDetermination1Internal ( k0 , k1 , k2 , k3 , u0 , u1 , v0 , v1 ) )
return false ;
}
// p2
getJs ( k0 , k1 , k2 , k3 , face - > m_n [ 1 ] , face - > m_n [ 2 ] , face - > m_n [ 0 ] , node , dt , j0 , j1 , j2 ) ;
if ( nearZero ( j0 + j2 - j1 * 2.0 ) )
{
btScalar lt0 , lt1 ;
getSigns ( true , k0 , k1 , k2 , k3 , j0 , j2 , lt0 , lt1 ) ;
if ( lt0 < - SAFE_EPSILON )
return false ;
}
else
{
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( ! signDetermination1Internal ( k0 , k1 , k2 , k3 , u0 , u1 , v0 , v1 ) )
return false ;
}
// p3
getJs ( k0 , k1 , k2 , k3 , face - > m_n [ 2 ] , face - > m_n [ 0 ] , face - > m_n [ 1 ] , node , dt , j0 , j1 , j2 ) ;
if ( nearZero ( j0 + j2 - j1 * 2.0 ) )
{
btScalar lt0 , lt1 ;
getSigns ( true , k0 , k1 , k2 , k3 , j0 , j2 , lt0 , lt1 ) ;
if ( lt0 < - SAFE_EPSILON )
return false ;
}
else
{
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( ! signDetermination1Internal ( k0 , k1 , k2 , k3 , u0 , u1 , v0 , v1 ) )
return false ;
}
return true ;
}
static SIMD_FORCE_INLINE bool signDetermination2 ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt )
{
btScalar j0 , j1 , j2 , u0 , u1 , v0 , v1 ;
// p1
getJs ( k0 , k1 , k2 , k3 , face - > m_n [ 0 ] , face - > m_n [ 1 ] , face - > m_n [ 2 ] , node , dt , j0 , j1 , j2 ) ;
if ( nearZero ( j0 + j2 - j1 * 2.0 ) )
{
btScalar lt0 , lt1 ;
bool bt0 = true , bt1 = true ;
getSigns ( false , k0 , k1 , k2 , k3 , j0 , j2 , lt0 , lt1 ) ;
if ( lt0 < - SAFE_EPSILON )
bt0 = false ;
if ( lt1 < - SAFE_EPSILON )
bt1 = false ;
if ( ! bt0 & & ! bt1 )
return false ;
}
else
{
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( ! signDetermination2Internal ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) )
return false ;
}
// p2
getJs ( k0 , k1 , k2 , k3 , face - > m_n [ 1 ] , face - > m_n [ 2 ] , face - > m_n [ 0 ] , node , dt , j0 , j1 , j2 ) ;
if ( nearZero ( j0 + j2 - j1 * 2.0 ) )
{
btScalar lt0 , lt1 ;
bool bt0 = true , bt1 = true ;
getSigns ( false , k0 , k1 , k2 , k3 , j0 , j2 , lt0 , lt1 ) ;
if ( lt0 < - SAFE_EPSILON )
bt0 = false ;
if ( lt1 < - SAFE_EPSILON )
bt1 = false ;
if ( ! bt0 & & ! bt1 )
return false ;
}
else
{
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( ! signDetermination2Internal ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) )
return false ;
}
// p3
getJs ( k0 , k1 , k2 , k3 , face - > m_n [ 2 ] , face - > m_n [ 0 ] , face - > m_n [ 1 ] , node , dt , j0 , j1 , j2 ) ;
if ( nearZero ( j0 + j2 - j1 * 2.0 ) )
{
btScalar lt0 , lt1 ;
bool bt0 = true , bt1 = true ;
getSigns ( false , k0 , k1 , k2 , k3 , j0 , j2 , lt0 , lt1 ) ;
if ( lt0 < - SAFE_EPSILON )
bt0 = false ;
if ( lt1 < - SAFE_EPSILON )
bt1 = false ;
if ( ! bt0 & & ! bt1 )
return false ;
}
else
{
polyDecomposition ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) ;
if ( ! signDetermination2Internal ( k0 , k1 , k2 , k3 , j0 , j1 , j2 , u0 , u1 , v0 , v1 ) )
return false ;
}
return true ;
}
static SIMD_FORCE_INLINE bool coplanarAndInsideTest ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt )
{
// Coplanar test
if ( diffSign ( k1 - k0 , k3 - k2 ) )
{
// Case b:
if ( sameSign ( k0 , k3 ) & & ! rootFindingLemma ( k0 , k1 , k2 , k3 ) )
return false ;
// inside test
return signDetermination2 ( k0 , k1 , k2 , k3 , face , node , dt ) ;
}
else
{
// Case c:
if ( sameSign ( k0 , k3 ) )
return false ;
// inside test
return signDetermination1 ( k0 , k1 , k2 , k3 , face , node , dt ) ;
}
return false ;
}
static SIMD_FORCE_INLINE bool conservativeCulling ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & mrg )
{
if ( k0 > mrg & & k1 > mrg & & k2 > mrg & & k3 > mrg )
return true ;
if ( k0 < - mrg & & k1 < - mrg & & k2 < - mrg & & k3 < - mrg )
return true ;
return false ;
}
static SIMD_FORCE_INLINE bool bernsteinVFTest ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & mrg , const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt )
{
if ( conservativeCulling ( k0 , k1 , k2 , k3 , mrg ) )
return false ;
return coplanarAndInsideTest ( k0 , k1 , k2 , k3 , face , node , dt ) ;
}
static SIMD_FORCE_INLINE void deCasteljau ( const btScalar & k0 , const btScalar & k1 , const btScalar & k2 , const btScalar & k3 , const btScalar & t0 , btScalar & k10 , btScalar & k20 , btScalar & k30 , btScalar & k21 , btScalar & k12 )
{
k10 = k0 * ( 1.0 - t0 ) + k1 * t0 ;
btScalar k11 = k1 * ( 1.0 - t0 ) + k2 * t0 ;
k12 = k2 * ( 1.0 - t0 ) + k3 * t0 ;
k20 = k10 * ( 1.0 - t0 ) + k11 * t0 ;
k21 = k11 * ( 1.0 - t0 ) + k12 * t0 ;
k30 = k20 * ( 1.0 - t0 ) + k21 * t0 ;
}
static SIMD_FORCE_INLINE bool bernsteinVFTest ( const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt , const btScalar & mrg )
{
btScalar k0 , k1 , k2 , k3 ;
getBernsteinCoeff ( face , node , dt , k0 , k1 , k2 , k3 ) ;
if ( conservativeCulling ( k0 , k1 , k2 , k3 , mrg ) )
return false ;
return true ;
if ( diffSign ( k2 - 2.0 * k1 + k0 , k3 - 2.0 * k2 + k1 ) )
{
btScalar k10 , k20 , k30 , k21 , k12 ;
btScalar t0 = ( k2 - 2.0 * k1 + k0 ) / ( k0 - 3.0 * k1 + 3.0 * k2 - k3 ) ;
deCasteljau ( k0 , k1 , k2 , k3 , t0 , k10 , k20 , k30 , k21 , k12 ) ;
return bernsteinVFTest ( k0 , k10 , k20 , k30 , mrg , face , node , dt ) | | bernsteinVFTest ( k30 , k21 , k12 , k3 , mrg , face , node , dt ) ;
}
return coplanarAndInsideTest ( k0 , k1 , k2 , k3 , face , node , dt ) ;
}
static SIMD_FORCE_INLINE bool continuousCollisionDetection ( const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt , const btScalar & mrg , btVector3 & bary )
{
if ( hasSeparatingPlane ( face , node , dt ) )
return false ;
btVector3 x21 = face - > m_n [ 1 ] - > m_x - face - > m_n [ 0 ] - > m_x ;
btVector3 x31 = face - > m_n [ 2 ] - > m_x - face - > m_n [ 0 ] - > m_x ;
btVector3 x41 = node - > m_x - face - > m_n [ 0 ] - > m_x ;
btVector3 v21 = face - > m_n [ 1 ] - > m_v - face - > m_n [ 0 ] - > m_v ;
btVector3 v31 = face - > m_n [ 2 ] - > m_v - face - > m_n [ 0 ] - > m_v ;
btVector3 v41 = node - > m_v - face - > m_n [ 0 ] - > m_v ;
btVector3 a = x21 . cross ( x31 ) ;
btVector3 b = x21 . cross ( v31 ) + v21 . cross ( x31 ) ;
btVector3 c = v21 . cross ( v31 ) ;
btVector3 d = x41 ;
btVector3 e = v41 ;
btScalar a0 = a . dot ( d ) ;
btScalar a1 = a . dot ( e ) + b . dot ( d ) ;
btScalar a2 = c . dot ( d ) + b . dot ( e ) ;
btScalar a3 = c . dot ( e ) ;
btScalar eps = SAFE_EPSILON ;
int num_roots = 0 ;
btScalar roots [ 3 ] ;
if ( std : : abs ( a3 ) < eps )
{
// cubic term is zero
if ( std : : abs ( a2 ) < eps )
{
if ( std : : abs ( a1 ) < eps )
{
if ( std : : abs ( a0 ) < eps )
{
num_roots = 2 ;
roots [ 0 ] = 0 ;
roots [ 1 ] = dt ;
}
}
else
{
num_roots = 1 ;
roots [ 0 ] = - a0 / a1 ;
}
}
else
{
num_roots = SolveP2 ( roots , a1 / a2 , a0 / a2 ) ;
}
}
else
{
num_roots = SolveP3 ( roots , a2 / a3 , a1 / a3 , a0 / a3 ) ;
}
// std::sort(roots, roots+num_roots);
if ( num_roots > 1 )
{
if ( roots [ 0 ] > roots [ 1 ] )
btSwap ( roots [ 0 ] , roots [ 1 ] ) ;
}
if ( num_roots > 2 )
{
if ( roots [ 0 ] > roots [ 2 ] )
btSwap ( roots [ 0 ] , roots [ 2 ] ) ;
if ( roots [ 1 ] > roots [ 2 ] )
btSwap ( roots [ 1 ] , roots [ 2 ] ) ;
}
for ( int r = 0 ; r < num_roots ; + + r )
{
double root = roots [ r ] ;
if ( root < = 0 )
continue ;
if ( root > dt + SIMD_EPSILON )
return false ;
btVector3 x1 = face - > m_n [ 0 ] - > m_x + root * face - > m_n [ 0 ] - > m_v ;
btVector3 x2 = face - > m_n [ 1 ] - > m_x + root * face - > m_n [ 1 ] - > m_v ;
btVector3 x3 = face - > m_n [ 2 ] - > m_x + root * face - > m_n [ 2 ] - > m_v ;
btVector3 x4 = node - > m_x + root * node - > m_v ;
btVector3 normal = ( x2 - x1 ) . cross ( x3 - x1 ) ;
normal . safeNormalize ( ) ;
if ( proximityTest ( x1 , x2 , x3 , x4 , normal , mrg , bary ) )
return true ;
}
return false ;
}
static SIMD_FORCE_INLINE bool bernsteinCCD ( const btSoftBody : : Face * face , const btSoftBody : : Node * node , const btScalar & dt , const btScalar & mrg , btVector3 & bary )
{
if ( ! bernsteinVFTest ( face , node , dt , mrg ) )
return false ;
if ( ! continuousCollisionDetection ( face , node , dt , 1e-6 , bary ) )
return false ;
return true ;
}
//
// btSymMatrix
//
template < typename T >
struct btSymMatrix
{
btSymMatrix ( ) : dim ( 0 ) { }
btSymMatrix ( int n , const T & init = T ( ) ) { resize ( n , init ) ; }
void resize ( int n , const T & init = T ( ) )
{
dim = n ;
store . resize ( ( n * ( n + 1 ) ) / 2 , init ) ;
}
int index ( int c , int r ) const
{
if ( c > r ) btSwap ( c , r ) ;
btAssert ( r < dim ) ;
return ( ( r * ( r + 1 ) ) / 2 + c ) ;
}
T & operator ( ) ( int c , int r ) { return ( store [ index ( c , r ) ] ) ; }
const T & operator ( ) ( int c , int r ) const { return ( store [ index ( c , r ) ] ) ; }
btAlignedObjectArray < T > store ;
int dim ;
} ;
//
// btSoftBodyCollisionShape
//
class btSoftBodyCollisionShape : public btConcaveShape
{
public :
btSoftBody * m_body ;
btSoftBodyCollisionShape ( btSoftBody * backptr )
{
m_shapeType = SOFTBODY_SHAPE_PROXYTYPE ;
m_body = backptr ;
}
virtual ~ btSoftBodyCollisionShape ( )
{
}
void processAllTriangles ( btTriangleCallback * /*callback*/ , const btVector3 & /*aabbMin*/ , const btVector3 & /*aabbMax*/ ) const
{
//not yet
btAssert ( 0 ) ;
}
///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t.
virtual void getAabb ( const btTransform & t , btVector3 & aabbMin , btVector3 & aabbMax ) const
{
/* t is usually identity, except when colliding against btCompoundShape. See Issue 512 */
const btVector3 mins = m_body - > m_bounds [ 0 ] ;
const btVector3 maxs = m_body - > m_bounds [ 1 ] ;
const btVector3 crns [ ] = { t * btVector3 ( mins . x ( ) , mins . y ( ) , mins . z ( ) ) ,
t * btVector3 ( maxs . x ( ) , mins . y ( ) , mins . z ( ) ) ,
t * btVector3 ( maxs . x ( ) , maxs . y ( ) , mins . z ( ) ) ,
t * btVector3 ( mins . x ( ) , maxs . y ( ) , mins . z ( ) ) ,
t * btVector3 ( mins . x ( ) , mins . y ( ) , maxs . z ( ) ) ,
t * btVector3 ( maxs . x ( ) , mins . y ( ) , maxs . z ( ) ) ,
t * btVector3 ( maxs . x ( ) , maxs . y ( ) , maxs . z ( ) ) ,
t * btVector3 ( mins . x ( ) , maxs . y ( ) , maxs . z ( ) ) } ;
aabbMin = aabbMax = crns [ 0 ] ;
for ( int i = 1 ; i < 8 ; + + i )
{
aabbMin . setMin ( crns [ i ] ) ;
aabbMax . setMax ( crns [ i ] ) ;
}
}
virtual void setLocalScaling ( const btVector3 & /*scaling*/ )
{
///na
}
virtual const btVector3 & getLocalScaling ( ) const
{
static const btVector3 dummy ( 1 , 1 , 1 ) ;
return dummy ;
}
virtual void calculateLocalInertia ( btScalar /*mass*/ , btVector3 & /*inertia*/ ) const
{
///not yet
btAssert ( 0 ) ;
}
virtual const char * getName ( ) const
{
return " SoftBody " ;
}
} ;
//
// btSoftClusterCollisionShape
//
class btSoftClusterCollisionShape : public btConvexInternalShape
{
public :
const btSoftBody : : Cluster * m_cluster ;
btSoftClusterCollisionShape ( const btSoftBody : : Cluster * cluster ) : m_cluster ( cluster ) { setMargin ( 0 ) ; }
virtual btVector3 localGetSupportingVertex ( const btVector3 & vec ) const
{
btSoftBody : : Node * const * n = & m_cluster - > m_nodes [ 0 ] ;
btScalar d = btDot ( vec , n [ 0 ] - > m_x ) ;
int j = 0 ;
for ( int i = 1 , ni = m_cluster - > m_nodes . size ( ) ; i < ni ; + + i )
{
const btScalar k = btDot ( vec , n [ i ] - > m_x ) ;
if ( k > d )
{
d = k ;
j = i ;
}
}
return ( n [ j ] - > m_x ) ;
}
virtual btVector3 localGetSupportingVertexWithoutMargin ( const btVector3 & vec ) const
{
return ( localGetSupportingVertex ( vec ) ) ;
}
//notice that the vectors should be unit length
virtual void batchedUnitVectorGetSupportingVertexWithoutMargin ( const btVector3 * vectors , btVector3 * supportVerticesOut , int numVectors ) const
{
}
virtual void calculateLocalInertia ( btScalar mass , btVector3 & inertia ) const
{
}
virtual void getAabb ( const btTransform & t , btVector3 & aabbMin , btVector3 & aabbMax ) const
{
}
virtual int getShapeType ( ) const { return SOFTBODY_SHAPE_PROXYTYPE ; }
//debugging
virtual const char * getName ( ) const { return " SOFTCLUSTER " ; }
virtual void setMargin ( btScalar margin )
{
btConvexInternalShape : : setMargin ( margin ) ;
}
virtual btScalar getMargin ( ) const
{
return btConvexInternalShape : : getMargin ( ) ;
}
} ;
//
// Inline's
//
//
template < typename T >
static inline void ZeroInitialize ( T & value )
{
memset ( & value , 0 , sizeof ( T ) ) ;
}
//
template < typename T >
static inline bool CompLess ( const T & a , const T & b )
{
return ( a < b ) ;
}
//
template < typename T >
static inline bool CompGreater ( const T & a , const T & b )
{
return ( a > b ) ;
}
//
template < typename T >
static inline T Lerp ( const T & a , const T & b , btScalar t )
{
return ( a + ( b - a ) * t ) ;
}
//
template < typename T >
static inline T InvLerp ( const T & a , const T & b , btScalar t )
{
return ( ( b + a * t - b * t ) / ( a * b ) ) ;
}
//
static inline btMatrix3x3 Lerp ( const btMatrix3x3 & a ,
const btMatrix3x3 & b ,
btScalar t )
{
btMatrix3x3 r ;
r [ 0 ] = Lerp ( a [ 0 ] , b [ 0 ] , t ) ;
r [ 1 ] = Lerp ( a [ 1 ] , b [ 1 ] , t ) ;
r [ 2 ] = Lerp ( a [ 2 ] , b [ 2 ] , t ) ;
return ( r ) ;
}
//
static inline btVector3 Clamp ( const btVector3 & v , btScalar maxlength )
{
const btScalar sql = v . length2 ( ) ;
if ( sql > ( maxlength * maxlength ) )
return ( ( v * maxlength ) / btSqrt ( sql ) ) ;
else
return ( v ) ;
}
//
template < typename T >
static inline T Clamp ( const T & x , const T & l , const T & h )
{
return ( x < l ? l : x > h ? h : x ) ;
}
//
template < typename T >
static inline T Sq ( const T & x )
{
return ( x * x ) ;
}
//
template < typename T >
static inline T Cube ( const T & x )
{
return ( x * x * x ) ;
}
//
template < typename T >
static inline T Sign ( const T & x )
{
return ( ( T ) ( x < 0 ? - 1 : + 1 ) ) ;
}
//
template < typename T >
static inline bool SameSign ( const T & x , const T & y )
{
return ( ( x * y ) > 0 ) ;
}
//
static inline btScalar ClusterMetric ( const btVector3 & x , const btVector3 & y )
{
const btVector3 d = x - y ;
return ( btFabs ( d [ 0 ] ) + btFabs ( d [ 1 ] ) + btFabs ( d [ 2 ] ) ) ;
}
//
static inline btMatrix3x3 ScaleAlongAxis ( const btVector3 & a , btScalar s )
{
const btScalar xx = a . x ( ) * a . x ( ) ;
const btScalar yy = a . y ( ) * a . y ( ) ;
const btScalar zz = a . z ( ) * a . z ( ) ;
const btScalar xy = a . x ( ) * a . y ( ) ;
const btScalar yz = a . y ( ) * a . z ( ) ;
const btScalar zx = a . z ( ) * a . x ( ) ;
btMatrix3x3 m ;
m [ 0 ] = btVector3 ( 1 - xx + xx * s , xy * s - xy , zx * s - zx ) ;
m [ 1 ] = btVector3 ( xy * s - xy , 1 - yy + yy * s , yz * s - yz ) ;
m [ 2 ] = btVector3 ( zx * s - zx , yz * s - yz , 1 - zz + zz * s ) ;
return ( m ) ;
}
//
static inline btMatrix3x3 Cross ( const btVector3 & v )
{
btMatrix3x3 m ;
m [ 0 ] = btVector3 ( 0 , - v . z ( ) , + v . y ( ) ) ;
m [ 1 ] = btVector3 ( + v . z ( ) , 0 , - v . x ( ) ) ;
m [ 2 ] = btVector3 ( - v . y ( ) , + v . x ( ) , 0 ) ;
return ( m ) ;
}
//
static inline btMatrix3x3 Diagonal ( btScalar x )
{
btMatrix3x3 m ;
m [ 0 ] = btVector3 ( x , 0 , 0 ) ;
m [ 1 ] = btVector3 ( 0 , x , 0 ) ;
m [ 2 ] = btVector3 ( 0 , 0 , x ) ;
return ( m ) ;
}
static inline btMatrix3x3 Diagonal ( const btVector3 & v )
{
btMatrix3x3 m ;
m [ 0 ] = btVector3 ( v . getX ( ) , 0 , 0 ) ;
m [ 1 ] = btVector3 ( 0 , v . getY ( ) , 0 ) ;
m [ 2 ] = btVector3 ( 0 , 0 , v . getZ ( ) ) ;
return ( m ) ;
}
static inline btScalar Dot ( const btScalar * a , const btScalar * b , int ndof )
{
btScalar result = 0 ;
for ( int i = 0 ; i < ndof ; + + i )
result + = a [ i ] * b [ i ] ;
return result ;
}
static inline btMatrix3x3 OuterProduct ( const btScalar * v1 , const btScalar * v2 , const btScalar * v3 ,
const btScalar * u1 , const btScalar * u2 , const btScalar * u3 , int ndof )
{
btMatrix3x3 m ;
btScalar a11 = Dot ( v1 , u1 , ndof ) ;
btScalar a12 = Dot ( v1 , u2 , ndof ) ;
btScalar a13 = Dot ( v1 , u3 , ndof ) ;
btScalar a21 = Dot ( v2 , u1 , ndof ) ;
btScalar a22 = Dot ( v2 , u2 , ndof ) ;
btScalar a23 = Dot ( v2 , u3 , ndof ) ;
btScalar a31 = Dot ( v3 , u1 , ndof ) ;
btScalar a32 = Dot ( v3 , u2 , ndof ) ;
btScalar a33 = Dot ( v3 , u3 , ndof ) ;
m [ 0 ] = btVector3 ( a11 , a12 , a13 ) ;
m [ 1 ] = btVector3 ( a21 , a22 , a23 ) ;
m [ 2 ] = btVector3 ( a31 , a32 , a33 ) ;
return ( m ) ;
}
static inline btMatrix3x3 OuterProduct ( const btVector3 & v1 , const btVector3 & v2 )
{
btMatrix3x3 m ;
btScalar a11 = v1 [ 0 ] * v2 [ 0 ] ;
btScalar a12 = v1 [ 0 ] * v2 [ 1 ] ;
btScalar a13 = v1 [ 0 ] * v2 [ 2 ] ;
btScalar a21 = v1 [ 1 ] * v2 [ 0 ] ;
btScalar a22 = v1 [ 1 ] * v2 [ 1 ] ;
btScalar a23 = v1 [ 1 ] * v2 [ 2 ] ;
btScalar a31 = v1 [ 2 ] * v2 [ 0 ] ;
btScalar a32 = v1 [ 2 ] * v2 [ 1 ] ;
btScalar a33 = v1 [ 2 ] * v2 [ 2 ] ;
m [ 0 ] = btVector3 ( a11 , a12 , a13 ) ;
m [ 1 ] = btVector3 ( a21 , a22 , a23 ) ;
m [ 2 ] = btVector3 ( a31 , a32 , a33 ) ;
return ( m ) ;
}
//
static inline btMatrix3x3 Add ( const btMatrix3x3 & a ,
const btMatrix3x3 & b )
{
btMatrix3x3 r ;
for ( int i = 0 ; i < 3 ; + + i ) r [ i ] = a [ i ] + b [ i ] ;
return ( r ) ;
}
//
static inline btMatrix3x3 Sub ( const btMatrix3x3 & a ,
const btMatrix3x3 & b )
{
btMatrix3x3 r ;
for ( int i = 0 ; i < 3 ; + + i ) r [ i ] = a [ i ] - b [ i ] ;
return ( r ) ;
}
//
static inline btMatrix3x3 Mul ( const btMatrix3x3 & a ,
btScalar b )
{
btMatrix3x3 r ;
for ( int i = 0 ; i < 3 ; + + i ) r [ i ] = a [ i ] * b ;
return ( r ) ;
}
//
static inline void Orthogonalize ( btMatrix3x3 & m )
{
m [ 2 ] = btCross ( m [ 0 ] , m [ 1 ] ) . normalized ( ) ;
m [ 1 ] = btCross ( m [ 2 ] , m [ 0 ] ) . normalized ( ) ;
m [ 0 ] = btCross ( m [ 1 ] , m [ 2 ] ) . normalized ( ) ;
}
//
static inline btMatrix3x3 MassMatrix ( btScalar im , const btMatrix3x3 & iwi , const btVector3 & r )
{
const btMatrix3x3 cr = Cross ( r ) ;
return ( Sub ( Diagonal ( im ) , cr * iwi * cr ) ) ;
}
//
static inline btMatrix3x3 ImpulseMatrix ( btScalar dt ,
btScalar ima ,
btScalar imb ,
const btMatrix3x3 & iwi ,
const btVector3 & r )
{
return ( Diagonal ( 1 / dt ) * Add ( Diagonal ( ima ) , MassMatrix ( imb , iwi , r ) ) . inverse ( ) ) ;
}
//
static inline btMatrix3x3 ImpulseMatrix ( btScalar dt ,
const btMatrix3x3 & effective_mass_inv ,
btScalar imb ,
const btMatrix3x3 & iwi ,
const btVector3 & r )
{
return ( Diagonal ( 1 / dt ) * Add ( effective_mass_inv , MassMatrix ( imb , iwi , r ) ) . inverse ( ) ) ;
// btMatrix3x3 iimb = MassMatrix(imb, iwi, r);
// if (iimb.determinant() == 0)
// return effective_mass_inv.inverse();
// return effective_mass_inv.inverse() * Add(effective_mass_inv.inverse(), iimb.inverse()).inverse() * iimb.inverse();
}
//
static inline btMatrix3x3 ImpulseMatrix ( btScalar ima , const btMatrix3x3 & iia , const btVector3 & ra ,
btScalar imb , const btMatrix3x3 & iib , const btVector3 & rb )
{
return ( Add ( MassMatrix ( ima , iia , ra ) , MassMatrix ( imb , iib , rb ) ) . inverse ( ) ) ;
}
//
static inline btMatrix3x3 AngularImpulseMatrix ( const btMatrix3x3 & iia ,
const btMatrix3x3 & iib )
{
return ( Add ( iia , iib ) . inverse ( ) ) ;
}
//
static inline btVector3 ProjectOnAxis ( const btVector3 & v ,
const btVector3 & a )
{
return ( a * btDot ( v , a ) ) ;
}
//
static inline btVector3 ProjectOnPlane ( const btVector3 & v ,
const btVector3 & a )
{
return ( v - ProjectOnAxis ( v , a ) ) ;
}
//
static inline void ProjectOrigin ( const btVector3 & a ,
const btVector3 & b ,
btVector3 & prj ,
btScalar & sqd )
{
const btVector3 d = b - a ;
const btScalar m2 = d . length2 ( ) ;
if ( m2 > SIMD_EPSILON )
{
const btScalar t = Clamp < btScalar > ( - btDot ( a , d ) / m2 , 0 , 1 ) ;
const btVector3 p = a + d * t ;
const btScalar l2 = p . length2 ( ) ;
if ( l2 < sqd )
{
prj = p ;
sqd = l2 ;
}
}
}
//
static inline void ProjectOrigin ( const btVector3 & a ,
const btVector3 & b ,
const btVector3 & c ,
btVector3 & prj ,
btScalar & sqd )
{
const btVector3 & q = btCross ( b - a , c - a ) ;
const btScalar m2 = q . length2 ( ) ;
if ( m2 > SIMD_EPSILON )
{
const btVector3 n = q / btSqrt ( m2 ) ;
const btScalar k = btDot ( a , n ) ;
const btScalar k2 = k * k ;
if ( k2 < sqd )
{
const btVector3 p = n * k ;
if ( ( btDot ( btCross ( a - p , b - p ) , q ) > 0 ) & &
( btDot ( btCross ( b - p , c - p ) , q ) > 0 ) & &
( btDot ( btCross ( c - p , a - p ) , q ) > 0 ) )
{
prj = p ;
sqd = k2 ;
}
else
{
ProjectOrigin ( a , b , prj , sqd ) ;
ProjectOrigin ( b , c , prj , sqd ) ;
ProjectOrigin ( c , a , prj , sqd ) ;
}
}
}
}
//
static inline bool rayIntersectsTriangle ( const btVector3 & origin , const btVector3 & dir , const btVector3 & v0 , const btVector3 & v1 , const btVector3 & v2 , btScalar & t )
{
btScalar a , f , u , v ;
btVector3 e1 = v1 - v0 ;
btVector3 e2 = v2 - v0 ;
btVector3 h = dir . cross ( e2 ) ;
a = e1 . dot ( h ) ;
if ( a > - 0.00001 & & a < 0.00001 )
return ( false ) ;
f = btScalar ( 1 ) / a ;
btVector3 s = origin - v0 ;
u = f * s . dot ( h ) ;
if ( u < 0.0 | | u > 1.0 )
return ( false ) ;
btVector3 q = s . cross ( e1 ) ;
v = f * dir . dot ( q ) ;
if ( v < 0.0 | | u + v > 1.0 )
return ( false ) ;
// at this stage we can compute t to find out where
// the intersection point is on the line
t = f * e2 . dot ( q ) ;
if ( t > 0 ) // ray intersection
return ( true ) ;
else // this means that there is a line intersection
// but not a ray intersection
return ( false ) ;
}
static inline bool lineIntersectsTriangle ( const btVector3 & rayStart , const btVector3 & rayEnd , const btVector3 & p1 , const btVector3 & p2 , const btVector3 & p3 , btVector3 & sect , btVector3 & normal )
{
btVector3 dir = rayEnd - rayStart ;
btScalar dir_norm = dir . norm ( ) ;
if ( dir_norm < SIMD_EPSILON )
return false ;
dir . normalize ( ) ;
btScalar t ;
bool ret = rayIntersectsTriangle ( rayStart , dir , p1 , p2 , p3 , t ) ;
if ( ret )
{
if ( t < = dir_norm )
{
sect = rayStart + dir * t ;
}
else
{
ret = false ;
}
}
if ( ret )
{
btVector3 n = ( p3 - p1 ) . cross ( p2 - p1 ) ;
n . safeNormalize ( ) ;
if ( n . dot ( dir ) < 0 )
normal = n ;
else
normal = - n ;
}
return ret ;
}
//
template < typename T >
static inline T BaryEval ( const T & a ,
const T & b ,
const T & c ,
const btVector3 & coord )
{
return ( a * coord . x ( ) + b * coord . y ( ) + c * coord . z ( ) ) ;
}
//
static inline btVector3 BaryCoord ( const btVector3 & a ,
const btVector3 & b ,
const btVector3 & c ,
const btVector3 & p )
{
const btScalar w [ ] = { btCross ( a - p , b - p ) . length ( ) ,
btCross ( b - p , c - p ) . length ( ) ,
btCross ( c - p , a - p ) . length ( ) } ;
const btScalar isum = 1 / ( w [ 0 ] + w [ 1 ] + w [ 2 ] ) ;
return ( btVector3 ( w [ 1 ] * isum , w [ 2 ] * isum , w [ 0 ] * isum ) ) ;
}
//
inline static btScalar ImplicitSolve ( btSoftBody : : ImplicitFn * fn ,
const btVector3 & a ,
const btVector3 & b ,
const btScalar accuracy ,
const int maxiterations = 256 )
{
btScalar span [ 2 ] = { 0 , 1 } ;
btScalar values [ 2 ] = { fn - > Eval ( a ) , fn - > Eval ( b ) } ;
if ( values [ 0 ] > values [ 1 ] )
{
btSwap ( span [ 0 ] , span [ 1 ] ) ;
btSwap ( values [ 0 ] , values [ 1 ] ) ;
}
if ( values [ 0 ] > - accuracy ) return ( - 1 ) ;
if ( values [ 1 ] < + accuracy ) return ( - 1 ) ;
for ( int i = 0 ; i < maxiterations ; + + i )
{
const btScalar t = Lerp ( span [ 0 ] , span [ 1 ] , values [ 0 ] / ( values [ 0 ] - values [ 1 ] ) ) ;
const btScalar v = fn - > Eval ( Lerp ( a , b , t ) ) ;
if ( ( t < = 0 ) | | ( t > = 1 ) ) break ;
if ( btFabs ( v ) < accuracy ) return ( t ) ;
if ( v < 0 )
{
span [ 0 ] = t ;
values [ 0 ] = v ;
}
else
{
span [ 1 ] = t ;
values [ 1 ] = v ;
}
}
return ( - 1 ) ;
}
inline static void EvaluateMedium ( const btSoftBodyWorldInfo * wfi ,
const btVector3 & x ,
btSoftBody : : sMedium & medium )
{
medium . m_velocity = btVector3 ( 0 , 0 , 0 ) ;
medium . m_pressure = 0 ;
medium . m_density = wfi - > air_density ;
if ( wfi - > water_density > 0 )
{
const btScalar depth = - ( btDot ( x , wfi - > water_normal ) + wfi - > water_offset ) ;
if ( depth > 0 )
{
medium . m_density = wfi - > water_density ;
medium . m_pressure = depth * wfi - > water_density * wfi - > m_gravity . length ( ) ;
}
}
}
//
static inline btVector3 NormalizeAny ( const btVector3 & v )
{
const btScalar l = v . length ( ) ;
if ( l > SIMD_EPSILON )
return ( v / l ) ;
else
return ( btVector3 ( 0 , 0 , 0 ) ) ;
}
//
static inline btDbvtVolume VolumeOf ( const btSoftBody : : Face & f ,
btScalar margin )
{
const btVector3 * pts [ ] = { & f . m_n [ 0 ] - > m_x ,
& f . m_n [ 1 ] - > m_x ,
& f . m_n [ 2 ] - > m_x } ;
btDbvtVolume vol = btDbvtVolume : : FromPoints ( pts , 3 ) ;
vol . Expand ( btVector3 ( margin , margin , margin ) ) ;
return ( vol ) ;
}
//
static inline btVector3 CenterOf ( const btSoftBody : : Face & f )
{
return ( ( f . m_n [ 0 ] - > m_x + f . m_n [ 1 ] - > m_x + f . m_n [ 2 ] - > m_x ) / 3 ) ;
}
//
static inline btScalar AreaOf ( const btVector3 & x0 ,
const btVector3 & x1 ,
const btVector3 & x2 )
{
const btVector3 a = x1 - x0 ;
const btVector3 b = x2 - x0 ;
const btVector3 cr = btCross ( a , b ) ;
const btScalar area = cr . length ( ) ;
return ( area ) ;
}
//
static inline btScalar VolumeOf ( const btVector3 & x0 ,
const btVector3 & x1 ,
const btVector3 & x2 ,
const btVector3 & x3 )
{
const btVector3 a = x1 - x0 ;
const btVector3 b = x2 - x0 ;
const btVector3 c = x3 - x0 ;
return ( btDot ( a , btCross ( b , c ) ) ) ;
}
//
//
static inline void ApplyClampedForce ( btSoftBody : : Node & n ,
const btVector3 & f ,
btScalar dt )
{
const btScalar dtim = dt * n . m_im ;
if ( ( f * dtim ) . length2 ( ) > n . m_v . length2 ( ) )
{ /* Clamp */
n . m_f - = ProjectOnAxis ( n . m_v , f . normalized ( ) ) / dtim ;
}
else
{ /* Apply */
n . m_f + = f ;
}
}
//
static inline int MatchEdge ( const btSoftBody : : Node * a ,
const btSoftBody : : Node * b ,
const btSoftBody : : Node * ma ,
const btSoftBody : : Node * mb )
{
if ( ( a = = ma ) & & ( b = = mb ) ) return ( 0 ) ;
if ( ( a = = mb ) & & ( b = = ma ) ) return ( 1 ) ;
return ( - 1 ) ;
}
//
// btEigen : Extract eigen system,
// straitforward implementation of http://math.fullerton.edu/mathews/n2003/JacobiMethodMod.html
// outputs are NOT sorted.
//
struct btEigen
{
static int system ( btMatrix3x3 & a , btMatrix3x3 * vectors , btVector3 * values = 0 )
{
static const int maxiterations = 16 ;
static const btScalar accuracy = ( btScalar ) 0.0001 ;
btMatrix3x3 & v = * vectors ;
int iterations = 0 ;
vectors - > setIdentity ( ) ;
do
{
int p = 0 , q = 1 ;
if ( btFabs ( a [ p ] [ q ] ) < btFabs ( a [ 0 ] [ 2 ] ) )
{
p = 0 ;
q = 2 ;
}
if ( btFabs ( a [ p ] [ q ] ) < btFabs ( a [ 1 ] [ 2 ] ) )
{
p = 1 ;
q = 2 ;
}
if ( btFabs ( a [ p ] [ q ] ) > accuracy )
{
const btScalar w = ( a [ q ] [ q ] - a [ p ] [ p ] ) / ( 2 * a [ p ] [ q ] ) ;
const btScalar z = btFabs ( w ) ;
const btScalar t = w / ( z * ( btSqrt ( 1 + w * w ) + z ) ) ;
if ( t = = t ) /* [WARNING] let hope that one does not get thrown aways by some compilers... */
{
const btScalar c = 1 / btSqrt ( t * t + 1 ) ;
const btScalar s = c * t ;
mulPQ ( a , c , s , p , q ) ;
mulTPQ ( a , c , s , p , q ) ;
mulPQ ( v , c , s , p , q ) ;
}
else
break ;
}
else
break ;
} while ( ( + + iterations ) < maxiterations ) ;
if ( values )
{
* values = btVector3 ( a [ 0 ] [ 0 ] , a [ 1 ] [ 1 ] , a [ 2 ] [ 2 ] ) ;
}
return ( iterations ) ;
}
private :
static inline void mulTPQ ( btMatrix3x3 & a , btScalar c , btScalar s , int p , int q )
{
const btScalar m [ 2 ] [ 3 ] = { { a [ p ] [ 0 ] , a [ p ] [ 1 ] , a [ p ] [ 2 ] } ,
{ a [ q ] [ 0 ] , a [ q ] [ 1 ] , a [ q ] [ 2 ] } } ;
int i ;
for ( i = 0 ; i < 3 ; + + i ) a [ p ] [ i ] = c * m [ 0 ] [ i ] - s * m [ 1 ] [ i ] ;
for ( i = 0 ; i < 3 ; + + i ) a [ q ] [ i ] = c * m [ 1 ] [ i ] + s * m [ 0 ] [ i ] ;
}
static inline void mulPQ ( btMatrix3x3 & a , btScalar c , btScalar s , int p , int q )
{
const btScalar m [ 2 ] [ 3 ] = { { a [ 0 ] [ p ] , a [ 1 ] [ p ] , a [ 2 ] [ p ] } ,
{ a [ 0 ] [ q ] , a [ 1 ] [ q ] , a [ 2 ] [ q ] } } ;
int i ;
for ( i = 0 ; i < 3 ; + + i ) a [ i ] [ p ] = c * m [ 0 ] [ i ] - s * m [ 1 ] [ i ] ;
for ( i = 0 ; i < 3 ; + + i ) a [ i ] [ q ] = c * m [ 1 ] [ i ] + s * m [ 0 ] [ i ] ;
}
} ;
//
// Polar decomposition,
// "Computing the Polar Decomposition with Applications", Nicholas J. Higham, 1986.
//
static inline int PolarDecompose ( const btMatrix3x3 & m , btMatrix3x3 & q , btMatrix3x3 & s )
{
static const btPolarDecomposition polar ;
return polar . decompose ( m , q , s ) ;
}
//
// btSoftColliders
//
struct btSoftColliders
{
//
// ClusterBase
//
struct ClusterBase : btDbvt : : ICollide
{
btScalar erp ;
btScalar idt ;
btScalar m_margin ;
btScalar friction ;
btScalar threshold ;
ClusterBase ( )
{
erp = ( btScalar ) 1 ;
idt = 0 ;
m_margin = 0 ;
friction = 0 ;
threshold = ( btScalar ) 0 ;
}
bool SolveContact ( const btGjkEpaSolver2 : : sResults & res ,
btSoftBody : : Body ba , const btSoftBody : : Body bb ,
btSoftBody : : CJoint & joint )
{
if ( res . distance < m_margin )
{
btVector3 norm = res . normal ;
norm . normalize ( ) ; //is it necessary?
const btVector3 ra = res . witnesses [ 0 ] - ba . xform ( ) . getOrigin ( ) ;
const btVector3 rb = res . witnesses [ 1 ] - bb . xform ( ) . getOrigin ( ) ;
const btVector3 va = ba . velocity ( ra ) ;
const btVector3 vb = bb . velocity ( rb ) ;
const btVector3 vrel = va - vb ;
const btScalar rvac = btDot ( vrel , norm ) ;
btScalar depth = res . distance - m_margin ;
// printf("depth=%f\n",depth);
const btVector3 iv = norm * rvac ;
const btVector3 fv = vrel - iv ;
joint . m_bodies [ 0 ] = ba ;
joint . m_bodies [ 1 ] = bb ;
joint . m_refs [ 0 ] = ra * ba . xform ( ) . getBasis ( ) ;
joint . m_refs [ 1 ] = rb * bb . xform ( ) . getBasis ( ) ;
joint . m_rpos [ 0 ] = ra ;
joint . m_rpos [ 1 ] = rb ;
joint . m_cfm = 1 ;
joint . m_erp = 1 ;
joint . m_life = 0 ;
joint . m_maxlife = 0 ;
joint . m_split = 1 ;
joint . m_drift = depth * norm ;
joint . m_normal = norm ;
// printf("normal=%f,%f,%f\n",res.normal.getX(),res.normal.getY(),res.normal.getZ());
joint . m_delete = false ;
joint . m_friction = fv . length2 ( ) < ( rvac * friction * rvac * friction ) ? 1 : friction ;
joint . m_massmatrix = ImpulseMatrix ( ba . invMass ( ) , ba . invWorldInertia ( ) , joint . m_rpos [ 0 ] ,
bb . invMass ( ) , bb . invWorldInertia ( ) , joint . m_rpos [ 1 ] ) ;
return ( true ) ;
}
return ( false ) ;
}
} ;
//
// CollideCL_RS
//
struct CollideCL_RS : ClusterBase
{
btSoftBody * psb ;
const btCollisionObjectWrapper * m_colObjWrap ;
void Process ( const btDbvtNode * leaf )
{
btSoftBody : : Cluster * cluster = ( btSoftBody : : Cluster * ) leaf - > data ;
btSoftClusterCollisionShape cshape ( cluster ) ;
const btConvexShape * rshape = ( const btConvexShape * ) m_colObjWrap - > getCollisionShape ( ) ;
///don't collide an anchored cluster with a static/kinematic object
if ( m_colObjWrap - > getCollisionObject ( ) - > isStaticOrKinematicObject ( ) & & cluster - > m_containsAnchor )
return ;
btGjkEpaSolver2 : : sResults res ;
if ( btGjkEpaSolver2 : : SignedDistance ( & cshape , btTransform : : getIdentity ( ) ,
rshape , m_colObjWrap - > getWorldTransform ( ) ,
btVector3 ( 1 , 0 , 0 ) , res ) )
{
btSoftBody : : CJoint joint ;
if ( SolveContact ( res , cluster , m_colObjWrap - > getCollisionObject ( ) , joint ) ) //prb,joint))
{
btSoftBody : : CJoint * pj = new ( btAlignedAlloc ( sizeof ( btSoftBody : : CJoint ) , 16 ) ) btSoftBody : : CJoint ( ) ;
* pj = joint ;
psb - > m_joints . push_back ( pj ) ;
if ( m_colObjWrap - > getCollisionObject ( ) - > isStaticOrKinematicObject ( ) )
{
pj - > m_erp * = psb - > m_cfg . kSKHR_CL ;
pj - > m_split * = psb - > m_cfg . kSK_SPLT_CL ;
}
else
{
pj - > m_erp * = psb - > m_cfg . kSRHR_CL ;
pj - > m_split * = psb - > m_cfg . kSR_SPLT_CL ;
}
}
}
}
void ProcessColObj ( btSoftBody * ps , const btCollisionObjectWrapper * colObWrap )
{
psb = ps ;
m_colObjWrap = colObWrap ;
idt = ps - > m_sst . isdt ;
m_margin = m_colObjWrap - > getCollisionShape ( ) - > getMargin ( ) + psb - > getCollisionShape ( ) - > getMargin ( ) ;
///Bullet rigid body uses multiply instead of minimum to determine combined friction. Some customization would be useful.
friction = btMin ( psb - > m_cfg . kDF , m_colObjWrap - > getCollisionObject ( ) - > getFriction ( ) ) ;
btVector3 mins ;
btVector3 maxs ;
ATTRIBUTE_ALIGNED16 ( btDbvtVolume )
volume ;
colObWrap - > getCollisionShape ( ) - > getAabb ( colObWrap - > getWorldTransform ( ) , mins , maxs ) ;
volume = btDbvtVolume : : FromMM ( mins , maxs ) ;
volume . Expand ( btVector3 ( 1 , 1 , 1 ) * m_margin ) ;
ps - > m_cdbvt . collideTV ( ps - > m_cdbvt . m_root , volume , * this ) ;
}
} ;
//
// CollideCL_SS
//
struct CollideCL_SS : ClusterBase
{
btSoftBody * bodies [ 2 ] ;
void Process ( const btDbvtNode * la , const btDbvtNode * lb )
{
btSoftBody : : Cluster * cla = ( btSoftBody : : Cluster * ) la - > data ;
btSoftBody : : Cluster * clb = ( btSoftBody : : Cluster * ) lb - > data ;
bool connected = false ;
if ( ( bodies [ 0 ] = = bodies [ 1 ] ) & & ( bodies [ 0 ] - > m_clusterConnectivity . size ( ) ) )
{
connected = bodies [ 0 ] - > m_clusterConnectivity [ cla - > m_clusterIndex + bodies [ 0 ] - > m_clusters . size ( ) * clb - > m_clusterIndex ] ;
}
if ( ! connected )
{
btSoftClusterCollisionShape csa ( cla ) ;
btSoftClusterCollisionShape csb ( clb ) ;
btGjkEpaSolver2 : : sResults res ;
if ( btGjkEpaSolver2 : : SignedDistance ( & csa , btTransform : : getIdentity ( ) ,
& csb , btTransform : : getIdentity ( ) ,
cla - > m_com - clb - > m_com , res ) )
{
btSoftBody : : CJoint joint ;
if ( SolveContact ( res , cla , clb , joint ) )
{
btSoftBody : : CJoint * pj = new ( btAlignedAlloc ( sizeof ( btSoftBody : : CJoint ) , 16 ) ) btSoftBody : : CJoint ( ) ;
* pj = joint ;
bodies [ 0 ] - > m_joints . push_back ( pj ) ;
pj - > m_erp * = btMax ( bodies [ 0 ] - > m_cfg . kSSHR_CL , bodies [ 1 ] - > m_cfg . kSSHR_CL ) ;
pj - > m_split * = ( bodies [ 0 ] - > m_cfg . kSS_SPLT_CL + bodies [ 1 ] - > m_cfg . kSS_SPLT_CL ) / 2 ;
}
}
}
else
{
static int count = 0 ;
count + + ;
//printf("count=%d\n",count);
}
}
void ProcessSoftSoft ( btSoftBody * psa , btSoftBody * psb )
{
idt = psa - > m_sst . isdt ;
//m_margin = (psa->getCollisionShape()->getMargin()+psb->getCollisionShape()->getMargin())/2;
m_margin = ( psa - > getCollisionShape ( ) - > getMargin ( ) + psb - > getCollisionShape ( ) - > getMargin ( ) ) ;
friction = btMin ( psa - > m_cfg . kDF , psb - > m_cfg . kDF ) ;
bodies [ 0 ] = psa ;
bodies [ 1 ] = psb ;
psa - > m_cdbvt . collideTT ( psa - > m_cdbvt . m_root , psb - > m_cdbvt . m_root , * this ) ;
}
} ;
//
// CollideSDF_RS
//
struct CollideSDF_RS : btDbvt : : ICollide
{
void Process ( const btDbvtNode * leaf )
{
btSoftBody : : Node * node = ( btSoftBody : : Node * ) leaf - > data ;
DoNode ( * node ) ;
}
void DoNode ( btSoftBody : : Node & n ) const
{
const btScalar m = n . m_im > 0 ? dynmargin : stamargin ;
btSoftBody : : RContact c ;
if ( ( ! n . m_battach ) & &
psb - > checkContact ( m_colObj1Wrap , n . m_x , m , c . m_cti ) )
{
const btScalar ima = n . m_im ;
const btScalar imb = m_rigidBody ? m_rigidBody - > getInvMass ( ) : 0.f ;
const btScalar ms = ima + imb ;
if ( ms > 0 )
{
const btTransform & wtr = m_rigidBody ? m_rigidBody - > getWorldTransform ( ) : m_colObj1Wrap - > getCollisionObject ( ) - > getWorldTransform ( ) ;
static const btMatrix3x3 iwiStatic ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
const btMatrix3x3 & iwi = m_rigidBody ? m_rigidBody - > getInvInertiaTensorWorld ( ) : iwiStatic ;
const btVector3 ra = n . m_x - wtr . getOrigin ( ) ;
const btVector3 va = m_rigidBody ? m_rigidBody - > getVelocityInLocalPoint ( ra ) * psb - > m_sst . sdt : btVector3 ( 0 , 0 , 0 ) ;
const btVector3 vb = n . m_x - n . m_q ;
const btVector3 vr = vb - va ;
const btScalar dn = btDot ( vr , c . m_cti . m_normal ) ;
const btVector3 fv = vr - c . m_cti . m_normal * dn ;
const btScalar fc = psb - > m_cfg . kDF * m_colObj1Wrap - > getCollisionObject ( ) - > getFriction ( ) ;
c . m_node = & n ;
c . m_c0 = ImpulseMatrix ( psb - > m_sst . sdt , ima , imb , iwi , ra ) ;
c . m_c1 = ra ;
c . m_c2 = ima * psb - > m_sst . sdt ;
c . m_c3 = fv . length2 ( ) < ( dn * fc * dn * fc ) ? 0 : 1 - fc ;
c . m_c4 = m_colObj1Wrap - > getCollisionObject ( ) - > isStaticOrKinematicObject ( ) ? psb - > m_cfg . kKHR : psb - > m_cfg . kCHR ;
psb - > m_rcontacts . push_back ( c ) ;
if ( m_rigidBody )
m_rigidBody - > activate ( ) ;
}
}
}
btSoftBody * psb ;
const btCollisionObjectWrapper * m_colObj1Wrap ;
btRigidBody * m_rigidBody ;
btScalar dynmargin ;
btScalar stamargin ;
} ;
//
// CollideSDF_RD
//
struct CollideSDF_RD : btDbvt : : ICollide
{
void Process ( const btDbvtNode * leaf )
{
btSoftBody : : Node * node = ( btSoftBody : : Node * ) leaf - > data ;
DoNode ( * node ) ;
}
void DoNode ( btSoftBody : : Node & n ) const
{
const btScalar m = n . m_im > 0 ? dynmargin : stamargin ;
btSoftBody : : DeformableNodeRigidContact c ;
if ( ! n . m_battach )
{
// check for collision at x_{n+1}^*
if ( psb - > checkDeformableContact ( m_colObj1Wrap , n . m_q , m , c . m_cti , /*predict = */ true ) )
{
const btScalar ima = n . m_im ;
// todo: collision between multibody and fixed deformable node will be missed.
const btScalar imb = m_rigidBody ? m_rigidBody - > getInvMass ( ) : 0.f ;
const btScalar ms = ima + imb ;
if ( ms > 0 )
{
// resolve contact at x_n
psb - > checkDeformableContact ( m_colObj1Wrap , n . m_x , m , c . m_cti , /*predict = */ false ) ;
btSoftBody : : sCti & cti = c . m_cti ;
c . m_node = & n ;
const btScalar fc = psb - > m_cfg . kDF * m_colObj1Wrap - > getCollisionObject ( ) - > getFriction ( ) ;
c . m_c2 = ima ;
c . m_c3 = fc ;
c . m_c4 = m_colObj1Wrap - > getCollisionObject ( ) - > isStaticOrKinematicObject ( ) ? psb - > m_cfg . kKHR : psb - > m_cfg . kCHR ;
c . m_c5 = n . m_effectiveMass_inv ;
if ( cti . m_colObj - > getInternalType ( ) = = btCollisionObject : : CO_RIGID_BODY )
{
const btTransform & wtr = m_rigidBody ? m_rigidBody - > getWorldTransform ( ) : m_colObj1Wrap - > getCollisionObject ( ) - > getWorldTransform ( ) ;
static const btMatrix3x3 iwiStatic ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
const btMatrix3x3 & iwi = m_rigidBody ? m_rigidBody - > getInvInertiaTensorWorld ( ) : iwiStatic ;
const btVector3 ra = n . m_x - wtr . getOrigin ( ) ;
c . m_c0 = ImpulseMatrix ( 1 , n . m_effectiveMass_inv , imb , iwi , ra ) ;
// c.m_c0 = ImpulseMatrix(1, ima, imb, iwi, ra);
c . m_c1 = ra ;
}
else if ( cti . m_colObj - > getInternalType ( ) = = btCollisionObject : : CO_FEATHERSTONE_LINK )
{
btMultiBodyLinkCollider * multibodyLinkCol = ( btMultiBodyLinkCollider * ) btMultiBodyLinkCollider : : upcast ( cti . m_colObj ) ;
if ( multibodyLinkCol )
{
btVector3 normal = cti . m_normal ;
btVector3 t1 = generateUnitOrthogonalVector ( normal ) ;
btVector3 t2 = btCross ( normal , t1 ) ;
btMultiBodyJacobianData jacobianData_normal , jacobianData_t1 , jacobianData_t2 ;
findJacobian ( multibodyLinkCol , jacobianData_normal , c . m_node - > m_x , normal ) ;
findJacobian ( multibodyLinkCol , jacobianData_t1 , c . m_node - > m_x , t1 ) ;
findJacobian ( multibodyLinkCol , jacobianData_t2 , c . m_node - > m_x , t2 ) ;
btScalar * J_n = & jacobianData_normal . m_jacobians [ 0 ] ;
btScalar * J_t1 = & jacobianData_t1 . m_jacobians [ 0 ] ;
btScalar * J_t2 = & jacobianData_t2 . m_jacobians [ 0 ] ;
btScalar * u_n = & jacobianData_normal . m_deltaVelocitiesUnitImpulse [ 0 ] ;
btScalar * u_t1 = & jacobianData_t1 . m_deltaVelocitiesUnitImpulse [ 0 ] ;
btScalar * u_t2 = & jacobianData_t2 . m_deltaVelocitiesUnitImpulse [ 0 ] ;
btMatrix3x3 rot ( normal . getX ( ) , normal . getY ( ) , normal . getZ ( ) ,
t1 . getX ( ) , t1 . getY ( ) , t1 . getZ ( ) ,
t2 . getX ( ) , t2 . getY ( ) , t2 . getZ ( ) ) ; // world frame to local frame
const int ndof = multibodyLinkCol - > m_multiBody - > getNumDofs ( ) + 6 ;
btMatrix3x3 local_impulse_matrix = ( n . m_effectiveMass_inv + OuterProduct ( J_n , J_t1 , J_t2 , u_n , u_t1 , u_t2 , ndof ) ) . inverse ( ) ;
c . m_c0 = rot . transpose ( ) * local_impulse_matrix * rot ;
c . jacobianData_normal = jacobianData_normal ;
c . jacobianData_t1 = jacobianData_t1 ;
c . jacobianData_t2 = jacobianData_t2 ;
c . t1 = t1 ;
c . t2 = t2 ;
}
}
psb - > m_nodeRigidContacts . push_back ( c ) ;
}
}
}
}
btSoftBody * psb ;
const btCollisionObjectWrapper * m_colObj1Wrap ;
btRigidBody * m_rigidBody ;
btScalar dynmargin ;
btScalar stamargin ;
} ;
//
// CollideSDF_RDF
//
struct CollideSDF_RDF : btDbvt : : ICollide
{
void Process ( const btDbvtNode * leaf )
{
btSoftBody : : Face * face = ( btSoftBody : : Face * ) leaf - > data ;
DoNode ( * face ) ;
}
void DoNode ( btSoftBody : : Face & f ) const
{
btSoftBody : : Node * n0 = f . m_n [ 0 ] ;
btSoftBody : : Node * n1 = f . m_n [ 1 ] ;
btSoftBody : : Node * n2 = f . m_n [ 2 ] ;
const btScalar m = ( n0 - > m_im > 0 & & n1 - > m_im > 0 & & n2 - > m_im > 0 ) ? dynmargin : stamargin ;
btSoftBody : : DeformableFaceRigidContact c ;
btVector3 contact_point ;
btVector3 bary ;
if ( psb - > checkDeformableFaceContact ( m_colObj1Wrap , f , contact_point , bary , m , c . m_cti , true ) )
{
btScalar ima = n0 - > m_im + n1 - > m_im + n2 - > m_im ;
const btScalar imb = m_rigidBody ? m_rigidBody - > getInvMass ( ) : 0.f ;
// todo: collision between multibody and fixed deformable face will be missed.
const btScalar ms = ima + imb ;
if ( ms > 0 )
{
// resolve contact at x_n
// psb->checkDeformableFaceContact(m_colObj1Wrap, f, contact_point, bary, m, c.m_cti, /*predict = */ false);
btSoftBody : : sCti & cti = c . m_cti ;
c . m_contactPoint = contact_point ;
c . m_bary = bary ;
// todo xuchenhan@: this is assuming mass of all vertices are the same. Need to modify if mass are different for distinct vertices
c . m_weights = btScalar ( 2 ) / ( btScalar ( 1 ) + bary . length2 ( ) ) * bary ;
c . m_face = & f ;
// friction is handled by the nodes to prevent sticking
// const btScalar fc = 0;
const btScalar fc = psb - > m_cfg . kDF * m_colObj1Wrap - > getCollisionObject ( ) - > getFriction ( ) ;
// the effective inverse mass of the face as in https://graphics.stanford.edu/papers/cloth-sig02/cloth.pdf
ima = bary . getX ( ) * c . m_weights . getX ( ) * n0 - > m_im + bary . getY ( ) * c . m_weights . getY ( ) * n1 - > m_im + bary . getZ ( ) * c . m_weights . getZ ( ) * n2 - > m_im ;
c . m_c2 = ima ;
c . m_c3 = fc ;
c . m_c4 = m_colObj1Wrap - > getCollisionObject ( ) - > isStaticOrKinematicObject ( ) ? psb - > m_cfg . kKHR : psb - > m_cfg . kCHR ;
c . m_c5 = Diagonal ( ima ) ;
if ( cti . m_colObj - > getInternalType ( ) = = btCollisionObject : : CO_RIGID_BODY )
{
const btTransform & wtr = m_rigidBody ? m_rigidBody - > getWorldTransform ( ) : m_colObj1Wrap - > getCollisionObject ( ) - > getWorldTransform ( ) ;
static const btMatrix3x3 iwiStatic ( 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) ;
const btMatrix3x3 & iwi = m_rigidBody ? m_rigidBody - > getInvInertiaTensorWorld ( ) : iwiStatic ;
const btVector3 ra = contact_point - wtr . getOrigin ( ) ;
// we do not scale the impulse matrix by dt
c . m_c0 = ImpulseMatrix ( 1 , ima , imb , iwi , ra ) ;
c . m_c1 = ra ;
}
else if ( cti . m_colObj - > getInternalType ( ) = = btCollisionObject : : CO_FEATHERSTONE_LINK )
{
btMultiBodyLinkCollider * multibodyLinkCol = ( btMultiBodyLinkCollider * ) btMultiBodyLinkCollider : : upcast ( cti . m_colObj ) ;
if ( multibodyLinkCol )
{
btVector3 normal = cti . m_normal ;
btVector3 t1 = generateUnitOrthogonalVector ( normal ) ;
btVector3 t2 = btCross ( normal , t1 ) ;
btMultiBodyJacobianData jacobianData_normal , jacobianData_t1 , jacobianData_t2 ;
findJacobian ( multibodyLinkCol , jacobianData_normal , contact_point , normal ) ;
findJacobian ( multibodyLinkCol , jacobianData_t1 , contact_point , t1 ) ;
findJacobian ( multibodyLinkCol , jacobianData_t2 , contact_point , t2 ) ;
btScalar * J_n = & jacobianData_normal . m_jacobians [ 0 ] ;
btScalar * J_t1 = & jacobianData_t1 . m_jacobians [ 0 ] ;
btScalar * J_t2 = & jacobianData_t2 . m_jacobians [ 0 ] ;
btScalar * u_n = & jacobianData_normal . m_deltaVelocitiesUnitImpulse [ 0 ] ;
btScalar * u_t1 = & jacobianData_t1 . m_deltaVelocitiesUnitImpulse [ 0 ] ;
btScalar * u_t2 = & jacobianData_t2 . m_deltaVelocitiesUnitImpulse [ 0 ] ;
btMatrix3x3 rot ( normal . getX ( ) , normal . getY ( ) , normal . getZ ( ) ,
t1 . getX ( ) , t1 . getY ( ) , t1 . getZ ( ) ,
t2 . getX ( ) , t2 . getY ( ) , t2 . getZ ( ) ) ; // world frame to local frame
const int ndof = multibodyLinkCol - > m_multiBody - > getNumDofs ( ) + 6 ;
btMatrix3x3 local_impulse_matrix = ( Diagonal ( ima ) + OuterProduct ( J_n , J_t1 , J_t2 , u_n , u_t1 , u_t2 , ndof ) ) . inverse ( ) ;
c . m_c0 = rot . transpose ( ) * local_impulse_matrix * rot ;
c . jacobianData_normal = jacobianData_normal ;
c . jacobianData_t1 = jacobianData_t1 ;
c . jacobianData_t2 = jacobianData_t2 ;
c . t1 = t1 ;
c . t2 = t2 ;
}
}
psb - > m_faceRigidContacts . push_back ( c ) ;
}
}
// Set caching barycenters to be false after collision detection.
// Only turn on when contact is static.
f . m_pcontact [ 3 ] = 0 ;
}
btSoftBody * psb ;
const btCollisionObjectWrapper * m_colObj1Wrap ;
btRigidBody * m_rigidBody ;
btScalar dynmargin ;
btScalar stamargin ;
} ;
//
// CollideVF_SS
//
struct CollideVF_SS : btDbvt : : ICollide
{
void Process ( const btDbvtNode * lnode ,
const btDbvtNode * lface )
{
btSoftBody : : Node * node = ( btSoftBody : : Node * ) lnode - > data ;
btSoftBody : : Face * face = ( btSoftBody : : Face * ) lface - > data ;
for ( int i = 0 ; i < 3 ; + + i )
{
if ( face - > m_n [ i ] = = node )
continue ;
}
btVector3 o = node - > m_x ;
btVector3 p ;
btScalar d = SIMD_INFINITY ;
ProjectOrigin ( face - > m_n [ 0 ] - > m_x - o ,
face - > m_n [ 1 ] - > m_x - o ,
face - > m_n [ 2 ] - > m_x - o ,
p , d ) ;
const btScalar m = mrg + ( o - node - > m_q ) . length ( ) * 2 ;
if ( d < ( m * m ) )
{
const btSoftBody : : Node * n [ ] = { face - > m_n [ 0 ] , face - > m_n [ 1 ] , face - > m_n [ 2 ] } ;
const btVector3 w = BaryCoord ( n [ 0 ] - > m_x , n [ 1 ] - > m_x , n [ 2 ] - > m_x , p + o ) ;
const btScalar ma = node - > m_im ;
btScalar mb = BaryEval ( n [ 0 ] - > m_im , n [ 1 ] - > m_im , n [ 2 ] - > m_im , w ) ;
if ( ( n [ 0 ] - > m_im < = 0 ) | |
( n [ 1 ] - > m_im < = 0 ) | |
( n [ 2 ] - > m_im < = 0 ) )
{
mb = 0 ;
}
const btScalar ms = ma + mb ;
if ( ms > 0 )
{
btSoftBody : : SContact c ;
c . m_normal = p / - btSqrt ( d ) ;
c . m_margin = m ;
c . m_node = node ;
c . m_face = face ;
c . m_weights = w ;
c . m_friction = btMax ( psb [ 0 ] - > m_cfg . kDF , psb [ 1 ] - > m_cfg . kDF ) ;
c . m_cfm [ 0 ] = ma / ms * psb [ 0 ] - > m_cfg . kSHR ;
c . m_cfm [ 1 ] = mb / ms * psb [ 1 ] - > m_cfg . kSHR ;
psb [ 0 ] - > m_scontacts . push_back ( c ) ;
}
}
}
btSoftBody * psb [ 2 ] ;
btScalar mrg ;
} ;
//
// CollideVF_DD
//
struct CollideVF_DD : btDbvt : : ICollide
{
void Process ( const btDbvtNode * lnode ,
const btDbvtNode * lface )
{
btSoftBody : : Node * node = ( btSoftBody : : Node * ) lnode - > data ;
btSoftBody : : Face * face = ( btSoftBody : : Face * ) lface - > data ;
btVector3 bary ;
if ( proximityTest ( face - > m_n [ 0 ] - > m_x , face - > m_n [ 1 ] - > m_x , face - > m_n [ 2 ] - > m_x , node - > m_x , face - > m_normal , mrg , bary ) )
{
const btSoftBody : : Node * n [ ] = { face - > m_n [ 0 ] , face - > m_n [ 1 ] , face - > m_n [ 2 ] } ;
const btVector3 w = bary ;
const btScalar ma = node - > m_im ;
btScalar mb = BaryEval ( n [ 0 ] - > m_im , n [ 1 ] - > m_im , n [ 2 ] - > m_im , w ) ;
if ( ( n [ 0 ] - > m_im < = 0 ) | |
( n [ 1 ] - > m_im < = 0 ) | |
( n [ 2 ] - > m_im < = 0 ) )
{
mb = 0 ;
}
const btScalar ms = ma + mb ;
if ( ms > 0 )
{
btSoftBody : : DeformableFaceNodeContact c ;
c . m_normal = face - > m_normal ;
if ( ! useFaceNormal & & c . m_normal . dot ( node - > m_x - face - > m_n [ 2 ] - > m_x ) < 0 )
c . m_normal = - face - > m_normal ;
c . m_margin = mrg ;
c . m_node = node ;
c . m_face = face ;
c . m_bary = w ;
c . m_friction = psb [ 0 ] - > m_cfg . kDF * psb [ 1 ] - > m_cfg . kDF ;
// Initialize unused fields.
c . m_weights = btVector3 ( 0 , 0 , 0 ) ;
c . m_imf = 0 ;
c . m_c0 = 0 ;
psb [ 0 ] - > m_faceNodeContacts . push_back ( c ) ;
}
}
}
btSoftBody * psb [ 2 ] ;
btScalar mrg ;
bool useFaceNormal ;
} ;
//
// CollideFF_DD
//
struct CollideFF_DD : btDbvt : : ICollide
{
void Process ( const btDbvntNode * lface1 ,
const btDbvntNode * lface2 )
{
btSoftBody : : Face * f1 = ( btSoftBody : : Face * ) lface1 - > data ;
btSoftBody : : Face * f2 = ( btSoftBody : : Face * ) lface2 - > data ;
if ( f1 ! = f2 )
{
Repel ( f1 , f2 ) ;
Repel ( f2 , f1 ) ;
}
}
void Repel ( btSoftBody : : Face * f1 , btSoftBody : : Face * f2 )
{
//#define REPEL_NEIGHBOR 1
# ifndef REPEL_NEIGHBOR
for ( int node_id = 0 ; node_id < 3 ; + + node_id )
{
btSoftBody : : Node * node = f1 - > m_n [ node_id ] ;
for ( int i = 0 ; i < 3 ; + + i )
{
if ( f2 - > m_n [ i ] = = node )
return ;
}
}
# endif
bool skip = false ;
for ( int node_id = 0 ; node_id < 3 ; + + node_id )
{
btSoftBody : : Node * node = f1 - > m_n [ node_id ] ;
# ifdef REPEL_NEIGHBOR
for ( int i = 0 ; i < 3 ; + + i )
{
if ( f2 - > m_n [ i ] = = node )
{
skip = true ;
break ;
}
}
if ( skip )
{
skip = false ;
continue ;
}
# endif
btSoftBody : : Face * face = f2 ;
btVector3 bary ;
if ( ! proximityTest ( face - > m_n [ 0 ] - > m_x , face - > m_n [ 1 ] - > m_x , face - > m_n [ 2 ] - > m_x , node - > m_x , face - > m_normal , mrg , bary ) )
continue ;
btSoftBody : : DeformableFaceNodeContact c ;
c . m_normal = face - > m_normal ;
if ( ! useFaceNormal & & c . m_normal . dot ( node - > m_x - face - > m_n [ 2 ] - > m_x ) < 0 )
c . m_normal = - face - > m_normal ;
c . m_margin = mrg ;
c . m_node = node ;
c . m_face = face ;
c . m_bary = bary ;
c . m_friction = psb [ 0 ] - > m_cfg . kDF * psb [ 1 ] - > m_cfg . kDF ;
// Initialize unused fields.
c . m_weights = btVector3 ( 0 , 0 , 0 ) ;
c . m_imf = 0 ;
c . m_c0 = 0 ;
psb [ 0 ] - > m_faceNodeContacts . push_back ( c ) ;
}
}
btSoftBody * psb [ 2 ] ;
btScalar mrg ;
bool useFaceNormal ;
} ;
struct CollideCCD : btDbvt : : ICollide
{
void Process ( const btDbvtNode * lnode ,
const btDbvtNode * lface )
{
btSoftBody : : Node * node = ( btSoftBody : : Node * ) lnode - > data ;
btSoftBody : : Face * face = ( btSoftBody : : Face * ) lface - > data ;
btVector3 bary ;
if ( bernsteinCCD ( face , node , dt , SAFE_EPSILON , bary ) )
{
btSoftBody : : DeformableFaceNodeContact c ;
c . m_normal = face - > m_normal ;
if ( ! useFaceNormal & & c . m_normal . dot ( node - > m_x - face - > m_n [ 2 ] - > m_x ) < 0 )
c . m_normal = - face - > m_normal ;
c . m_node = node ;
c . m_face = face ;
c . m_bary = bary ;
c . m_friction = psb [ 0 ] - > m_cfg . kDF * psb [ 1 ] - > m_cfg . kDF ;
// Initialize unused fields.
c . m_weights = btVector3 ( 0 , 0 , 0 ) ;
c . m_margin = mrg ;
c . m_imf = 0 ;
c . m_c0 = 0 ;
psb [ 0 ] - > m_faceNodeContacts . push_back ( c ) ;
}
}
void Process ( const btDbvntNode * lface1 ,
const btDbvntNode * lface2 )
{
btSoftBody : : Face * f1 = ( btSoftBody : : Face * ) lface1 - > data ;
btSoftBody : : Face * f2 = ( btSoftBody : : Face * ) lface2 - > data ;
if ( f1 ! = f2 )
{
Repel ( f1 , f2 ) ;
Repel ( f2 , f1 ) ;
}
}
void Repel ( btSoftBody : : Face * f1 , btSoftBody : : Face * f2 )
{
//#define REPEL_NEIGHBOR 1
# ifndef REPEL_NEIGHBOR
for ( int node_id = 0 ; node_id < 3 ; + + node_id )
{
btSoftBody : : Node * node = f1 - > m_n [ node_id ] ;
for ( int i = 0 ; i < 3 ; + + i )
{
if ( f2 - > m_n [ i ] = = node )
return ;
}
}
# endif
bool skip = false ;
for ( int node_id = 0 ; node_id < 3 ; + + node_id )
{
btSoftBody : : Node * node = f1 - > m_n [ node_id ] ;
# ifdef REPEL_NEIGHBOR
for ( int i = 0 ; i < 3 ; + + i )
{
if ( f2 - > m_n [ i ] = = node )
{
skip = true ;
break ;
}
}
if ( skip )
{
skip = false ;
continue ;
}
# endif
btSoftBody : : Face * face = f2 ;
btVector3 bary ;
if ( bernsteinCCD ( face , node , dt , SAFE_EPSILON , bary ) )
{
btSoftBody : : DeformableFaceNodeContact c ;
c . m_normal = face - > m_normal ;
if ( ! useFaceNormal & & c . m_normal . dot ( node - > m_x - face - > m_n [ 2 ] - > m_x ) < 0 )
c . m_normal = - face - > m_normal ;
c . m_node = node ;
c . m_face = face ;
c . m_bary = bary ;
c . m_friction = psb [ 0 ] - > m_cfg . kDF * psb [ 1 ] - > m_cfg . kDF ;
// Initialize unused fields.
c . m_weights = btVector3 ( 0 , 0 , 0 ) ;
c . m_margin = mrg ;
c . m_imf = 0 ;
c . m_c0 = 0 ;
psb [ 0 ] - > m_faceNodeContacts . push_back ( c ) ;
}
}
}
btSoftBody * psb [ 2 ] ;
btScalar dt , mrg ;
bool useFaceNormal ;
} ;
} ;
# endif //_BT_SOFT_BODY_INTERNALS_H