void BulletWrapper::utilSetupScene(const EigenTypes::Vector3f& refPosition) { // setup walls float halfSize = 0.05f; EigenTypes::Vector3f boxHalfExtents(halfSize, halfSize, halfSize); float spacing = 2.f * halfSize; float zDist = 0.5f; // for Dragonfly zDist = 0.6f * zDist; int halfCountX = std::min(4, int((zDist-halfSize)/spacing)); int halfCountY = 3; for (int y = -halfCountY; y <= halfCountY; y++) for (int x = -halfCountX; x <= halfCountX; x++) { utilAddCube(refPosition + EigenTypes::Vector3f(spacing * x, spacing * y, -zDist), boxHalfExtents); utilAddCube(refPosition + EigenTypes::Vector3f(spacing * x, spacing * y, zDist), boxHalfExtents); utilAddCube(refPosition + EigenTypes::Vector3f(zDist, spacing * y, spacing * x), boxHalfExtents); utilAddCube(refPosition + EigenTypes::Vector3f(-zDist, spacing * y, spacing * x), boxHalfExtents); } // Add head representation const bool notVisible = false; m_HeadRepresentation = utilAddFingerSphere(refPosition, 0.2f, notVisible); }
// The scabbard is a single constraint which should have multiple degrees of freedom, but will suffer from the following // artifacts if implemented using a single ball-and-socket constraint: // 1. Undesired motion (excessive, potentially implausible, or just not artisitically desired) due to the simplification // to a single point of attachment. // 2. Excessive energy, or undersired enrgy preservation when the character comes to rest. // 3. A potential performance impact if collisions are used to prevent interpenetration with the character. // To address these we use a ragdoll constraint instead which allows full control to restict angular degrees of freedom of the // underlying ball-and-socket, and we use angular damping to make sure the scabbard comes to rest quickly. // We can then disable all collision between the scabbard and the hip, leaving all other collisions valid. void HK_CALL CharacterAttachmentsHelpers::addScabbard(hkpWorld* world, const hkaRagdollInstance* ragdollInstance, const hkQsTransform& currentTransform, const char* startBoneName, hkpGroupFilter* filter, const ConstraintStabilityTricks& tricks ) { // We will use a tricks to increase stability: const hkReal angularDamping = 4.0f; // Get the relevant RBs to which we attach this belt. hkpRigidBody* torso = HK_NULL; { int torsoIndex = hkaSkeletonUtils::findBoneWithName( *ragdollInstance->m_skeleton, startBoneName); HK_ASSERT2( 0, torsoIndex >= 0, "Couldn't find " << startBoneName << " in ragdoll" ); torso = ragdollInstance->getRigidBodyOfBone( torsoIndex ); } hkpRigidBody* scabbard; { hkVector4 boxHalfExtents( 0.02f, 0.05f, 0.3f); // Create body hkpRigidBodyCinfo info; info.m_shape = new hkpBoxShape( boxHalfExtents, 0.01f ); // We are going to add a single body which does not collide with the bone to which it is attached in the ragdoll so we // will put in the same group and disable collision using subgroups. hkUint32 torsoFilterInfo = torso->getCollidable()->getCollisionFilterInfo(); info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo( 1, 2, 31, // New subgroup - larger than any subgroup in the ragdoll hkpGroupFilter::getSubSystemIdFromFilterInfo(torsoFilterInfo) // Don't collide with torso subgroup ); // Note that we use a scaled mass here to artificially damp the movement const hkReal mass = 1.0f; hkpInertiaTensorComputer::setShapeVolumeMassProperties( info.m_shape, mass, info ); info.m_mass = mass; // Note that we use an increased angular damping to further artificially damp the movement if( tricks.m_useDamping ) { info.m_angularDamping = angularDamping; } // Place roughly beside the character model space - we'll let a short simulation run settle the constraint properly. info.m_position.set( 0.2f, 0.0f, -0.2f ); // Move into world space behind character info.m_position.setTransformedPos(currentTransform, info.m_position); scabbard = new hkpRigidBody( info ); info.m_shape->removeReference(); world->addEntity( scabbard ); scabbard->removeReference(); } // // Create constraint (to attach and also restrict motion) // hkVector4 pivotA, pivotB; { // Scabbard pivotA.set(-0.02f, 0.0f, 0.3f); // Torso pivotB.set(0.0f, 0.0f, 0.2f); } hkpConstraintData* cd = HK_NULL; if( tricks.m_useLimits ) { hkReal planeMin = -HK_REAL_PI * 0.5f; hkReal planeMax = HK_REAL_PI * 0.05f; hkReal twistMin = HK_REAL_PI * -0.04f; hkReal twistMax = HK_REAL_PI * 0.04f; hkReal coneMin = HK_REAL_PI * 0.3f; hkpRagdollConstraintData* rdcd = new hkpRagdollConstraintData(); rdcd->setConeAngularLimit(coneMin); rdcd->setPlaneMinAngularLimit(planeMin); rdcd->setPlaneMaxAngularLimit(planeMax); rdcd->setTwistMinAngularLimit(twistMin); rdcd->setTwistMaxAngularLimit(twistMax); // Scabbard hkVector4 twistAxisA(0.0f, 0.0f, 1.0f); hkVector4 planeAxisA(1.0f, 0.0f, 0.0f); // Torso hkVector4 twistAxisB(1.0f, 0.0f, 0.0f); hkVector4 planeAxisB(0.0f, 0.0f, 1.0f); rdcd->setInBodySpace(pivotA, pivotB, planeAxisA, planeAxisB, twistAxisA, twistAxisB); cd = rdcd; } else { // Just use a ball-and-socket (no angular limits) hkpBallAndSocketConstraintData* bscd = new hkpBallAndSocketConstraintData(); bscd->setInBodySpace(pivotA, pivotB); cd = bscd; } // // Create and add the constraint // { hkpConstraintInstance* constraint = new hkpConstraintInstance(scabbard, torso, cd ); world->addConstraint(constraint); constraint->removeReference(); } cd->removeReference(); }
// The backpack is a single constraint which should have only one degree of freedom, but will suffer from the following // artifacts if implemented using a single hinge constraint: // 1. Undesired motion (excessive, potentially implausible, or just not artisitically desired) due to the large // accelerations of the character. // 2. A potential performance impact if collisions are used to prevent interpenetration with the character. // To address this we use a limited hinge constraint which keeps the backpack from penetrating the spline and // from moving to far upwards. // The alternative approach of ensuring collisions between the character and the backpack keep it in place has the following flaws: // (a) Constant collision (such as when the character is standing idle) is expensive, especially if colliding with several bodies // such as are in the spine - a single constraint with fixed limits avoids this completely with minimal expense. // (b) Again, without limits, even if the backpack rests against the base of the spine when moving down, there is nothing to prevent // the large accelerations of the character forcing the backpack to swing up and forward over the shoulders until it collides with // the back of the head, which is probably not desirable from an artistic standpoint. void HK_CALL CharacterAttachmentsHelpers::addBackpack(hkpWorld* world, const hkaRagdollInstance* ragdollInstance, const hkQsTransform& currentTransform, const char* startBoneName, hkpGroupFilter* filter, const ConstraintStabilityTricks& tricks ) { // Get the relevant RBs to which we attach this backpack. hkpRigidBody* torso = HK_NULL; { int torsoIndex = hkaSkeletonUtils::findBoneWithName( *ragdollInstance->m_skeleton, startBoneName); HK_ASSERT2( 0, torsoIndex >= 0, "Couldn't find " << startBoneName << " in ragdoll" ); torso = ragdollInstance->getRigidBodyOfBone( torsoIndex ); } hkpRigidBody* backpack; { hkVector4 boxHalfExtents( 0.1f, 0.05f, 0.2f); // Create a body hkpRigidBodyCinfo info; info.m_shape = new hkpBoxShape( boxHalfExtents, 0.01f ); // We are going to add a single body which does not collide with the ragdoll *at all* so we // will put in a different group and different layer and disable collision using layers. info.m_collisionFilterInfo = hkpGroupFilter::calcFilterInfo( 2, 3 ); filter->disableCollisionsBetween(1, 2); const hkReal mass = 1.0f; hkpInertiaTensorComputer::setShapeVolumeMassProperties( info.m_shape, mass, info ); info.m_mass = mass; // Place roughly behind the character model space - we'll let a short simulation run settle the constraint properly. info.m_position.set( 0.2f, 0.0f, -0.2f ); // Move into world space behind character info.m_position.setTransformedPos(currentTransform, info.m_position); backpack = new hkpRigidBody( info ); info.m_shape->removeReference(); world->addEntity( backpack ); backpack->removeReference(); } // // Create constraint (to attach and also restrict motion) // { hkpLimitedHingeConstraintData* lhc = new hkpLimitedHingeConstraintData(); hkVector4 pivotA, pivotB; // Backpack pivotA.set(0.0f, -0.05f, 0.2f); hkVector4 axisA(1.0f, 0.0f, 0.0f); hkVector4 axisAPerp(0.0f, 0.0f, 1.0f); // Torso pivotB.set(0.1f, -0.07f, 0.0f); hkVector4 axisB(0.0f, 0.0f, 1.0f); hkVector4 axisBPerp(1.0f, 0.0f, 0.0f); lhc->setInBodySpace(pivotA, pivotB, axisA, axisB, axisAPerp, axisBPerp); lhc->setMinAngularLimit(HK_REAL_PI/40.0f); lhc->setMaxAngularLimit(HK_REAL_PI/4.0f); // // Create and add the constraint // { hkpConstraintInstance* constraint = new hkpConstraintInstance(backpack, torso, lhc ); world->addConstraint(constraint); constraint->removeReference(); } if( !tricks.m_useLimits ) { lhc->disableLimits(); } lhc->removeReference(); } }
void DemoKeeper::BinaryActionDemo( void ) { springNode=mSceneMgr->getRootSceneNode()->createChildSceneNode(); mWorld->markForWrite(); // // Create Rigid Body. // { /// Here we construct a simple cube with sides 2 units and mass 1. hkVector4 boxHalfExtents( 1.0f, 1.0f, 1.0f ); hkpBoxShape* geom = new hkpBoxShape( boxHalfExtents , 0 ); const hkReal mass = 1.0f; hkVector4 pos( -2.0f, 5.0f, 0.0f ); hkpRigidBodyCinfo boxInfo; hkMassProperties massProperties; hkpInertiaTensorComputer::computeBoxVolumeMassProperties(boxHalfExtents, mass, massProperties); boxInfo.m_mass = massProperties.m_mass; boxInfo.m_centerOfMass = massProperties.m_centerOfMass; boxInfo.m_inertiaTensor = massProperties.m_inertiaTensor; boxInfo.m_shape = geom; boxInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; boxInfo.m_position = pos; boxInfo.m_gravityFactor = 0; m_boxRigidBody1 = new hkpRigidBody(boxInfo); // As the rigid bodies now references our shape, we no longer need to. geom->removeReference(); // and add it to the world. mWorld->addEntity( m_boxRigidBody1 ); //render it with Ogre Ogre::SceneNode* boxNode1 = mSceneMgr->getRootSceneNode()->createChildSceneNode(); //scale boxNode1->scale(2, 2, 2); //display and sync Ogre::Entity *ent = mSceneMgr->createEntity(Ogre::StringConverter::toString(mLabMgr->getEntityCount()),"defCube.mesh"); mLabMgr->setColor(ent, Ogre::Vector3(0.5538,0.3187,0.1275)); HkOgre::Renderable* rend = new HkOgre::Renderable(boxNode1, m_boxRigidBody1,mWorld); boxNode1->attachObject(ent); //register to lab manager mLabMgr->registerEnity( boxNode1, m_boxRigidBody1); } // // Create Rigid Body. // { // Here we construct a simple cube with sides 2 units and mass 1. hkVector4 boxHalfExtents( 1.0f, 1.0f, 1.0f ); hkpBoxShape* geom = new hkpBoxShape( boxHalfExtents , 0 ); const hkReal mass = 1.0f; hkVector4 pos( 2.0f, 5.0f, 0.0f ); hkpRigidBodyCinfo boxInfo; hkMassProperties massProperties; hkpInertiaTensorComputer::computeBoxVolumeMassProperties(boxHalfExtents, mass, massProperties); boxInfo.m_mass = massProperties.m_mass; boxInfo.m_centerOfMass = massProperties.m_centerOfMass; boxInfo.m_inertiaTensor = massProperties.m_inertiaTensor; boxInfo.m_shape = geom; boxInfo.m_motionType = hkpMotion::MOTION_BOX_INERTIA; boxInfo.m_position = pos; boxInfo.m_gravityFactor = 0; m_boxRigidBody2 = new hkpRigidBody(boxInfo); // As the rigid bodies now references our shape, we no longer need to. geom->removeReference(); // and add it to the world. mWorld->addEntity( m_boxRigidBody2 ); //render it with Ogre Ogre::SceneNode* boxNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode(); //scale boxNode2->scale(2, 2, 2); //display and sync Ogre::Entity *ent = mSceneMgr->createEntity(Ogre::StringConverter::toString(mLabMgr->getEntityCount()),"defCube.mesh"); mLabMgr->setColor(ent, Ogre::Vector3(0.5538,0.3187,0.1275)); HkOgre::Renderable* rend = new HkOgre::Renderable(boxNode2, m_boxRigidBody2,mWorld); boxNode2->attachObject(ent); //register to lab manager mLabMgr->registerEnity( boxNode2, m_boxRigidBody2); } // // Create the action and add it to the world. // { // hkpSpringAction applies forces to keep the two hkRigidBodies restLength apart // hkpSpringAction is defined in 'hkutilities/actions/spring/hkpSpringAction.h'. m_springAction = new hkpSpringAction(m_boxRigidBody1, m_boxRigidBody2); m_springAction->setPositionsInBodySpace( m_boxRigidBody1->getCenterOfMassLocal(), m_boxRigidBody2->getCenterOfMassLocal()); m_springAction->setRestLength(6.0f); m_springAction->setDamping(0.3f); m_springAction->setStrength(10.0f); // Add springAction to the world. From now on springAction will automatically // be applied to its bodies during integration so long as the bodies are active. // If the bodies become inactive, antiGravityAction is not applied. If they // reactivate, springAction again starts applying to them. // springAction can also be removed using hkpWorld::removeAction(springAction) // after which it is no longer included in simulation. mWorld->addAction( m_springAction ); } mWorld->unmarkForWrite(); binaryaction_demoRunning = true; }