hkDemo::Result KeyframingDemo::stepDemo() { { m_world->lock(); hkVector4 pos; hkQuaternion rot; // Use 'required' position/rotation as the one at the end of this timestep. // The hkpKeyFrameUtility finds the correct velocites to ensure this keyframe is reached // in the next timestep. getKeyframePositionAndRotation(m_time + m_timestep, pos, rot); // As you can see this code causes the 'stirrer' to be keyframed in a circular motion. Since our 'bowl' causes // the boxes to constantly tumble down into the 'stirrer' we see a continuous mixing effect. // // After calculating the correct position and orientation for our object we need to place it there. This can we // done with the help of some methods in the hkpKeyFrameUtility class. However, before we outline the required // method a brief description of so-called 'hard' and 'soft' keyframes would be useful. // A 'hard' keyframe allows for no 'give' in trying to get to the next keyframe. The velocity // will be set to absolutely ensure the next keyframe will be reached after the next timestep, // no matter where the body currently is (and no matter what other bodies it may collide with). // The alternative is a 'soft' keyframe, where the velocity is based on how far the body // currently is from both the last and next keyframes, and will not ensure the keyframes // are always reached. hkpKeyFrameUtility::applyHardKeyFrame(pos, rot, 1.0f / m_timestep, m_keyframedBody); // Once we have keyframed our object all that remains to do is step the simulation: m_world->unlock(); } hkDefaultPhysicsDemo::stepDemo(); { m_world->lock(); // At this point the keyframed body will have transform equal to (pos,rot) m_time += m_timestep; m_world->unlock(); } return DEMO_OK; }
bool DemoKeeper::demoLoop( const Ogre::FrameEvent& evt ) { mWorld->markForWrite(); // //running demo loop accordingly // if (Keyframe_demoRunning) { hkVector4 pos; hkQuaternion rot; getKeyframePositionAndRotation(m_time + evt.timeSinceLastFrame, pos, rot); hkpKeyFrameUtility::applyHardKeyFrame(pos, rot, 1.0f /evt.timeSinceLastFrame, m_keyframedBody); m_time += evt.timeSinceLastFrame; } else if (binaryaction_demoRunning) { hkVector4 pos1 = m_boxRigidBody1->getPosition(); hkVector4 pos2 = m_boxRigidBody2->getPosition(); hkVector4 lenVec; lenVec.setSub4(pos1, pos2); manual_spring = mSceneMgr->createManualObject(); manual_spring->setQueryFlags(0); manual_spring->begin( "BaseWhiteNoLighting", Ogre::RenderOperation::OT_LINE_LIST); manual_spring->position(pos1(0),pos1(1),pos1(2)); if (lenVec.length3() > m_springAction->getRestLength()) { // Line is red if the spring is stretched. manual_spring->colour(1,0,0); } else { // Line is blue is spring is at rest or compressed. manual_spring->colour(0,0,1); } manual_spring->position(pos2(0),pos2(1),pos2(2)); manual_spring->end(); springNode->detachAllObjects(); springNode->attachObject(manual_spring); } mWorld->unmarkForWrite(); return true; }
KeyframingDemo::KeyframingDemo(hkDemoEnvironment* env) : hkDefaultPhysicsDemo(env) { // // Set parameters for keyframes, and number of bodies // m_speed = 0.2f; m_radius = 5.0f; m_numBodies = 15; m_time = 0.0f; // // Setup the camera // { hkVector4 from(0, 40, 40); hkVector4 to(0, 0, 0); hkVector4 up(0, 1, 0); setupDefaultCameras(env, from, to, up); } // // Setup and create the hkpWorld. // { hkpWorldCinfo info; info.m_gravity = hkVector4(0.0f, -9.8f, 0.0f); info.setBroadPhaseWorldSize(150.0f); info.setupSolverInfo(hkpWorldCinfo::SOLVER_TYPE_4ITERS_MEDIUM); m_world = new hkpWorld( info ); m_world->lock(); setupGraphics(); } // // Register the single agent required (a hkpBoxBoxAgent). // { hkpAgentRegisterUtil::registerAllAgents(m_world->getCollisionDispatcher()); } // // Create the rigid bodies. // createBodies(); // // Create the ground. // createGround(); // // Create the keyframed body. // { const hkVector4 halfExtents(3.0f, 1.75f, 0.3f); hkpBoxShape* shape = new hkpBoxShape(halfExtents, 0 ); // Assign the rigid body properties hkpRigidBodyCinfo bodyInfo; bodyInfo.m_shape = shape; // By setting the motion type to hkpMotion::MOTION_KEYFRAMED we are essentially telling Havok that this // body has infinite mass. Thus neither applying forces nor impulses can change the velocity of the body and // as a result, the body is considered totally immovable during interactions (collisions) with other bodies. // This means that the user can force the body to follow a set of keyframes by directly setting the // velocity required to move to the next keyframe before each world step. // The body is guaranteed to reach the next keyframe, even if other bodies collide with it. // To help convert keyframes to velocities we have provided some useful methods in hkpKeyFrameUtility. // To create a keyframed object simply set the motion type as follows: bodyInfo.m_motionType = hkpMotion::MOTION_KEYFRAMED; { // Get inital keyframe. getKeyframePositionAndRotation(0.0f, bodyInfo.m_position, bodyInfo.m_rotation); } // Add our keyframed body. m_keyframedBody = new hkpRigidBody(bodyInfo); m_world->addEntity(m_keyframedBody); m_keyframedBody->removeReference(); shape->removeReference(); } m_world->unlock(); }
void DemoKeeper::KeyframingDemo( void ) { mWorld->markForWrite(); // // Set parameters for keyframes, and number of bodies // m_speed = 0.2f; m_radius = 5.0f; m_numBodies = 15; m_time = 0.0f; // // Create the rigid bodies. // createBodies(); // // Create the ground. // createGround(); // // Create the keyframed body. // { const hkVector4 halfExtents(3.0f, 1.75f, 0.3f); hkpBoxShape* shape = new hkpBoxShape(halfExtents, 0 ); // Assign the rigid body properties hkpRigidBodyCinfo bodyInfo; bodyInfo.m_shape = shape; // By setting the motion type to hkpMotion::MOTION_KEYFRAMED we are essentially telling Havok that this // body has infinite mass. Thus neither applying forces nor impulses can change the velocity of the body and // as a result, the body is considered totally immovable during interactions (collisions) with other bodies. // This means that the user can force the body to follow a set of keyframes by directly setting the // velocity required to move to the next keyframe before each world step. // The body is guaranteed to reach the next keyframe, even if other bodies collide with it. // To help convert keyframes to velocities we have provided some useful methods in hkpKeyFrameUtility. // To create a keyframed object simply set the motion type as follows: bodyInfo.m_motionType = hkpMotion::MOTION_KEYFRAMED; { // Get inital keyframe. getKeyframePositionAndRotation(0.0f, bodyInfo.m_position, bodyInfo.m_rotation); } // Add our keyframed body. m_keyframedBody = new hkpRigidBody(bodyInfo); mWorld->addEntity(m_keyframedBody); m_keyframedBody->removeReference(); shape->removeReference(); //render it with Ogre Ogre::SceneNode* boxNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); //scale boxNode->scale(6, 3.5, 0.6); //display and sync Ogre::Entity *ent = mSceneMgr->createEntity(Ogre::StringConverter::toString(mLabMgr->getEntityCount()),"defCube.mesh"); mLabMgr->setColor(ent, Ogre::Vector3(rand()/(double)RAND_MAX,rand()/(double)RAND_MAX,rand()/(double)RAND_MAX)); HkOgre::Renderable* rend = new HkOgre::Renderable(boxNode, m_keyframedBody,mWorld); boxNode->attachObject(ent); //register to lab manager mLabMgr->registerEnity( boxNode, m_keyframedBody); } mWorld->unmarkForWrite(); Keyframe_demoRunning = true; }