hkDemo::Result ControlDemo::stepDemo() { hkaPose pose (m_skeleton); // Advance the active animations for (int i=0; i < HK_NUM_CHARACTERS; i++) { m_skeletonInstance[i]->stepDeltaTime( m_timestep ); // Sample the active animations and combine into a single pose m_skeletonInstance[i]->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); hkQsTransform worldFromModel (hkQsTransform::IDENTITY); worldFromModel.m_translation.set(0, i*2-4.0f ,0); AnimationUtils::drawPose( pose, worldFromModel, 0xffff0000 ); } // all animations //draw the text for (int t=0; t < HK_NUM_CHARACTERS; t++) { hkString txt(description[t]); m_env->m_textDisplay->outputText3D( txt, 0, t*2-4.0f ,-1, 0xffffffff, 1); } // Destroy the controls after a period of time { static int countdown = 2000; countdown--; if (countdown == 0) { for (int i=0; i < HK_NUM_CHARACTERS; i++) { m_control[i]->removeReference(); } } } return hkDemo::DEMO_OK; }
hkDemo::Result SkeletonMappingDemo::stepDemo() { // Advance the animation of both a high-res and low-res animated skeletons m_highAnimatedSkeleton->stepDeltaTime( m_timestep ); m_lowAnimatedSkeleton->stepDeltaTime ( m_timestep ); // HIGH LOW HIGH { // Transform used for display hkQsTransform worldFromModel (hkQsTransform::IDENTITY ); // Get a high-res pose from the high resolution animated skeleton hkaPose poseHigh (m_highSkeleton); m_highAnimatedSkeleton->sampleAndCombineAnimations( poseHigh.accessUnsyncedPoseLocalSpace().begin(), poseHigh.getFloatSlotValues().begin()); // Draw the high res pose AnimationUtils::drawPose( poseHigh, worldFromModel, 0x7fffffff); // Construct a low-res pose in the reference pose hkaPose poseLow (m_lowSkeleton); poseLow.setToReferencePose(); // Map the high-res pos into the low-res pose m_highToLowMapper->mapPose(poseHigh, poseLow, hkaSkeletonMapper::CURRENT_POSE); // Draw the low res pose worldFromModel.m_translation.set(20,0,0); AnimationUtils::drawPose( poseLow, worldFromModel, 0x7f00ff00 ); // Now, map the los-res pos back to the high-res pose m_lowToHighMapper->mapPose( poseLow, poseHigh, hkaSkeletonMapper::CURRENT_POSE); // Draw the high res pose worldFromModel.m_translation.set(40,0,0); AnimationUtils::drawPose( poseHigh, worldFromModel, 0x7fffffff ); } // LOW HIGH LOW { // Transform used for display hkQsTransform worldFromModel (hkQsTransform::IDENTITY); // Get a low-res pose from the low resolution animated skeleton hkaPose poseLow (m_lowSkeleton); m_lowAnimatedSkeleton->sampleAndCombineAnimations( poseLow.accessUnsyncedPoseLocalSpace().begin(), poseLow.getFloatSlotValues().begin() ); // Draw the low-res pose worldFromModel.m_translation.set(0, 0, 90); AnimationUtils::drawPose( poseLow, worldFromModel, 0x7f00ff00); // Construct a high-res pose in the reference pose hkaPose poseHigh (m_highSkeleton); poseHigh.setToReferencePose(); // Map the low-res pos to the high-res m_lowToHighMapper->mapPose(poseLow, poseHigh, hkaSkeletonMapper::CURRENT_POSE); // Draw it worldFromModel.m_translation.set(20,0,90); AnimationUtils::drawPose( poseHigh, worldFromModel, 0x7fffffff ); // Now, map the high-res pose back to the low-res pose m_highToLowMapper->mapPose(poseHigh, poseLow, hkaSkeletonMapper::CURRENT_POSE); // And draw the low-res pose worldFromModel.m_translation.set(40,0,90); AnimationUtils::drawPose( poseLow, worldFromModel, 0x7f00ff00 ); } return DEMO_OK; }
hkDemo::Result RagdollScalingDemo::stepDemo() { // Handle button presses... hkReal& oldScale = m_scale; hkReal newScale = oldScale; static const hkReal slowFactor = hkMath::pow( 2.0f, 1.0f / 100.0f ); static const hkReal fastFactor = hkMath::pow( 2.0f, 1.0f / 10.0f ); if ( m_env->m_gamePad->isButtonPressed( HKG_PAD_DPAD_UP ) ) { newScale *= slowFactor; } if ( m_env->m_gamePad->isButtonPressed( HKG_PAD_DPAD_DOWN ) ) { newScale /= slowFactor; } if ( m_env->m_gamePad->wasButtonPressed( HKG_PAD_DPAD_RIGHT ) ) { newScale *= fastFactor; } if ( m_env->m_gamePad->wasButtonPressed( HKG_PAD_DPAD_LEFT ) ) { newScale /= fastFactor; } // Test if the user has requested scaling if ( newScale != oldScale ) { const hkReal scale = newScale / oldScale; m_world->lock(); // Use the ragdoll scaling utility m_ragdoll->addReference(); m_ragdoll->removeFromWorld(); hkaRagdollUtils::scaleRagdoll( m_ragdoll, scale ); m_ragdoll->addToWorld( m_world, false ); m_ragdoll->removeReference(); m_world->unlock(); // Scale the skeleton mapper hkaSkeletonMapperUtils::scaleMapping( *m_ragdollFromAnimation, scale ); hkaSkeletonMapperUtils::scaleMapping( *m_animationFromRagdoll, scale ); // Scale the reference poses of the animated and ragdoll characters hkaSampleAndCombineUtils::scaleTranslations( scale, m_ragdollSkeleton->m_referencePose, m_ragdollSkeleton->m_numBones ); hkaSampleAndCombineUtils::scaleTranslations( scale, m_animationSkeleton->m_referencePose, m_animationSkeleton->m_numBones ); // Update the scale value oldScale = newScale; } { // Sample the animation and drive the ragdolls to the desired pose hkaPose animationPose( m_animationSkeleton ); hkaPose ragdollPose( m_ragdollSkeleton ); hkaPose upsampledPose( m_animationSkeleton ); // Sample the character's current animated pose m_character->sampleAndCombineAnimations( animationPose.accessUnsyncedPoseLocalSpace().begin(), HK_NULL ); // Scale the bone lengths of the poses hkaSampleAndCombineUtils::scaleTranslations( m_scale, ragdollPose.accessUnsyncedPoseLocalSpace().begin(), m_ragdollSkeleton->m_numBones ); hkaSampleAndCombineUtils::scaleTranslations( m_scale, animationPose.accessUnsyncedPoseLocalSpace().begin(), m_animationSkeleton->m_numBones ); // Scale the root (necessary for skinning) animationPose.accessUnsyncedPoseLocalSpace()[ 0 ].m_scale.mul4( m_scale ); // Convert the animation pose to a ragdoll pose m_ragdollFromAnimation->mapPose( animationPose.getSyncedPoseModelSpace().begin(), m_ragdollSkeleton->m_referencePose, ragdollPose.accessUnsyncedPoseModelSpace().begin(), hkaSkeletonMapper::CURRENT_POSE ); // Map the ragdoll pose back to an animation pose m_animationFromRagdoll->mapPose( ragdollPose.getSyncedPoseModelSpace().begin(), m_animationSkeleton->m_referencePose, upsampledPose.accessUnsyncedPoseModelSpace().begin(), hkaSkeletonMapper::CURRENT_POSE ); // Copy the scales back into the upsampled pose hkaRagdollUtils::copyScales( upsampledPose.accessUnsyncedPoseModelSpace().begin(), animationPose.getSyncedPoseModelSpace().begin(), m_animationSkeleton->m_numBones ); // Draw the upsampled Pose { hkQsTransform animWorldFromModel( m_worldFromModel ); animWorldFromModel.m_translation( 0 ) = -1.0f; AnimationUtils::drawPose( upsampledPose, animWorldFromModel ); } // Skin the animation { hkTransform worldFromModel( m_worldFromModel.m_rotation, m_worldFromModel.m_translation ); worldFromModel.getTranslation()( 0 ) = 1.0f; const hkQsTransform* poseModelSpace = upsampledPose.getSyncedPoseModelSpace().begin(); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( m_animationSkeleton->m_numBones ); compositeWorldInverse.setSize( m_animationSkeleton->m_numBones ); for ( int i = 0; i < m_numSkinBindings; i++ ) { // assumes either a straight map (null map) or a single one (1 palette) hkInt16* usedBones = m_skinBindings[i]->m_mappings? m_skinBindings[i]->m_mappings[0].m_mapping : HK_NULL; int numUsedBones = usedBones? m_skinBindings[i]->m_mappings[0].m_numMapping : m_animationSkeleton->m_numBones; // Multiply through by the bind pose inverse world inverse matrices for (int p=0; p < numUsedBones; p++) { int boneIndex = usedBones? usedBones[p] : p; compositeWorldInverse[p].setMul( poseModelSpace[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, worldFromModel, compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } } m_world->lock(); m_ragdollRigidBodyController->driveToPose( m_timestep, ragdollPose.accessSyncedPoseLocalSpace().begin(), m_worldFromModel, HK_NULL ); m_world->unlock(); // Step the animation m_character->stepDeltaTime( m_timestep ); } // Print the current scale factor { char buf[ 255 ]; hkString::sprintf(buf, "Scale: %.3f", m_scale ); const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText( buf, 20, h-40, 0xffffffff, 1); } // Step the physics hkDefaultPhysicsDemo::stepDemo(); return DEMO_OK; // original animation demo return }
hkDemo::Result BindingDemo::stepDemo() { hkReal w1 = m_control[0]->getMasterWeight(); hkReal w2 = m_control[1]->getMasterWeight(); const hkReal inc = 0.01f; { const hkgPad* pad = m_env->m_gamePad; if ((pad->getButtonState() & HKG_PAD_DPAD_UP) != 0) w1+=inc; if ((pad->getButtonState() & HKG_PAD_DPAD_LEFT) != 0) w2+=inc; if ((pad->getButtonState() & HKG_PAD_DPAD_RIGHT) != 0) w2-=inc; if ((pad->getButtonState() & HKG_PAD_DPAD_DOWN) != 0) w1-=inc; //clamp w1 = (w1 > 1) ? 1 : w1; w1 = (w1 < 0) ? 0 : w1; w2 = (w2 > 1) ? 1 : w2; w2 = (w2 < 0) ? 0 : w2; } m_control[0]->setMasterWeight( w1 ); m_control[1]->setMasterWeight( w2 ); char buf[255]; hkString::sprintf(buf, "wave weight :%0.3f idle weight:%0.3f fill thresh:%0.3f", w2, w1, m_skeletonInstance->getReferencePoseWeightThreshold()); const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText( buf, 20, h-40, 0xffffffff, 1); // Advance the active animations m_skeletonInstance->stepDeltaTime( .016f ); const int boneCount = m_skeleton->m_numBones; // Sample the active animations and combine into a single pose hkaPose pose (m_skeleton); m_skeletonInstance->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); AnimationUtils::drawPose( pose, hkQsTransform::getIdentity(), 0xffff0000 ); hkLocalArray<hkQsTransform> trackSample(boneCount); trackSample.setSizeUnchecked(boneCount); for (int i=0; i < NUM_ANIMS; i++) { trackSample.setSizeUnchecked( m_control[i]->getAnimationBinding()->m_animation->m_numberOfTransformTracks ); m_binding[i]->m_animation->sampleTracks( m_control[i]->getLocalTime(), trackSample.begin(), HK_NULL , HK_NULL); pose.setToReferencePose(); hkaAnimation* anim = m_binding[i]->m_animation; for (hkInt16 t=0; t < anim->m_numberOfTransformTracks; t++) { hkInt16 boneIdx = m_binding[i]->m_transformTrackToBoneIndices[t]; if (boneIdx !=-1) { pose.setBoneLocalSpace(boneIdx, trackSample[t]); } } hkQsTransform worldFromModel (hkQsTransform::IDENTITY); worldFromModel.m_translation.set(i * 2.0f - 1.0f , 0, 0); hkReal gray = m_control[i]->getMasterWeight() * 0.4f + 0.6f; int color = hkColor::rgbFromFloats( gray, gray, gray ); AnimationUtils::drawPose( pose, worldFromModel, color); } return hkDemo::DEMO_OK; }
hkDemo::Result CompressionDemo::stepDemo() { // Point local arrays on the scratchpad if ( m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_0) ) { m_currentAnimation = (m_currentAnimation-1+m_animationRecords.getSize())%(m_animationRecords.getSize()); hkVector4 at = m_animationRecords[m_currentAnimation]->m_offset; lookAt( at ); } if ( m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_1) ) { m_currentAnimation = (m_currentAnimation+1)%(m_animationRecords.getSize()); hkVector4 at = m_animationRecords[m_currentAnimation]->m_offset; lookAt( at ); } // Turn caching on / off if ( m_env->m_gamePad->wasButtonPressed(HKG_PAD_BUTTON_2) ) { m_useCache = !m_useCache; } // print cache statistics with user input if( m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_3 ) ) { // display message to notify user of cache pool flush char buf[64]; hkString::sprintf( buf, "The cache's statistics have been saved." ); m_env->m_textDisplay->outputText( buf, 20, 180, 0xffffffff, 140); // print cache statistics hkOstream file("cacheStats.txt"); m_cache->printCacheStats( &file ); } hkaPose pose (m_skeleton); for (int i = 0; i < m_animationRecords.getSize(); ++i ) { TestRecord* rec = m_animationRecords[i]; hkaAnimatedSkeleton* inst = rec->m_animatedSkeleton; // Advance the animation rec->m_stopwatch.reset(); rec->m_stopwatch.start(); inst->stepDeltaTime( m_timestep ); // Sample if ( m_useCache ) { inst->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() , m_cache ); // using our cache } else { inst->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); } rec->m_stopwatch.stop(); // Draw hkQsTransform worldFromModel (hkQsTransform::IDENTITY); worldFromModel.m_translation = rec->m_offset; hkUint32 color = (i == m_currentAnimation) ? 0xffff0000 : 0xffffffff; AnimationUtils::drawPose( pose, worldFromModel, color ); const hkReal heightOffset = -1.0f; const hkReal widthOffset = -0.20f; hkString label( rec->m_name ); label.setAsSubstr( 0, label.indexOf( ' ', 0 ) ); hkVector4& textPos = m_animationRecords[i]->m_offset; m_env->m_textDisplay->outputText3D( label, textPos(0) + widthOffset, textPos(1), textPos(2) + heightOffset, 0xffffffff ); } TestRecord* rec = m_animationRecords[m_currentAnimation]; char msg[2048]; hkUint64 ticks = rec->m_stopwatch.getElapsedTicks(); double tpf = double(ticks/rec->m_stopwatch.getNumTimings()); double tpms = double(rec->m_stopwatch.getTicksPerSecond()/1000000); double mspf = tpf / tpms; hkString::sprintf(msg, "%s\nbytes:%d\nratio:%.2f:1\nmicrosecs/f:%f\ncaching:%s", rec->m_name, rec->m_bytes, (hkReal)m_originalSize / rec->m_bytes, mspf, ((m_useCache) ? "enabled" : "disabled") ); const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText( msg, 20, h-100, 0xffffffff); return DEMO_OK; }