void VAnimationEventEffectTrigger::MessageFunction( int iID, INT_PTR iParamA, INT_PTR iParamB ) { IVTransitionEventTrigger::MessageFunction(iID, iParamA, iParamB); #ifdef WIN32 if (iID == VIS_MSG_EDITOR_GETSTANDARDVALUES) { // Get bone names const char *szKey = (const char *)iParamA; if (!strcmp(szKey,"Bone")) { // Check for model and skeleton VisBaseEntity_cl* pEntity = (VisBaseEntity_cl *)m_pOwner; if (pEntity == NULL) return; VDynamicMesh* pMesh = pEntity->GetMesh(); if (pMesh == NULL) return; VisSkeleton_cl *pSkeleton = pMesh->GetSkeleton(); if (pSkeleton == NULL) return; // Fill list with bone names (first entry is empty) VStrList *pDestList = (VStrList*) iParamB; pDestList->AddString(" "); for (int i = 0; i < pSkeleton->GetBoneCount(); i++) pDestList->AddString(pSkeleton->GetBone(i)->m_sBoneName.AsChar()); } } #endif }
void SimpleSkeletalAnimatedObject_cl::LayerTwoAnimations() { // Layer two animations (using a LayerMixer node). We use this to fade-in an upper body animation // on top of a full body animation. The mixer gets the two animation controls as input and generates // the layered result. The animation tree looks as follows: // // - FinalSkeletalResult // - LayerMixerNode // - SkeletalAnimControl (WalkDagger Animation; influences full body) // - SkeletalAnimControl (RunDagger Animation: influences upper body only) // // The weight of the layered upper body animation is set on the mixer instance. // // Create a new AnimConfig instance VDynamicMesh *pMesh = GetMesh(); VisSkeleton_cl *pSkeleton = pMesh->GetSkeleton(); VisAnimFinalSkeletalResult_cl* pFinalSkeletalResult; VisAnimConfig_cl* pConfig = VisAnimConfig_cl::CreateSkeletalConfig(pMesh, &pFinalSkeletalResult); // get skeletal animation sequence VisSkeletalAnimSequence_cl* pAnimSequenceWalkDagger = static_cast<VisSkeletalAnimSequence_cl*>( pMesh->GetSequence("Walk_Dagger", VIS_MODELANIM_SKELETAL)); VisSkeletalAnimSequence_cl* pAnimSequenceDrawDagger = static_cast<VisSkeletalAnimSequence_cl*>( pMesh->GetSequence("Draw_Dagger", VIS_MODELANIM_SKELETAL)); if (pAnimSequenceWalkDagger == NULL || pAnimSequenceDrawDagger == NULL) return; // Create the two animation controls: WalkDagger: full body animation; DrawDagger: upper body animation. // Use a helper function to create the animation controls. VSmartPtr<VisSkeletalAnimControl_cl> spWalkDaggerAnimControl = VisSkeletalAnimControl_cl::Create( pMesh->GetSkeleton(), pAnimSequenceWalkDagger, VANIMCTRL_LOOP|VSKELANIMCTRL_DEFAULTS, 1.0f, true); VSmartPtr<VisSkeletalAnimControl_cl> spDrawDaggerAnimControl = VisSkeletalAnimControl_cl::Create( pMesh->GetSkeleton(), pAnimSequenceDrawDagger, VSKELANIMCTRL_DEFAULTS, 1.0f, true); // create the layer node which layers the two animations m_spLayerMixerNode = new VisAnimLayerMixerNode_cl(pMesh->GetSkeleton()); m_spLayerMixerNode->AddMixerInput(spWalkDaggerAnimControl, 1.0f); int iMixerInputDrawDagger = m_spLayerMixerNode->AddMixerInput(spDrawDaggerAnimControl, 0.0f); // set a per bone weighting list for the DrawDagger (upper body) slot in the mixer. It shall overlay the // upper body of the character and thus only influence the upper body bones. int iBoneCount = pSkeleton->GetBoneCount(); VASSERT(iBoneCount < 256); float fPerBoneWeightingList[256]; memset(fPerBoneWeightingList, 0, sizeof(float)*iBoneCount); pSkeleton->SetBoneWeightRecursive(1.f, pSkeleton->GetBoneIndexByName("skeleton1:Spine"), fPerBoneWeightingList); m_spLayerMixerNode->ApplyPerBoneWeightingMask(iMixerInputDrawDagger, iBoneCount, fPerBoneWeightingList); // finally set the mixer as the root animation node pFinalSkeletalResult->SetSkeletalAnimInput(m_spLayerMixerNode); SetAnimConfig(pConfig); // fade-in the upper body animation //m_spLayerMixerNode->EaseIn(iMixerInputDrawDagger, 0.4f, true); }
void AnimatedWarrior_cl::InitFunction() { SetCastShadows(TRUE); SetupAnimations(); if (!m_bModelValid) return; m_pCharacterController = new vHavokCharacterController(); m_pCharacterController->Initialize(); hkvAlignedBBox bbox; GetMesh()->GetCollisionBoundingBox(bbox); float r = bbox.getSizeX() * 0.5f; m_pCharacterController->Capsule_Radius = r; m_pCharacterController->Character_Top.set(0,0,bbox.m_vMax.z - r); m_pCharacterController->Character_Bottom.set(0,0,bbox.m_vMin.z + r); m_pCharacterController->Max_Slope = 75.0f; if (!m_bEnabled) m_pCharacterController->SetEnabled(FALSE); AddComponent(m_pCharacterController); //// setup animation system // create config VDynamicMesh* pMesh = GetMesh(); VASSERT(pMesh); VisSkeleton_cl* pSkeleton = pMesh->GetSkeleton(); VASSERT(pSkeleton); // create mixer structure, we keep pointers on the mixers to add and remove inputs m_spLayerMixer = new VisAnimLayerMixerNode_cl(pSkeleton); m_pNormalizeMixer = new VisAnimNormalizeMixerNode_cl(pSkeleton); m_spLayerMixer->AddMixerInput(m_pNormalizeMixer, 1.f); //// create per bone weighting list for upper body int iBoneCount = pSkeleton->GetBoneCount(); float* fPerBoneWeightingList = new float[iBoneCount]; memset(fPerBoneWeightingList, 0, sizeof(float)*iBoneCount); // set all bone weights above the spine to 1 pSkeleton->SetBoneWeightRecursive(1.f, pSkeleton->GetBoneIndexByName("skeleton1:Spine"), fPerBoneWeightingList); int iMixerInputIndex = -1; for(int i=0; i<UPPERBODY_CONTROLCOUNT; i++) { m_spUpperBodyControls[i] = new VisSkeletalAnimControl_cl(pSkeleton, VSKELANIMCTRL_DEFAULTS); m_spUpperBodyControls[i]->AddEventListener(this); // we want to receive all events from sequence and control iMixerInputIndex = m_spLayerMixer->AddMixerInput(m_spUpperBodyControls[i], 0.f); m_spLayerMixer->ApplyPerBoneWeightingMask(iMixerInputIndex, iBoneCount, fPerBoneWeightingList); } V_SAFE_DELETE_ARRAY(fPerBoneWeightingList); // set the start animation BlendOverFullBodyAnimation(0.f, ANIMID_IDLE, 1.f, 0.f); SetFullBodyState(m_pFullBodyIdleState[FBSTATETYPE_NORMAL]); SetUpperBodyState(m_pUpperBodyIdleState); // initialize variables for upperbody fadein/fadeout m_eUpperBodyFadeState = FADESTATE_NONE; // setup neck bone for head rotation m_iHeadBoneIndex = pSkeleton->GetBoneIndexByName("skeleton1:Neck"); m_fHeadRotationAngles[0] = 0.f; m_fHeadRotationAngles[1] = 0.f; m_fHeadRotationAngles[2] = 0.f; m_bHeadInMovement = false; // setup the torch hkvVec3 vDummyOrigin; m_pTorch = (AttachedTorch_cl *) Vision::Game.CreateEntity( "AttachedTorch_cl", vDummyOrigin ); HideTorch(); // attach the torch to the bone //hkvVec3 localTranslation(-11.f, -4.5f, 25.f); hkvVec3 localTranslation(-11.f, 5.5f, 0.f); float euler[3] = {90, 0, 185}; hkvQuat localRotation; localRotation.setFromEulerAngles (euler[2], euler[1], euler[0]); // pass as roll, pitch, yaw m_pTorch->Attach(this, "skeleton1:RightHand", localRotation, localTranslation); SetEnabled(true); }
void vHavokBehaviorComponent::OnAfterHavokUpdate() { if( m_character == HK_NULL || m_entityOwner == HK_NULL ) { return; } // Update WFM of skin or override it if ( m_useBehaviorWorldFromModel ) { const hkQsTransform& worldFromModel = m_character->getWorldFromModel(); // Copy the Behavior result into vision hkvMat3 visionRotation; hkvVec3 visionTranslation; vHavokConversionUtils::HkQuatToVisMatrix( worldFromModel.getRotation(), visionRotation ); vHavokConversionUtils::PhysVecToVisVecWorld( worldFromModel.getTranslation(), visionTranslation ); m_entityOwner->SetPosition( visionTranslation ); m_entityOwner->SetRotationMatrix( visionRotation ); } else { // Override Behavior results. // This will currently cause Behavior data being sent to HBT during remote debug to be one frame off. // However, the only other solution with the current APIs is to disable motion accumulation on *all* // Characters. A slight delay/offset in the special case of remote debugging in HBT isn't worth that change. UpdateHavokTransformFromVision(); } if( m_entityOwner->GetMesh() == HK_NULL || m_entityOwner->GetMesh()->GetSkeleton() == HK_NULL ) { return; } VisAnimConfig_cl* animConfig = m_entityOwner->GetAnimConfig(); if( !animConfig ) { return; } VisAnimFinalSkeletalResult_cl* skeletalResult = animConfig->GetFinalResult(); if( !skeletalResult ) { return; } // Try updating the bone index list in case a mesh was added if( m_boneIndexList.getSize() == 0 ) { UpdateAnimationAndBoneIndexList(); // Exit early if there's no bone index list if( m_boneIndexList.getSize() == 0 ) { return; } } // Convert pose to Havok model space const hkQsTransform* poseLocal = m_character->getPoseLocal(); hkArray<hkQsTransform> poseModel( m_character->getNumPoseLocal() ); hkaSkeletonUtils::transformLocalPoseToModelPose( m_character->getNumPoseLocal(), m_character->getSetup()->m_animationSkeleton->m_parentIndices.begin(), poseLocal, poseModel.begin() ); const hkQsTransform* pose = poseModel.begin(); float const inverseCharacterScale = 1.0f / m_character->getSetup()->getData()->m_scale; // Convert pose to vision units VisSkeleton_cl* visionSkeleton = m_entityOwner->GetMesh()->GetSkeleton(); for( int havokBoneIndex = 0; havokBoneIndex < m_character->getNumPoseLocal(); havokBoneIndex++ ) { // Find the bone index int visionBoneIndex = m_boneIndexList[havokBoneIndex]; if( visionBoneIndex != -1 ) { HK_ON_DEBUG( VisSkeletalBone_cl* bone = visionSkeleton->GetBone(visionBoneIndex) ); HK_ASSERT2(0x68b6649, hkString::strCmp( bone->m_sBoneName.AsChar(), m_character->getSetup()->m_animationSkeleton->m_bones[havokBoneIndex].m_name.cString() ) == 0, "" ); const hkQsTransform& transform = pose[havokBoneIndex]; // Convert Havok pose to Vision pose hkvQuat quat; quat.setIdentity(); vHavokConversionUtils::HkQuatToVisQuat( transform.getRotation(), quat ); hkvVec3 scale; vHavokConversionUtils::PhysVecToVisVec_noscale( transform.getScale(), scale ); hkvVec3 translation; vHavokConversionUtils::PhysVecToVisVecWorld( transform.getTranslation(), translation ); // Behavior propagates character scale through the skeleton; need to compensate when scaling to Vision scale *= inverseCharacterScale; // Set the skeletal result skeletalResult->SetCustomBoneScaling( visionBoneIndex, scale, VIS_REPLACE_BONE | VIS_OBJECT_SPACE ); skeletalResult->SetCustomBoneRotation( visionBoneIndex, quat, VIS_REPLACE_BONE | VIS_OBJECT_SPACE ); skeletalResult->SetCustomBoneTranslation( visionBoneIndex, translation, VIS_REPLACE_BONE | VIS_OBJECT_SPACE ); } } #if 0 // Draw skeleton for( int i = 0; i < visionSkeleton->GetBoneCount(); i++ ) { VisSkeletalBone_cl* bone = visionSkeleton->GetBone(i); if( bone->m_iParentIndex != -1 ) { hkvVec3 translation, subTranslation; hkvQuat rotation, subRotation; m_entityOwner->GetBoneCurrentWorldSpaceTransformation( i, translation, rotation ); m_entityOwner->GetBoneCurrentWorldSpaceTransformation( bone->m_iParentIndex, subTranslation, subRotation ); Vision::Game.DrawSingleLine( translation.x, translation.y, translation.z, subTranslation.x, subTranslation.y, subTranslation.z ); } } #endif }