hkDemo::Result HardwareSkinningDemo::stepDemo() { // Advance the active animations if (m_canSkin) { m_skeletonInstance->stepDeltaTime( .016f ); hkaPose pose (m_skeleton); // Sample the active animations and combine into a single pose m_skeletonInstance->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); // Grab the pose in model space const hkArray<hkQsTransform>& poseModelSpace = pose.getSyncedPoseModelSpace(); const int numSkins = m_numSkinBindings; for (int i=0; i < numSkins; i++) { const hkxMesh* inputMesh = m_skinBindings[i]->m_mesh; int numBones = m_skinBindings[i]->m_numBoneFromSkinMeshTransforms; // Compute the skinning matrix palette hkLocalArray<hkTransform> compositeWorldInverse( numBones ); compositeWorldInverse.setSize( numBones ); // Multiply through by the bind pose inverse world inverse matrices, according to the skel to mesh bone mapping for (int p=0; p < numBones; p++) { compositeWorldInverse[p].setMul( poseModelSpace[ p ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ p ] ); } // reflect the matrices in the palette used by the shader m_env->m_sceneConverter->updateSkin( inputMesh, compositeWorldInverse, hkTransform::getIdentity() ); } } return hkDemo::DEMO_OK; }
hkDemo::Result MotionExtractionDemo::stepDemo() { static hkReal val = 0.0f; hkReal stickX = m_env->m_gamePad->getStickPosX(1); val += (stickX - val) * 0.3f; hkReal leftWeight = (val < 0) ? -val : 0; hkReal rightWeight = (val > 0) ? val : 0; m_control[1]->setMasterWeight( leftWeight ); m_control[2]->setMasterWeight( rightWeight ); // Grab accumulated motion { hkQsTransform deltaMotion; deltaMotion.setIdentity(); m_skeletonInstance->getDeltaReferenceFrame( m_timestep, deltaMotion); m_currentMotion.setMulEq(deltaMotion); } // Show the extracted motion for the next 2 seconds const hkReal freq = 60; hkVector4 lp = m_currentMotion.getTranslation(); for (hkReal tm = 0.0f; tm < 2.0f; tm += 1.0f / freq) { hkQsTransform deltaMotion; deltaMotion.setIdentity(); m_skeletonInstance->getDeltaReferenceFrame(tm, deltaMotion); hkVector4 p; p.setTransformedPos(m_currentMotion, deltaMotion.getTranslation()); HK_DISPLAY_LINE( lp, p, 0xffff0f0f); lp = p; } // Advance the active animations m_skeletonInstance->stepDeltaTime( m_timestep ); hkaPose pose (m_skeleton); // Sample the active animations and combine into a single pose m_skeletonInstance->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); AnimationUtils::drawPose( pose, hkQsTransform::getIdentity() ); // Skin { // Work with the pose in Model space const hkArray<hkQsTransform>& poseInWorld = pose.getSyncedPoseModelSpace(); // Construct the composite world transform const int boneCount = m_skeleton->m_numBones; hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); // Convert accumlated info to graphics matrix hkTransform graphicsTransform; m_currentMotion.copyToTransform(graphicsTransform); // Skin the meshes 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 : boneCount; // 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( poseInWorld[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, graphicsTransform, compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } } return hkDemo::DEMO_OK; }
hkDemo::Result LookAtDemo::stepDemo() { // Advance the active animations m_skeletonInstance->stepDeltaTime( 0.016f ); int boneCount = m_skeleton->m_numBones; hkaPose pose (m_skeleton); // Sample the active animations and combine into a single pose m_skeletonInstance->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); // m_targetPosition is similar to camera hkVector4 newTargetPosition; m_env->m_window->getCurrentViewport()->getCamera()->getFrom((float*)&newTargetPosition); hkaLookAtIkSolver::Setup setup; setup.m_fwdLS.set(0,1,0); setup.m_eyePositionLS.set(0.1f,0.1f,0); setup.m_limitAxisMS.setRotatedDir(pose.getBoneModelSpace(m_neckIndex).getRotation(), hkVector4(0,1,0)); setup.m_limitAngle = HK_REAL_PI / 3.0f; // Check if the angle-limited variant is in use if ( m_variantId == 0 ) { // Solve normally hkaLookAtIkSolver::solve (setup, newTargetPosition, 1.0f, pose.accessBoneModelSpace(m_headIndex, hkaPose::PROPAGATE), HK_NULL ); } else { // Define the range of motion hkaLookAtIkSolver::RangeLimits range; range.m_limitAngleLeft = 90.0f * HK_REAL_DEG_TO_RAD; range.m_limitAngleRight = -90.0f * HK_REAL_DEG_TO_RAD; range.m_limitAngleUp = 30.0f * HK_REAL_DEG_TO_RAD; range.m_limitAngleDown = -10.0f * HK_REAL_DEG_TO_RAD; hkVector4 upLS; upLS.set(1,0,0); range.m_upAxisMS.setRotatedDir(pose.getBoneModelSpace(m_neckIndex).getRotation(), upLS); // Solve using user-defined range of motion hkaLookAtIkSolver::solve (setup, newTargetPosition, 1.0f, pose.accessBoneModelSpace(m_headIndex, hkaPose::PROPAGATE), &range ); } setup.m_fwdLS.set(0,-1,0); setup.m_eyePositionLS.set(0.0f,0.0f,0); setup.m_limitAxisMS.setRotatedDir(pose.getBoneModelSpace(m_headIndex).getRotation(), hkVector4(0,1,0)); setup.m_limitAngle = HK_REAL_PI / 10.0f; hkaLookAtIkSolver::solve (setup, newTargetPosition, 1.0f, pose.accessBoneModelSpace(m_rEyeIndex, hkaPose::PROPAGATE)); setup.m_fwdLS.set(0,-1,0); setup.m_eyePositionLS.set(0.0f,0.0f,0); setup.m_limitAxisMS.setRotatedDir(pose.getBoneModelSpace(m_headIndex).getRotation(), hkVector4(0,1,0)); setup.m_limitAngle = HK_REAL_PI / 10.0f; hkaLookAtIkSolver::solve (setup, newTargetPosition, 1.0f, pose.accessBoneModelSpace(m_lEyeIndex, hkaPose::PROPAGATE)); // // draw the skeleton pose // AnimationUtils::drawPose( pose, hkQsTransform::getIdentity() ); // Skin { // Work with the pose in world const hkArray<hkQsTransform>& poseInWorld = pose.getSyncedPoseModelSpace(); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); // Skin the meshes 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 : boneCount; // 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( poseInWorld[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, hkTransform::getIdentity(), compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } } // Move the attachments { HK_ALIGN(float f[16], 16); for (int a=0; a < m_numAttachments; a++) { if (m_attachmentObjects[a]) { hkaBoneAttachment* ba = m_attachments[a]; pose.getBoneModelSpace( ba->m_boneIndex ).get4x4ColumnMajor(f); hkMatrix4 worldFromBone; worldFromBone.set4x4ColumnMajor(f); hkMatrix4 worldFromAttachment; worldFromAttachment.setMul(worldFromBone, ba->m_boneFromAttachment); m_env->m_sceneConverter->updateAttachment(m_attachmentObjects[a], worldFromAttachment); } } } return hkDemo::DEMO_OK; }
hkDemo::Result NormalBlendingDemo::stepDemo() { hkReal runWeight = m_control[HK_RUN_ANIM]->getMasterWeight(); // Update input { const hkReal inc = 0.01f; const hkgPad* pad = m_env->m_gamePad; if ((pad->getButtonState() & HKG_PAD_DPAD_UP) != 0) runWeight+=inc; if ((pad->getButtonState() & HKG_PAD_DPAD_DOWN) != 0) runWeight-=inc; runWeight = hkMath::min2(runWeight, 1.0f); runWeight = hkMath::max2(runWeight, 0.0f); } const hkReal walkWeight = 1.0f - runWeight; // Set the animation weights { m_control[HK_RUN_ANIM]->setMasterWeight( runWeight ); m_control[HK_WALK_ANIM]->setMasterWeight( walkWeight ); } // Sync playback speeds { const hkReal runPeriod = m_control[HK_RUN_ANIM]->getAnimationBinding()->m_animation->m_duration; const hkReal walkPeriod = m_control[HK_WALK_ANIM]->getAnimationBinding()->m_animation->m_duration; const hkReal totalW = runWeight+walkWeight+1e-6f; const hkReal walkP = walkWeight / totalW; const hkReal runP = runWeight / totalW; const hkReal runWalkRatio = runPeriod / walkPeriod; m_control[HK_RUN_ANIM]->setPlaybackSpeed( (1-runP) * runWalkRatio + runP ); m_control[HK_WALK_ANIM]->setPlaybackSpeed( (1-walkP) * (1.0f / runWalkRatio) + walkP ); } // Show blend ratio { char buf[255]; hkString::sprintf(buf, "run:%0.3f walk:%0.3f", runWeight, walkWeight); 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( m_timestep ); 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() ); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); const hkArray<hkQsTransform>& poseInWorld = pose.getSyncedPoseModelSpace(); // Skin the meshes 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 : boneCount; // 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( poseInWorld[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, hkTransform::getIdentity(), compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } return hkDemo::DEMO_OK; }
hkDemo::Result EaseCurvesDemo::stepDemo() { // Display current settings { char buf[255]; for (int i=0; i< NUM_ANIMS; i++) { hkString::sprintf(buf, "anim%d:%0.3f", i, m_control[i]->getWeight()); m_env->m_textDisplay->outputText( buf, 10, 240+14*i, curveCols[i], 1); } } // Check user input { for (int i=0; i < 3; i++) { if (m_env->m_gamePad->wasButtonPressed( 1 << (i+1) )) { if (( m_control[i]->getEaseStatus() == hkaDefaultAnimationControl::EASING_IN ) || ( m_control[i]->getEaseStatus() == hkaDefaultAnimationControl::EASED_IN )) { m_control[i]->easeOut( 1.0f ); } else { m_control[i]->easeIn( 1.0f ); } } } } const int boneCount = m_skeleton->m_numBones; // Advance the active animations m_skeletonInstance->stepDeltaTime( 1.0f / 60.0f ); // 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() ); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); const hkArray<hkQsTransform>& poseModelSpace = pose.getSyncedPoseModelSpace(); // Skin the meshes 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 : boneCount; // 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, hkTransform::getIdentity(), compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } // Show curves { int* data = reinterpret_cast<int*>(m_texture->getDataPointer()); //Shuffle Texture for (int w=0; w< GRAPH_CANVAS_WIDTH-1; w++) { for (int h=0; h< GRAPH_CANVAS_HEIGHT; h++) { data[h * GRAPH_CANVAS_WIDTH + w] = data[h * GRAPH_CANVAS_WIDTH + w+1]; } } // Clear the line for (int h=0; h< GRAPH_CANVAS_HEIGHT; h++) { data[h * GRAPH_CANVAS_WIDTH + GRAPH_CANVAS_WIDTH-1] = 0xff7f7f7f; } // Take a new sample for (int c=0; c< 3; c++) { int y = (int)(m_control[c]->getWeight() * (GRAPH_CANVAS_HEIGHT-5)); data[(GRAPH_CANVAS_HEIGHT-2 - (y+c+1)) * GRAPH_CANVAS_WIDTH + GRAPH_CANVAS_WIDTH-1] = curveCols[c]; data[(GRAPH_CANVAS_HEIGHT-2 - (y+c)) * GRAPH_CANVAS_WIDTH + GRAPH_CANVAS_WIDTH-1] &= 0xff0f0f0f; } } m_context->lock(); if (m_textureRealized) { m_texture->free(); } m_texture->realize(true); m_textureRealized = true; drawTexture( m_texture ); m_context->unlock(); return hkDemo::DEMO_OK; }
hkDemo::Result MirroredMotionDemo::stepDemo() { // Check user input { if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_1 )) { for ( int i = 0; i < 2; i++ ) { if (( m_control[i]->getEaseStatus() == hkaDefaultAnimationControl::EASING_IN ) || ( m_control[i]->getEaseStatus() == hkaDefaultAnimationControl::EASED_IN )) { m_control[i]->easeOut( .5f ); } else { m_control[i]->easeIn( .5f ); } } } if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_2 )) { m_wireframe = !m_wireframe; setGraphicsState( HKG_ENABLED_WIREFRAME, m_wireframe ); } if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_3 )) { m_drawSkin = !m_drawSkin; } if ( m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_0 ) ) { m_useExtractedMotion = !m_useExtractedMotion; } if ( m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_L1 ) ) { m_accumulatedMotion[0].setIdentity(); m_accumulatedMotion[1].setIdentity(); } if ( m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_R1 ) ) { m_paused = !m_paused; if ( m_paused ) { m_timestep = 0; } else { m_timestep = 1.0f / 60.0f; } } } const int boneCount = m_skeleton->m_numBones; for ( int j = 0; j < 2; j++ ) { // Grab accumulated motion { hkQsTransform deltaMotion; deltaMotion.setIdentity(); m_skeletonInstance[j]->getDeltaReferenceFrame( m_timestep, deltaMotion ); m_accumulatedMotion[j].setMulEq( deltaMotion ); } // Advance the active animations m_skeletonInstance[j]->stepDeltaTime( m_timestep ); // Sample the active animations and combine into a single pose hkaPose pose (m_skeleton); m_skeletonInstance[j]->sampleAndCombineAnimations( pose.accessUnsyncedPoseLocalSpace().begin(), pose.getFloatSlotValues().begin() ); hkReal separation = m_separation * hkReal( 2*j-1 ); hkQsTransform Q( hkQsTransform::IDENTITY ); Q.m_translation.set( separation, 0, 0 ); if ( m_useExtractedMotion ) { Q.setMulEq( m_accumulatedMotion[j] ); } pose.syncModelSpace(); AnimationUtils::drawPose( pose, Q ); // Test if the skin is to be drawn if ( !m_drawSkin ) { Q.m_translation( 2 ) -= 2.0f * m_separation; } // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); const hkArray<hkQsTransform>& poseModelSpace = pose.getSyncedPoseModelSpace(); // Skin the meshes for (int i=0; i < m_numSkinBindings[j]; i++) { // assumes either a straight map (null map) or a single one (1 palette) hkInt16* usedBones = m_skinBindings[j][i]->m_mappings? m_skinBindings[j][i]->m_mappings[0].m_mapping : HK_NULL; int numUsedBones = usedBones? m_skinBindings[j][i]->m_mappings[0].m_numMapping : boneCount; // Multiply through by the bind pose inverse world inverse matrices for (int p=0; p < numUsedBones; p++) { int boneIndex = usedBones? usedBones[p] : p; hkTransform tWorld; poseModelSpace[ boneIndex ].copyToTransform(tWorld); compositeWorldInverse[p].setMul( tWorld, m_skinBindings[j][i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[j][i]->m_mesh, hkTransform( Q.m_rotation, hkVector4( Q.m_translation(0), Q.m_translation(1), Q.m_translation(2), 1 ) ), compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } // Move the attachments { HK_ALIGN(float f[16], 16); for (int a=0; a < m_numAttachments[j]; a++) { if (m_attachmentObjects[j][a]) { hkaBoneAttachment* ba = m_attachments[j][a]; hkQsTransform modelFromBone = pose.getBoneModelSpace( ba->m_boneIndex ); hkQsTransform worldFromBoneQs; worldFromBoneQs.setMul( Q, modelFromBone ); worldFromBoneQs.get4x4ColumnMajor(f); hkMatrix4 worldFromBone; worldFromBone.set4x4ColumnMajor(f); hkMatrix4 worldFromAttachment; worldFromAttachment.setMul(worldFromBone, ba->m_boneFromAttachment); m_env->m_sceneConverter->updateAttachment(m_attachmentObjects[j][a], worldFromAttachment); } } } } return hkDemo::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 BasicMovementDemo::stepDemo() { // for PlayStation(R)2 metrowerks pushDoubleConversionCheck( false ); // Display current settings { char buf[255]; for (int i=0; i< NUM_ANIMS; i++) { hkString::sprintf(buf, "anim%d: %0.3f", i, m_control[i]->getWeight()); const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText( buf, 20, h-70+16*i, curveCols[i], 1); } } popDoubleConversionCheck(); // Handle the keys { bool jumping = (m_control[1]->getWeight() > 0.001f); if (!jumping) { hkVector4 upVec(0,0,1); hkReal up, turn; up = m_env->m_gamePad->getStickPosY( 1 ); // 1 is the only one on PSP const hkBool upPressed = (up > 0.0f); const hkBool easeIn = (m_control[0]->getEaseStatus() == hkaDefaultAnimationControl::EASING_IN ) || ( m_control[0]->getEaseStatus() == hkaDefaultAnimationControl::EASED_IN ); if ( easeIn && ( !upPressed )) { // Ease in stand m_control[0]->easeOut( 0.9f ); } else if (( !easeIn ) && upPressed ) { // Ease in walk cycle m_control[0]->easeIn( 0.9f ); } turn = m_env->m_gamePad->getStickPosX(1); turn *= -5.0f * HK_REAL_PI / 180.0f * m_control[0]->getWeight(); hkQuaternion q; q.setAxisAngle(upVec, turn); m_currentMotion.m_rotation.mul(q); } else { hkReal remaining = m_control[1]->getAnimationBinding()->m_animation->m_duration - m_control[1]->getLocalTime(); // If we've played through then fade out const hkBool easeIn = (m_control[1]->getEaseStatus() == hkaDefaultAnimationControl::EASING_IN ) || ( m_control[1]->getEaseStatus() == hkaDefaultAnimationControl::EASED_IN ); if ( easeIn && (remaining < 0.2f)) { m_control[1]->easeOut( remaining ); m_control[0]->setLocalTime( m_control[0]->getAnimationBinding()->m_animation->m_duration - remaining ); m_control[0]->easeIn( remaining ); } } if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_2) && !jumping) { // Reset jump animation and play m_control[1]->setLocalTime(0.0f); m_control[1]->easeIn( 0.1f ); m_control[0]->easeOut( 0.1f ); } if (m_env->m_gamePad->wasButtonPressed( HKG_PAD_BUTTON_1)) { m_currentMotion.setIdentity(); } } // Grab accumulated motion { hkQsTransform deltaMotion; deltaMotion.setIdentity(); m_skeletonInstance->getDeltaReferenceFrame( m_timestep, deltaMotion); hkQsTransform temp; temp.setMul(m_currentMotion, deltaMotion); m_currentMotion = temp; } const int boneCount = m_skeleton->m_numBones; // Advance the active animations m_skeletonInstance->stepDeltaTime( 1.0f / 60.0f ); // 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() ); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); // Convert accumlated info to graphics matrix hkTransform graphicsTransform; m_currentMotion.copyToTransform(graphicsTransform); // Skin the meshes { const hkArray<hkQsTransform>& poseInWorld = pose.getSyncedPoseModelSpace(); 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 : boneCount; // 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( poseInWorld[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, graphicsTransform, compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } } return hkDemo::DEMO_OK; }
hkDemo::Result AdditiveBlendingDemo::stepDemo() { hkReal w1 = m_control[HK_ADDITIVE_ANIM]->getMasterWeight(); // Update input { 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_DOWN) != 0) w1-=inc; w1 = hkMath::min2(w1, 1.0f); w1 = hkMath::max2(w1, 0.0f); } // Set the additive animation weight { m_control[HK_ADDITIVE_ANIM]->setMasterWeight( w1 ); } // Show animation weight { char buf[255]; hkString::sprintf( buf, "weight:%0.3f", w1 ); const int h = m_env->m_window->getHeight(); m_env->m_textDisplay->outputText( buf, 20, h-40, 0xffffffff, 1); } // Advance the active controls m_skeletonInstance->stepDeltaTime( m_timestep ); 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() ); // Construct the composite world transform hkLocalArray<hkTransform> compositeWorldInverse( boneCount ); compositeWorldInverse.setSize( boneCount ); const hkArray<hkQsTransform>& poseInWorld = pose.getSyncedPoseModelSpace(); // Skin the meshes 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 : boneCount; // 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( poseInWorld[ boneIndex ], m_skinBindings[i]->m_boneFromSkinMeshTransforms[ boneIndex ] ); } AnimationUtils::skinMesh( *m_skinBindings[i]->m_mesh, hkTransform::getIdentity(), compositeWorldInverse.begin(), *m_env->m_sceneConverter ); } // Move the attachments { HK_ALIGN(float f[16], 16); for (int a=0; a < m_numAttachments; a++) { if (m_attachmentObjects[a]) { hkaBoneAttachment* ba = m_attachments[a]; pose.getBoneModelSpace( ba->m_boneIndex ).get4x4ColumnMajor(f); hkMatrix4 worldFromBone; worldFromBone.set4x4ColumnMajor(f); hkMatrix4 worldFromAttachment; worldFromAttachment.setMul(worldFromBone, ba->m_boneFromAttachment); m_env->m_sceneConverter->updateAttachment(m_attachmentObjects[a], worldFromAttachment); } } } return hkDemo::DEMO_OK; }