btScalar GodotRestInfoContactResultCallback::addSingleResult(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1) { if (cp.getDistance() <= m_min_distance) { m_min_distance = cp.getDistance(); CollisionObjectBullet *colObj; if (m_self_object == colObj0Wrap->getCollisionObject()) { colObj = static_cast<CollisionObjectBullet *>(colObj1Wrap->getCollisionObject()->getUserPointer()); m_result->shape = cp.m_index1; B_TO_G(cp.getPositionWorldOnB(), m_result->point); m_rest_info_bt_point = cp.getPositionWorldOnB(); m_rest_info_collision_object = colObj1Wrap->getCollisionObject(); } else { colObj = static_cast<CollisionObjectBullet *>(colObj0Wrap->getCollisionObject()->getUserPointer()); m_result->shape = cp.m_index0; B_TO_G(cp.m_normalWorldOnB * -1, m_result->normal); m_rest_info_bt_point = cp.getPositionWorldOnA(); m_rest_info_collision_object = colObj0Wrap->getCollisionObject(); } if (colObj) m_result->collider_id = colObj->get_instance_id(); else m_result->collider_id = 0; m_result->rid = colObj->get_self(); m_collided = true; } return cp.getDistance(); }
virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* col0, int partId0, int index0, const btCollisionObject* col1, int partId1, int index1) { const RigidBody* body = dynamic_cast<const RigidBody*>(col1); if(body && body->mName != mFilter) { btScalar distsqr = mOrigin.distance2(cp.getPositionWorldOnA()); if(!mObject || distsqr < mLeastDistSqr) { mObject = body; mLeastDistSqr = distsqr; mContactPoint = cp.getPositionWorldOnA(); } } return 0.f; }
virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObjectWrapper* colObj0Wrap,int partId0,int index0,const btCollisionObjectWrapper* colObj1Wrap,int partId1,int index1) { glBegin(GL_LINES); glColor3f(0, 0, 0); btVector3 ptA = cp.getPositionWorldOnA(); btVector3 ptB = cp.getPositionWorldOnB(); glVertex3d(ptA.x(),ptA.y(),ptA.z()); glVertex3d(ptB.x(),ptB.y(),ptB.z()); glEnd(); return 0; }
void handleVehicleResponse(GameObject* object, btManifoldPoint& mp, bool isA) { bool isVehicle = object->type() == GameObject::Vehicle; if(! isVehicle) return; if( mp.getAppliedImpulse() <= 100.f ) return; btVector3 src, dmg; if(isA) { src = mp.getPositionWorldOnB(); dmg = mp.getPositionWorldOnA(); } else { src = mp.getPositionWorldOnA(); dmg = mp.getPositionWorldOnB(); } object->takeDamage({ {dmg.x(), dmg.y(), dmg.z()}, {src.x(), src.y(), src.z()}, 0.f, GameObject::DamageInfo::Physics, mp.getAppliedImpulse() }); }
bool materialCombinerCallback(btManifoldPoint& cp, const btCollisionObject* colObj0, int partId0, int index0, const btCollisionObject* colObj1, int partId1, int index1) { btVector3 impact_point = cp.getPositionWorldOnA(); if (!colObj0->isStaticObject() && colObj0->isActive()) { osg::Node *n0 = static_cast<osg::Node*>(colObj0->getUserPointer()); osg::Node *n1 = static_cast<osg::Node*>(colObj1->getUserPointer()); std::cout << "Hit at ["<< impact_point.getX() << ", " << impact_point.getY() << ", " << impact_point.getZ() << "] "<< std::endl; //if (n0 && !n0->getName().empty()) std::cout << " obj0: " << n0->getName() << std::endl; if (n1 && !n1->getName().empty()) std::cout << " obj1: " << n1->getName() << std::endl; //std::cout << "Hit between " << static_cast<osg::Node *> (colObj0->getUserPointer())->getName() << " and " << static_cast<osg::Node *> (colObj1->getUserPointer())->getName() << " at ["<< impact_point.getX() << ", " << impact_point.getY() << ", " << impact_point.getZ() << "] "<< std::endl; } return false; }
void btMultiBodyConstraintSolver::setupMultiBodyContactConstraint(btMultiBodySolverConstraint& solverConstraint, const btVector3& contactNormal, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal, btScalar& relaxation, bool isFriction, btScalar desiredVelocity, btScalar cfmSlip) { BT_PROFILE("setupMultiBodyContactConstraint"); btVector3 rel_pos1; btVector3 rel_pos2; btMultiBody* multiBodyA = solverConstraint.m_multiBodyA; btMultiBody* multiBodyB = solverConstraint.m_multiBodyB; const btVector3& pos1 = cp.getPositionWorldOnA(); const btVector3& pos2 = cp.getPositionWorldOnB(); btSolverBody* bodyA = multiBodyA ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdA]; btSolverBody* bodyB = multiBodyB ? 0 : &m_tmpSolverBodyPool[solverConstraint.m_solverBodyIdB]; btRigidBody* rb0 = multiBodyA ? 0 : bodyA->m_originalBody; btRigidBody* rb1 = multiBodyB ? 0 : bodyB->m_originalBody; if (bodyA) rel_pos1 = pos1 - bodyA->getWorldTransform().getOrigin(); if (bodyB) rel_pos2 = pos2 - bodyB->getWorldTransform().getOrigin(); relaxation = 1.f; if (multiBodyA) { if (solverConstraint.m_linkA<0) { rel_pos1 = pos1 - multiBodyA->getBasePos(); } else { rel_pos1 = pos1 - multiBodyA->getLink(solverConstraint.m_linkA).m_cachedWorldTransform.getOrigin(); } const int ndofA = (multiBodyA->isMultiDof() ? multiBodyA->getNumDofs() : multiBodyA->getNumLinks()) + 6; solverConstraint.m_deltaVelAindex = multiBodyA->getCompanionId(); if (solverConstraint.m_deltaVelAindex <0) { solverConstraint.m_deltaVelAindex = m_data.m_deltaVelocities.size(); multiBodyA->setCompanionId(solverConstraint.m_deltaVelAindex); m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size()+ndofA); } else { btAssert(m_data.m_deltaVelocities.size() >= solverConstraint.m_deltaVelAindex+ndofA); } solverConstraint.m_jacAindex = m_data.m_jacobians.size(); m_data.m_jacobians.resize(m_data.m_jacobians.size()+ndofA); m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofA); btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size()); btScalar* jac1=&m_data.m_jacobians[solverConstraint.m_jacAindex]; if(multiBodyA->isMultiDof()) multiBodyA->fillContactJacobianMultiDof(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m); else multiBodyA->fillContactJacobian(solverConstraint.m_linkA, cp.getPositionWorldOnA(), contactNormal, jac1, m_data.scratch_r, m_data.scratch_v, m_data.scratch_m); btScalar* delta = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; if(multiBodyA->isMultiDof()) multiBodyA->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v); else multiBodyA->calcAccelerationDeltas(&m_data.m_jacobians[solverConstraint.m_jacAindex],delta,m_data.scratch_r, m_data.scratch_v); btVector3 torqueAxis0 = rel_pos1.cross(contactNormal); solverConstraint.m_relpos1CrossNormal = torqueAxis0; solverConstraint.m_contactNormal1 = contactNormal; } else { btVector3 torqueAxis0 = rel_pos1.cross(contactNormal); solverConstraint.m_relpos1CrossNormal = torqueAxis0; solverConstraint.m_contactNormal1 = contactNormal; solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); } if (multiBodyB) { if (solverConstraint.m_linkB<0) { rel_pos2 = pos2 - multiBodyB->getBasePos(); } else { rel_pos2 = pos2 - multiBodyB->getLink(solverConstraint.m_linkB).m_cachedWorldTransform.getOrigin(); } const int ndofB = (multiBodyB->isMultiDof() ? multiBodyB->getNumDofs() : multiBodyB->getNumLinks()) + 6; solverConstraint.m_deltaVelBindex = multiBodyB->getCompanionId(); if (solverConstraint.m_deltaVelBindex <0) { solverConstraint.m_deltaVelBindex = m_data.m_deltaVelocities.size(); multiBodyB->setCompanionId(solverConstraint.m_deltaVelBindex); m_data.m_deltaVelocities.resize(m_data.m_deltaVelocities.size()+ndofB); } solverConstraint.m_jacBindex = m_data.m_jacobians.size(); m_data.m_jacobians.resize(m_data.m_jacobians.size()+ndofB); m_data.m_deltaVelocitiesUnitImpulse.resize(m_data.m_deltaVelocitiesUnitImpulse.size()+ndofB); btAssert(m_data.m_jacobians.size() == m_data.m_deltaVelocitiesUnitImpulse.size()); if(multiBodyB->isMultiDof()) multiBodyB->fillContactJacobianMultiDof(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -contactNormal, &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m); else multiBodyB->fillContactJacobian(solverConstraint.m_linkB, cp.getPositionWorldOnB(), -contactNormal, &m_data.m_jacobians[solverConstraint.m_jacBindex], m_data.scratch_r, m_data.scratch_v, m_data.scratch_m); if(multiBodyB->isMultiDof()) multiBodyB->calcAccelerationDeltasMultiDof(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v); else multiBodyB->calcAccelerationDeltas(&m_data.m_jacobians[solverConstraint.m_jacBindex],&m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex],m_data.scratch_r, m_data.scratch_v); btVector3 torqueAxis1 = rel_pos2.cross(contactNormal); solverConstraint.m_relpos2CrossNormal = -torqueAxis1; solverConstraint.m_contactNormal2 = -contactNormal; } else { btVector3 torqueAxis1 = rel_pos2.cross(contactNormal); solverConstraint.m_relpos2CrossNormal = -torqueAxis1; solverConstraint.m_contactNormal2 = -contactNormal; solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0); } { btVector3 vec; btScalar denom0 = 0.f; btScalar denom1 = 0.f; btScalar* jacB = 0; btScalar* jacA = 0; btScalar* lambdaA =0; btScalar* lambdaB =0; int ndofA = 0; if (multiBodyA) { ndofA = (multiBodyA->isMultiDof() ? multiBodyA->getNumDofs() : multiBodyA->getNumLinks()) + 6; jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex]; lambdaA = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; for (int i = 0; i < ndofA; ++i) { btScalar j = jacA[i] ; btScalar l =lambdaA[i]; denom0 += j*l; } } else { if (rb0) { vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); denom0 = rb0->getInvMass() + contactNormal.dot(vec); } } if (multiBodyB) { const int ndofB = (multiBodyB->isMultiDof() ? multiBodyB->getNumDofs() : multiBodyB->getNumLinks()) + 6; jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex]; lambdaB = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; for (int i = 0; i < ndofB; ++i) { btScalar j = jacB[i] ; btScalar l =lambdaB[i]; denom1 += j*l; } } else { if (rb1) { vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); denom1 = rb1->getInvMass() + contactNormal.dot(vec); } } btScalar d = denom0+denom1; if (d>SIMD_EPSILON) { solverConstraint.m_jacDiagABInv = relaxation/(d); } else { //disable the constraint row to handle singularity/redundant constraint solverConstraint.m_jacDiagABInv = 0.f; } } //compute rhs and remaining solverConstraint fields btScalar restitution = 0.f; btScalar penetration = isFriction? 0 : cp.getDistance()+infoGlobal.m_linearSlop; btScalar rel_vel = 0.f; int ndofA = 0; int ndofB = 0; { btVector3 vel1,vel2; if (multiBodyA) { ndofA = (multiBodyA->isMultiDof() ? multiBodyA->getNumDofs() : multiBodyA->getNumLinks()) + 6; btScalar* jacA = &m_data.m_jacobians[solverConstraint.m_jacAindex]; for (int i = 0; i < ndofA ; ++i) rel_vel += multiBodyA->getVelocityVector()[i] * jacA[i]; } else { if (rb0) { rel_vel += rb0->getVelocityInLocalPoint(rel_pos1).dot(solverConstraint.m_contactNormal1); } } if (multiBodyB) { ndofB = (multiBodyB->isMultiDof() ? multiBodyB->getNumDofs() : multiBodyB->getNumLinks()) + 6; btScalar* jacB = &m_data.m_jacobians[solverConstraint.m_jacBindex]; for (int i = 0; i < ndofB ; ++i) rel_vel += multiBodyB->getVelocityVector()[i] * jacB[i]; } else { if (rb1) { rel_vel += rb1->getVelocityInLocalPoint(rel_pos2).dot(solverConstraint.m_contactNormal2); } } solverConstraint.m_friction = cp.m_combinedFriction; if(!isFriction) { restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution); if (restitution <= btScalar(0.)) { restitution = 0.f; } } } ///warm starting (or zero if disabled) //disable warmstarting for btMultiBody, it has issues gaining energy (==explosion) if (0)//infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING) { solverConstraint.m_appliedImpulse = isFriction ? 0 : cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor; if (solverConstraint.m_appliedImpulse) { if (multiBodyA) { btScalar impulse = solverConstraint.m_appliedImpulse; btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacAindex]; if(multiBodyA->isMultiDof()) multiBodyA->applyDeltaVeeMultiDof(deltaV,impulse); else multiBodyA->applyDeltaVee(deltaV,impulse); applyDeltaVee(deltaV,impulse,solverConstraint.m_deltaVelAindex,ndofA); } else { if (rb0) bodyA->internalApplyImpulse(solverConstraint.m_contactNormal1*bodyA->internalGetInvMass()*rb0->getLinearFactor(),solverConstraint.m_angularComponentA,solverConstraint.m_appliedImpulse); } if (multiBodyB) { btScalar impulse = solverConstraint.m_appliedImpulse; btScalar* deltaV = &m_data.m_deltaVelocitiesUnitImpulse[solverConstraint.m_jacBindex]; if(multiBodyB->isMultiDof()) multiBodyB->applyDeltaVeeMultiDof(deltaV,impulse); else multiBodyB->applyDeltaVee(deltaV,impulse); applyDeltaVee(deltaV,impulse,solverConstraint.m_deltaVelBindex,ndofB); } else { if (rb1) bodyB->internalApplyImpulse(-solverConstraint.m_contactNormal2*bodyB->internalGetInvMass()*rb1->getLinearFactor(),-solverConstraint.m_angularComponentB,-(btScalar)solverConstraint.m_appliedImpulse); } } } else { solverConstraint.m_appliedImpulse = 0.f; } solverConstraint.m_appliedPushImpulse = 0.f; { btScalar positionalError = 0.f; btScalar velocityError = restitution - rel_vel;// * damping; //note for friction restitution is always set to 0 (check above) so it is acutally velocityError = -rel_vel for friction btScalar erp = infoGlobal.m_erp2; if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { erp = infoGlobal.m_erp; } if (penetration>0) { positionalError = 0; velocityError -= penetration / infoGlobal.m_timeStep; } else { positionalError = -penetration * erp/infoGlobal.m_timeStep; } btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; if(!isFriction) { if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { //combine position and velocity into rhs solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; } else { //split position and velocity into rhs and m_rhsPenetration solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = penetrationImpulse; } solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } else { solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; solverConstraint.m_lowerLimit = -solverConstraint.m_friction; solverConstraint.m_upperLimit = solverConstraint.m_friction; } solverConstraint.m_cfm = 0.f; //why not use cfmSlip? } }
bool GameWorld::ContactProcessedCallback(btManifoldPoint &mp, void *body0, void *body1) { auto obA = static_cast<btCollisionObject*>(body0); auto obB = static_cast<btCollisionObject*>(body1); if( !( obA->getUserPointer() && obB->getUserPointer() ) ) { return false; } GameObject* a = static_cast<GameObject*>(obA->getUserPointer()); GameObject* b = static_cast<GameObject*>(obB->getUserPointer()); bool valA = a && a->type() == GameObject::Instance; bool valB = b && b->type() == GameObject::Instance; if( ! (valA && valB) && (valB || valA) ) { // Figure out which is the dynamic instance. InstanceObject* dynInst = nullptr; const btRigidBody* instBody = nullptr, * otherBody = nullptr; btVector3 src, dmg; if( valA ) { dynInst = static_cast<InstanceObject*>(a); instBody = static_cast<const btRigidBody*>(obA); otherBody = static_cast<const btRigidBody*>(obB); src = mp.getPositionWorldOnB(); dmg = mp.getPositionWorldOnA(); } else { dynInst = static_cast<InstanceObject*>(b); instBody = static_cast<const btRigidBody*>(obB); otherBody = static_cast<const btRigidBody*>(obA); src = mp.getPositionWorldOnA(); dmg = mp.getPositionWorldOnB(); } if( dynInst->dynamics != nullptr && instBody->isStaticObject() ) { // Attempt to determine relative velocity. auto dV = (otherBody->getLinearVelocity()); auto impulse = dV.length()/ (otherBody->getInvMass()); if( dynInst->dynamics->uprootForce <= impulse ) { dynInst->takeDamage({ {dmg.x(), dmg.y(), dmg.z()}, {src.x(), src.y(), src.z()}, 0.f, GameObject::DamageInfo::Physics, impulse }); } } } // Handle vehicles if(a) handleVehicleResponse(a, mp, true); if(b) handleVehicleResponse(b, mp, false); return true; }