void SimpleSkeletalAnimatedObject_cl::SetMode(SampleMode_e newMode) { ClearData(); m_eSampleMode = newMode; switch (newMode) { case MODE_SINGLEANIM: StartSingleAnimation(false); break; case MODE_BLENDTWOANIMS: BlendTwoAnimations(); break; case MODE_LISTENTOEVENTS: ListenToEvents(); break; case MODE_SETANIMATIONTIME: SetAnimationTime(); break; case MODE_LAYERTWOANIMATIONS: LayerTwoAnimations(); break; case MODE_FORWARDKINEMATICS: ForwardKinematics(); break; case MODE_LOOKAT: LookAt(); break; } // disable motion delta for this sample if (GetAnimConfig() != NULL) GetAnimConfig()->SetFlags(GetAnimConfig()->GetFlags() & ~APPLY_MOTION_DELTA); }
void SimpleSkeletalAnimatedObject_cl::ThinkFunction() { // Check whether the object is active. if (GetAnimConfig() == NULL) return; const float dtime = Vision::GetTimer()->GetTimeDifference(); // highlight the bone after animation event if (m_fBoneHighlightDuration > 0.0f && !m_sHighlightedBoneName.IsEmpty()) { int iColorVal = static_cast<int>(m_fBoneHighlightDuration / BONE_HIGHLIGHT_FADEOUTTIME * 255.0f); DrawBoneBoundingBox(m_sHighlightedBoneName, VColorRef(iColorVal,iColorVal, 0), 2.f); m_fBoneHighlightDuration -= Vision::GetTimer()->GetTimeDifference(); } // update the LookAt if (m_eSampleMode == MODE_LOOKAT) { VASSERT(m_pLookAtTarget); // rotate the object around the character m_fLookAtRotationPhase = hkvMath::mod(m_fLookAtRotationPhase + dtime*0.7f, hkvMath::pi() * 2.0f); hkvVec3 vNewPos(100.f*hkvMath::sinRad(m_fLookAtRotationPhase), 100.0f*hkvMath::cosRad(m_fLookAtRotationPhase), 160.0f); vNewPos += GetPosition(); m_pLookAtTarget->SetPosition(vNewPos); // update the LookAt orientation UpdateLookatHeadRotation(dtime); } }
void AnimatedWarrior_cl::SetEnabled(bool bEnabled) { if (m_bEnabled == bEnabled) return; m_bEnabled = bEnabled; if (!m_bModelValid) return; #if defined(USE_HAVOK) // Turn on/off character controller if (m_pCharacterController != NULL) m_pCharacterController->SetEnabled(bEnabled ? TRUE : FALSE); #endif VisAnimConfig_cl* pAnimConfig = GetAnimConfig(); if (bEnabled) { m_spAnimConfig = GetAnimConfig(); if (m_spAnimConfig == NULL) { m_spAnimConfig = VisAnimConfig_cl::CreateSkeletalConfig(GetMesh()); SetAnimConfig(m_spAnimConfig); } if (m_spAnimConfig->GetFinalResult() != NULL) m_spAnimConfig->GetFinalResult()->SetSkeletalAnimInput(m_spLayerMixer); // Resume animation controls for (int i = 0; i < UPPERBODY_CONTROLCOUNT; i++) m_spUpperBodyControls[i]->Resume(); for (int i = 0; i < m_FullBodyControlList.Count(); i++) m_FullBodyControlList.GetAt(i)->Resume(); } else { // Pause animation controls for (int i = 0; i < UPPERBODY_CONTROLCOUNT; i++) m_spUpperBodyControls[i]->Pause(); for (int i = 0; i < m_FullBodyControlList.Count(); i++) m_FullBodyControlList.GetAt(i)->Pause(); if (m_spAnimConfig != NULL && m_spAnimConfig->GetFinalResult() != NULL) m_spAnimConfig->GetFinalResult()->SetSkeletalAnimInput(NULL); } }
bool SimpleSkeletalAnimatedObject_cl::GetHeadRotation(const hkvVec3 &vTargetPos, hkvQuat &targetRot, float fMaxViewAngle) { hkvMat4 objectMatrix; hkvMat4 parentObjectMatrix; // get the index of the parent bone int parentBoneIndex = GetMesh()->GetSkeleton()->GetBone(m_iHeadBoneIndex)->m_iParentIndex; // get the 4x4 matrix of the head bone and its parent in object space const VisSkeletalAnimResult_cl* pObjectSpaceResult = GetAnimConfig()->GetFinalResult()->GetCurrentObjectSpaceResult(); pObjectSpaceResult->GetBoneTransformationMatrix(m_iHeadBoneIndex, objectMatrix); pObjectSpaceResult->GetBoneTransformationMatrix(parentBoneIndex, parentObjectMatrix); // get the current position of the target in object space hkvVec3 targetObjectspace = TransformToObjectSpace(vTargetPos); // get the current position of the bone in object space hkvVec3 boneObjectspace = objectMatrix.getTranslation(); // calculate the look at direction in object space (just for the angle constraints) hkvVec3 vLookAtDir = targetObjectspace - boneObjectspace; // check if we are within the angle constraints vLookAtDir.normalizeIfNotZero(); float fCosMax = hkvMath::cosDeg (180.f - fMaxViewAngle); bool bInsideFocusArea = vLookAtDir.y < fCosMax; if (!bInsideFocusArea) { // out of focus, so just look straight ahead targetRot.setIdentity(); return false; } // create a LookAt-3x3 matrix from the bone position and the target position (both are in object space) // This orientation is later used to replace(!) the head bone in local space (VIS_REPLACE_BONE|VIS_LOCAL_SPACE flags) hkvMat3 lookatMatrix(hkvNoInitialization); lookatMatrix.setLookInDirectionMatrix(targetObjectspace - boneObjectspace); // Apply our custom rotation matrix that tells the bone to focus with the eyes and not with the back of the head :-) lookatMatrix = lookatMatrix.multiply(m_RelativeHeadOrientation); // Invert the parents object matrix rotation to cancel out all parent bone orientations hkvMat3 parentObject = parentObjectMatrix.getRotationalPart(); parentObject.invert(); // put everything together hkvMat3 result = parentObject; result = result.multiply (lookatMatrix); // ...and make a quaternion from it targetRot.setFromMat3 (result); return true; }
void SimpleSkeletalAnimatedObject_cl::UpdateLookatHeadRotation(float fTimeDelta) { hkvQuat targetRotation; // evaluate the target rotation GetHeadRotation(m_pLookAtTarget->GetPosition(), targetRotation, 75.f); hkvVec3 vForwards(0.0f, -1.0f, 0.0f); hkvVec3 vFrom = m_CurrentNeckRotation.transform(vForwards); hkvVec3 vTo = targetRotation.transform(vForwards); float fAngle = vFrom.getAngleBetween (vTo); float fAnglePerSecond = 20.0f * fTimeDelta; float fFactor = hkvMath::Min(fAnglePerSecond / (fAngle + 0.000001f), 1.0f); m_CurrentNeckRotation.setSlerp(m_CurrentNeckRotation, targetRotation, fFactor); // Our new bone orientation defines the rotation absolute. // Thus our modify mode must be VIS_REPLACE_BONE and VIS_LOCAL_SPACE GetAnimConfig()->GetFinalResult()->SetCustomBoneRotation(m_iHeadBoneIndex, m_CurrentNeckRotation, VIS_REPLACE_BONE|VIS_LOCAL_SPACE); }
// ************************************************** // NECK BONE HANDLING // ************************************************** void AnimatedWarrior_cl::TurnHead(float fDegreesPerSecond, float fTimeDiff, float fMinAngle, float fMaxAngle) { float fAmount = fDegreesPerSecond * fTimeDiff; // update joint rotation (with clamp) m_fHeadRotationAngles[1] += fAmount; if (m_fHeadRotationAngles[1] > fMaxAngle) m_fHeadRotationAngles[1] = fMaxAngle; else if (m_fHeadRotationAngles[1] < fMinAngle) m_fHeadRotationAngles[1] = fMinAngle; //// set new rotation VASSERT(GetAnimConfig() == m_spAnimConfig); VisAnimFinalSkeletalResult_cl *pFinalResult = m_spAnimConfig->GetFinalResult(); VASSERT(pFinalResult != NULL); // update the current localspace result and add custom rotation pFinalResult->GetCurrentLocalSpaceResult(); hkvQuat tempRotation(hkvNoInitialization); tempRotation.setFromEulerAngles (m_fHeadRotationAngles[2], m_fHeadRotationAngles[1], m_fHeadRotationAngles[0]); pFinalResult->SetCustomBoneRotation(m_iHeadBoneIndex, tempRotation, VIS_MODIFY_BONE|VIS_LOCAL_SPACE); m_bHeadInMovement = true; }