public HkRigidBody GetBodyBindedToBone(MyCharacterBone myCharacterBone)
        {
            if (Ragdoll == null)
            {
                Debug.Fail("Ragdoll is not initialized!");
                return null;
            }

            if (myCharacterBone == null)
            {
                Debug.Fail("Invalid parameter - cannot be null! ");
                return null;
            }

            foreach (var pair in m_ragdollBonesMappings)
            {
                if (pair.Value.Bones.Contains(myCharacterBone.Name))
                {
                    Debug.Assert(Ragdoll.RigidBodies.IsValidIndex(m_rigidBodies[pair.Key]), "Invalid rigid body index!");
                    return Ragdoll.RigidBodies[m_rigidBodies[pair.Key]];
                }
            }

            Debug.Fail("Requested bone was not found in mappings!");
            return null;
        }
        /// <summary>
        /// Constructs the new mapper
        /// </summary>
        /// <param name="ragdoll">The ragdoll model</param>
        /// <param name="bones">List of the mapped bones</param>
        public MyRagdollMapper(MyCharacter character, MyCharacterBone[] bones)
        {
            Debug.Assert(character.Physics.Ragdoll != null, "Creating ragdoll mapper without ragdoll?");
            Debug.Assert(bones != null && bones.Length > 0, "Creating ragdoll mapper without mapped bones?");


            m_rigidBodiesToBonesIndices = new Dictionary<int, List<int>>();
            m_character = character;
            m_bones = bones;

            m_rigidBodies = new Dictionary<string, int>();
            m_keyframedBodies = new List<int>();
            m_dynamicBodies = new List<int>();
            IsActive = false;
            m_inicialized = false;
            IsPartiallySimulated = false;
        }
            /// <summary>
            /// Assign this bone to the correct bone in the model
            /// </summary>
            /// <param name="model"></param>
            public void SetModel(MyCharacter model)
            {
                if (ClipBone == null)
                    return;

                // Find this bone
                int index;
                m_assignedBone = model.FindBone(ClipBone.Name, out index);

                if (ClipBone.Name == model.Definition.SpineBone)
                    CalculateSpineAdditionalRotation = true;
                else
                    CalculateSpineAdditionalRotation = false;

                if (ClipBone.Name == model.Definition.HeadBone)
                    CalculateHeadAdditionalRotation = true;
                else
                    CalculateHeadAdditionalRotation = false;

                 //"l_Forearm") || (ClipBone.Name == "r_Forearm"))
                if ((ClipBone.Name == model.Definition.LeftForearmBone) || (ClipBone.Name == model.Definition.RightForearmBone))
                    CalculateHandAdditionalRotation = true;
                else
                    CalculateHandAdditionalRotation = false;

                if (ClipBone.Name == model.Definition.LeftUpperarmBone) 
                    CalculateUpperHandAdditionalRotation = 1;
                else
                    if (ClipBone.Name == model.Definition.RightUpperarmBone)
                    CalculateUpperHandAdditionalRotation = -1;
                else
                    CalculateUpperHandAdditionalRotation = 0;
            }
Esempio n. 4
0
        /// <summary>
        /// Get the bones from the model and create a bone class object for
        /// each bone. We use our bone class to do the real animated bone work.
        /// </summary>
        public virtual void ObtainBones()
        {
            MyCharacterBone[] characterBones = new MyCharacterBone[Model.Bones.Length];
            for (int i = 0; i < Model.Bones.Length; i++)
            {
                MyModelBone bone = Model.Bones[i];
                Matrix boneTransform = bone.Transform;
                // Create the bone object and add to the heirarchy
                MyCharacterBone newBone = new MyCharacterBone(bone.Name, boneTransform, bone.Parent != -1 ? characterBones[bone.Parent] : null);
                // Add to the bone array for this model
                characterBones[i] = newBone;
            }

            // pass array of bones to animation controller
            m_compAnimationController.CharacterBones = characterBones;
        }
 public static void RotateBone(MyCharacterBone bone, Vector3 planeNormal, double angle)
 {
     Matrix rotation = Matrix.CreateFromAxisAngle(planeNormal, (float)angle);
     Matrix finalMatrix = bone.AbsoluteTransform * rotation;
     Matrix parentTransform = bone.Parent != null ? bone.Parent.AbsoluteTransform : Matrix.Identity;
     Matrix localTransform = Matrix.Multiply(finalMatrix, Matrix.Invert(bone.BindTransform * parentTransform));
     bone.Rotation = Quaternion.CreateFromRotationMatrix(localTransform);
     bone.ComputeAbsoluteTransform();        
 }
Esempio n. 6
0
 public void Clear()
 {
     m_currentKeyframe = 0;
     m_isConst = false;
     m_assignedBone = null;
     Rotation = default(Quaternion);
     Translation = Vector3.Zero;
     Player = null;
     Keyframe1 = null;
     Keyframe2 = null;
     m_clipBone = null;
 }
        private void DrawBoneHierarchy(MyCharacter character, ref MatrixD parentTransform, MyCharacterBone[] characterBones, List<MyAnimationClip.BoneState> rawBones, int boneIndex)
        {
            // ----------------------------
            // raw animation data
            MatrixD currentTransform = rawBones != null ? Matrix.CreateTranslation(rawBones[boneIndex].Translation) * parentTransform : MatrixD.Identity;
            currentTransform = rawBones != null ? Matrix.CreateFromQuaternion(rawBones[boneIndex].Rotation) * currentTransform : currentTransform;
            if (rawBones != null)
            {
                MyRenderProxy.DebugDrawLine3D(currentTransform.Translation, parentTransform.Translation, Color.Green, Color.Green, false);
            }
            bool anyChildren = false;
            for (int i = 0; characterBones[boneIndex].GetChildBone(i) != null; i++)
            {
                var childBone = characterBones[boneIndex].GetChildBone(i);
                DrawBoneHierarchy(character, ref currentTransform, characterBones, rawBones,
                    m_boneRefToIndex[childBone]);
                anyChildren = true;
            }
            if (!anyChildren && rawBones != null)
            {
                MyRenderProxy.DebugDrawLine3D(currentTransform.Translation, currentTransform.Translation + currentTransform.Left * 0.05f, Color.Green, Color.Cyan, false);
            }

            // ----------------------------
            // final animation data - after IK, ragdoll...
            MyRenderProxy.DebugDrawText3D(Vector3D.Transform(characterBones[boneIndex].AbsoluteTransform.Translation, character.PositionComp.WorldMatrix), characterBones[boneIndex].Name, Color.Lime, 0.4f, false);
            if (characterBones[boneIndex].Parent != null)
            {
                Vector3D boneStartPos = Vector3D.Transform(characterBones[boneIndex].AbsoluteTransform.Translation, character.PositionComp.WorldMatrix);
                Vector3D boneEndPos = Vector3D.Transform(characterBones[boneIndex].Parent.AbsoluteTransform.Translation, character.PositionComp.WorldMatrix);
                MyRenderProxy.DebugDrawLine3D(boneStartPos, boneEndPos, Color.Purple, Color.Purple, false);
            }
            if (!anyChildren)
            {
                Vector3D boneStartPos = Vector3D.Transform(characterBones[boneIndex].AbsoluteTransform.Translation, character.PositionComp.WorldMatrix);
                Vector3D boneEndPos = Vector3D.Transform(characterBones[boneIndex].AbsoluteTransform.Translation + characterBones[boneIndex].AbsoluteTransform.Left * 0.05f, character.PositionComp.WorldMatrix);
                MyRenderProxy.DebugDrawLine3D(boneStartPos, boneEndPos, Color.Purple, Color.Red, false);
            }
        }
        public static bool SolveTwoJointsIk(ref Vector3 desiredEnd, MyCharacterBone firstBone, MyCharacterBone secondBone, MyCharacterBone endBone, ref Matrix finalTransform, Matrix WorldMatrix, Vector3 normal, bool preferPositiveAngle = true, MyCharacterBone finalBone = null, bool allowFinalBoneTranslation = true, bool minimizeRotation = true)
        {
            //TODO: Implement this new method, that will consider signed/unsigned angles of bone configurations for analytic solution and use a passed normal parameter for proper rotations configuration

             throw new NotImplementedException();
            //Matrix firstBoneAbsoluteTransform = firstBone.AbsoluteTransform;
            //Matrix secondBoneAbsoluteTransform = secondBone.AbsoluteTransform;
            //Matrix endBoneAbsoluteTransform = endBone.AbsoluteTransform;

            //Vector3 origin = firstBoneAbsoluteTransform.Translation;
            //Vector3 originToCurrentEnd = endBoneAbsoluteTransform.Translation - origin;
            //Vector3 originToDesiredEnd = desiredEnd - origin;
            //Vector3 firstBoneVector = secondBoneAbsoluteTransform.Translation - origin;
            //Vector3 secondBoneVector = originToCurrentEnd - firstBoneVector;
            //float firstBoneLength = firstBoneVector.Length();
            //float secondBoneLength = secondBoneVector.Length();
            //float originToDesiredEndLength = originToDesiredEnd.Length();
            //float originToCurrentEndLength = originToCurrentEnd.Length();

            //if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_IKSOLVERS)
            //{
            //    VRageRender.MyRenderProxy.DebugDrawSphere(Vector3.Transform(desiredEnd, WorldMatrix), 0.01f, Color.Red, 1, false);
            //    VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + originToCurrentEnd, WorldMatrix), Color.Yellow, Color.Yellow, false);
            //    VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + originToDesiredEnd, WorldMatrix), Color.Red, Color.Red, false);
            //    VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + firstBoneVector, WorldMatrix), Color.Green, Color.Green, false);
            //    VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin + firstBoneVector, WorldMatrix), Vector3.Transform(origin + firstBoneVector + secondBoneVector, WorldMatrix), Color.Blue, Color.Blue, false);
            //}

            // only two cases, the desired position is reachable or not
            //bool isDesiredEndReachable = firstBoneLength + secondBoneLength > originToDesiredEndLength;

            // alpha = angle between the first bone and originToDesiredEnd vector
            //double finalAlpha = 0;

            // beta = the angle between the first and second bone
            //double finalBeta = 0;

            //if (isDesiredEndReachable)
            //{
            //    CosineLaw(firstBoneLength, secondBoneLength, originToDesiredEndLength, out finalAlpha, out finalBeta);
            //}                   

            // get the current angles between bones
            //Vector3 planeNormal = Vector3.Cross(originToCurrentEnd, firstBoneVector);
            //planeNormal.Normalize();
            
            //double currentAlpha = GetAngleSigned(originToCurrentEnd, firstBoneVector, planeNormal);
            //double delta = GetAngleSigned(originToCurrentEnd, originToDesiredEnd, planeNormal);

            //finalAlpha = 1f;
            //planeNormal.X = 0.94f; planeNormal.Y = 0.27f; planeNormal.Z = -0.18f;
            //RotateBone(firstBone, planeNormal, delta);
            //if (delta < 0)
            //{
            //    finalAlpha = -finalAlpha;
            //}
            //if (finalAlpha.IsValid()) RotateBone(firstBone, planeNormal, finalAlpha);
            


            //currentBeta = Math.PI - currentBeta;

            //// check if the current Alpha is positive or negative oritented
            //Vector3 crossProduct = Vector3.Cross(firstBoneVector, originToCurrentEnd);
            ////crossProduct.Normalize();
            //float sinThetaX = crossProduct.X / (firstBoneVector.Length() * originToCurrentEnd.Length()) * Vector3.Normalize(crossProduct).X;
            //float sinThetaY = crossProduct.Y / (firstBoneVector.Length() * originToCurrentEnd.Length()) * Vector3.Normalize(crossProduct).Y;
            //float sinThetaZ = crossProduct.Z / (firstBoneVector.Length() * originToCurrentEnd.Length()) * Vector3.Normalize(crossProduct).Z;
            //double theta = 0;

            //if (crossProduct.X != 0)
            //{
            //    theta = Math.Asin(sinThetaX);
            //}
            //else if (crossProduct.Y != 0)
            //{
            //    theta = Math.Asin(sinThetaY);
            //}
            //else
            //{
            //    theta = Math.Asin(sinThetaZ);
            //}

            //if (currentAlpha != theta)
            //{
            //    currentAlpha = -currentAlpha;
            //    currentBeta = -currentBeta;
            //}


            // get the angle between original and final position plane normal
            //originToCurrentEnd.Normalize();
            //originToDesiredEnd.Normalize();
            //double dotProd = Vector3.Dot(Vector3.Normalize();

            //dotProd = MathHelper.Clamp(dotProd, -1, 1);
            //double delta = Math.Acos(dotProd);

            // set the alpha to positive/negative so the total rotation is minimized
            //if (currentAlpha + delta + finalAlpha > currentAlpha + delta - finalAlpha)
            //{
            //    finalAlpha = -finalAlpha;
            //    finalBeta = -finalBeta;
            //}
            //else
            //{
            //    //finalBeta = Math.PI-finalBeta;
            //}



            //Vector3 currentPlaneNormal = Vector3.Cross(firstBoneVector, originToCurrentEnd);
            //currentPlaneNormal.Normalize();


            // we can now rotate the bones in current plane as if the desired end was on the currentEnd axis
            //float alphaDif = (float)(finalAlpha - currentAlpha);
            //float betaDif = (float)(finalBeta - currentBeta);
            //Matrix firstBoneRotation = Matrix.CreateFromAxisAngle(currentPlaneNormal, alphaDif);
            //Matrix secondBoneRotation = Matrix.CreateFromAxisAngle(currentPlaneNormal, betaDif);

            //////// Now we compute the final absolute transforms for the bones
            //Matrix firstBoneFinalTransform = firstBoneAbsoluteTransform * firstBoneRotation;
            //Matrix firstBoneParentAbsoluteTransform = firstBone.Parent.AbsoluteTransform;
            //Matrix localFirstBoneTransform = Matrix.Multiply(firstBoneFinalTransform, Matrix.Invert(firstBone.BindTransform * firstBoneParentAbsoluteTransform));
            //firstBone.Rotation = Quaternion.CreateFromRotationMatrix(localFirstBoneTransform);
            //firstBone.ComputeAbsoluteTransform();

            //Matrix secondBoneFinalTransform = secondBoneAbsoluteTransform * secondBoneRotation;
            //Matrix secondBoneParentAbsoluteTransform = secondBone.Parent.AbsoluteTransform;
            //Matrix localSecondBoneTransform = Matrix.Multiply(secondBoneFinalTransform, Matrix.Invert(secondBone.BindTransform * secondBoneParentAbsoluteTransform));

            //secondBone.Rotation = Quaternion.CreateFromRotationMatrix(localSecondBoneTransform);
            //secondBone.ComputeAbsoluteTransform();



            ////Vector3 planeRotationAxis = planeNormal;//Vector3.Cross(originToCurrentEnd, originToDesiredEnd);
            ////planeRotationAxis.Normalize();

            ////// find the rotation matrices for bones in the original plane
            ////Matrix planeRotation = Matrix.CreateFromAxisAngle(planeRotationAxis, (float)delta);

            ////// compute the final rotations
            ////firstBoneRotation = planeRotation * firstBoneRotation;
            ////secondBoneRotation = secondBoneRotation * firstBoneRotation;

            //// draw the final positions if debug enabled
            //if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_IKSOLVERS)
            //{
            //    Vector3 rotatedFirst = Vector3.Transform(firstBoneVector, firstBoneRotation);
            //    Vector3 rotatedSecond = Vector3.Transform(secondBoneVector, secondBoneRotation);
            //    VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + rotatedFirst, WorldMatrix), Color.Purple, Color.Purple, false);
            //    VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin + rotatedFirst, WorldMatrix), Vector3.Transform(origin + rotatedFirst + rotatedSecond, WorldMatrix), Color.White, Color.White, false);
            //}

            // Now we compute the final absolute transforms for the bones
            //Matrix firstBoneFinalAbsoluteTransform = firstBoneAbsoluteTransform * firstBoneRotation;
            //Matrix firstBoneParentAbsoluteTransform = firstBone.Parent.AbsoluteTransform;
            //Matrix localFirstBoneTransform = Matrix.Multiply(firstBoneFinalAbsoluteTransform, Matrix.Invert(firstBone.BindTransform * firstBoneParentAbsoluteTransform));
            //firstBone.Rotation = Quaternion.CreateFromRotationMatrix(localFirstBoneTransform);
            //firstBone.ComputeAbsoluteTransform();

            //Matrix secondBoneFinalAbsoluteTransform = secondBoneAbsoluteTransform * secondBoneRotation;
            //Matrix secondBoneParentAbsoluteTransform = secondBone.Parent.AbsoluteTransform;
            //Matrix localSecondBoneTransform = Matrix.Multiply(secondBoneFinalAbsoluteTransform, Matrix.Invert(secondBone.BindTransform * secondBoneParentAbsoluteTransform));

            //secondBone.Rotation = Quaternion.CreateFromRotationMatrix(localSecondBoneTransform);
            //secondBone.ComputeAbsoluteTransform();

            // minimize the rotation of the second joint from it's origin
            // this will mean to rotate around originToDesiredEnd vector
            //if (minimizeRotation && isDesiredEndReachable)
            //{
            //    Vector3 a = originToDesiredEnd;
            //    Vector3 v = secondBone.AbsoluteTransform.Translation - firstBone.AbsoluteTransform.Translation;
            //    Vector3 k = firstBoneVector;
            //    a.Normalize();
            //    v.Normalize();
            //    k.Normalize();
            //    float A = Vector3.Dot(a, v) * Vector3.Dot(a, k) - Vector3.Dot(Vector3.Cross(Vector3.Cross(a, v), a), k);
            //    float B = Vector3.Dot(Vector3.Cross(a, v), k);
            //    float C = Vector3.Dot(v, k);
            //    double theta1 = Math.Atan(2 * B / (C - A));
            //    double theta2 = Math.PI + theta1;
            //    double finalTheta = 0;
            //    double secondDerivate1 = (A - C) / 2 * Math.Cos(theta1) - B * Math.Sin(theta1);
            //    if (secondDerivate1 > 0)
            //    {
            //        finalTheta = theta2;
            //    }
            //    else
            //    {
            //        finalTheta = theta1;
            //    }
                
            //    Matrix minimizingMatrix = Matrix.CreateFromAxisAngle(a, (float)finalTheta);
            //    Matrix firstBoneFinalMinimizedTransform = firstBone.AbsoluteTransform * minimizingMatrix;
            //    firstBoneParentAbsoluteTransform = firstBone.Parent.AbsoluteTransform;
            //    localFirstBoneTransform = Matrix.Multiply(firstBoneFinalMinimizedTransform, Matrix.Invert(firstBone.BindTransform * firstBoneParentAbsoluteTransform));
            //    firstBone.Rotation = Quaternion.CreateFromRotationMatrix(localFirstBoneTransform);
            //    firstBone.ComputeAbsoluteTransform();
            //}

            // solve the last bone 
            //if (finalBone != null && finalTransform.IsValid() && isDesiredEndReachable)
            //{
            //    //MatrixD absoluteTransformEnd = finalBone.AbsoluteTransform * finalTransform; // this is our local final transform ( rotation)

            //    // get the related transformation to original binding pose
            //    MatrixD localTransformRelated;

            //    if (allowFinalBoneTranslation) localTransformRelated = finalTransform * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);
            //    else localTransformRelated = finalTransform.GetOrientation() * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);

            //    //localTransformRelated = Matrix.Normalize(localTransformRelated);
            //    // from there get the rotation and translation
            //    finalBone.Rotation = Quaternion.CreateFromRotationMatrix(Matrix.Normalize((Matrix)localTransformRelated.GetOrientation()));
            //    if (allowFinalBoneTranslation) finalBone.Translation = (Vector3)localTransformRelated.Translation;
            //    finalBone.ComputeAbsoluteTransform();
            //}

             //    //return isDesiredEndReachable;            
            return true;
        }
Esempio n. 9
0
        private void SetBoneTo(RagdollBone ragdollBone, float weight, float dynamicChildrenWeight, float keyframedChildrenWeight, bool translationEnabled)
        {
            if (Ragdoll == null)
            {
                return;
            }
            if (!m_inicialized || !IsActive)
            {
                return;
            }

            int firstBoneIndex = m_rigidBodiesToBonesIndices[ragdollBone.m_rigidBodyIndex].First();

            MyCharacterBone bone = m_bones[firstBoneIndex];

            //Matrix localTransform = Ragdoll.GetRigidBodyLocalTransform(ragdollBone.m_rigidBodyIndex);

            Matrix localTransform = m_bodyToBoneRigTransforms[ragdollBone.m_rigidBodyIndex] * Ragdoll.GetRigidBodyLocalTransform(ragdollBone.m_rigidBodyIndex);

            Matrix parentMatrix = (bone.Parent != null) ? bone.Parent.AbsoluteTransform : Matrix.Identity;

            Matrix absoluteMatrixInverted = Matrix.Invert(bone.BindTransform * parentMatrix);

            Matrix finalTransform = localTransform * absoluteMatrixInverted;

            //finalTransform = rigidBodyToBoneTransform * finalTransform;

            Debug.Assert(finalTransform.IsValid() && finalTransform != Matrix.Zero, "Ragdoll - final bone transform is invalid!");

            if (finalTransform.IsValid() && finalTransform != Matrix.Zero)
            {
                if (weight == 1.0f)
                {
                    bone.Rotation = Quaternion.CreateFromRotationMatrix(Matrix.Normalize((Matrix)finalTransform.GetOrientation()));

                    // NOTE: If enabled, sometimes ragdoll bodies got extra translation which leads to disproporced transfomations on limbs, therefore disabled on all bodies except the firs one
                    if (translationEnabled)// || m_character.IsDead)
                    {
                        bone.Translation = finalTransform.Translation;
                    }
                }
                else
                {
                    bone.Rotation = Quaternion.Slerp(bone.Rotation, Quaternion.CreateFromRotationMatrix(Matrix.Normalize((Matrix)finalTransform.GetOrientation())), weight);

                    // NOTE: If enabled, sometimes ragdoll bodies got extra translation which leads to disproporced transfomations on limbs, therefore disabled
                    if (translationEnabled)// || m_character.IsDead)
                    {
                        bone.Translation = Vector3.Lerp(bone.Translation, finalTransform.Translation, weight);
                    }
                }
            }

            bone.ComputeAbsoluteTransform();

            foreach (var childBone in ragdollBone.m_children)
            {
                float childWeight = dynamicChildrenWeight;
                if (m_keyframedBodies.Contains(childBone.m_rigidBodyIndex))
                {
                    childWeight = keyframedChildrenWeight;
                }
                SetBoneTo(childBone, childWeight, dynamicChildrenWeight, keyframedChildrenWeight, MyFakes.ENABLE_RAGDOLL_BONES_TRANSLATION);
            }
        }
        public override void DebugDraw()
        {
            if (MyDebugDrawSettings.DEBUG_DRAW_SHOW_DAMAGE)
            {
                m_counter++;
                if (m_character.CharacterAccumulatedDamage != m_lastDamage)
                {
                    m_counter = 0;
                }
                VRageRender.MyRenderProxy.DebugDrawText3D(((MyEntity)m_character).WorldMatrix.Translation + ((MyEntity)m_character).WorldMatrix.Up, "Total damage:" + m_lastDamage + " velocity:" + m_lastCharacterVelocity, Color.Red, 1.5f, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);
                if (m_counter > 200)
                {
                    m_character.CharacterAccumulatedDamage = 0;
                    m_lastCharacterVelocity = 0;
                    m_counter = 0;
                }
                m_lastDamage            = m_character.CharacterAccumulatedDamage;
                m_lastCharacterVelocity = Math.Max(m_lastCharacterVelocity, m_character.Physics.LinearVelocity.Length());
            }

            if (MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_MISC && m_character.CurrentWeapon != null)
            {
                VRageRender.MyRenderProxy.DebugDrawAxis(((MyEntity)m_character.CurrentWeapon).WorldMatrix, 1.4f, false);
                VRageRender.MyRenderProxy.DebugDrawText3D(((MyEntity)m_character.CurrentWeapon).WorldMatrix.Translation, "Weapon", Color.White, 0.7f, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);

                VRageRender.MyRenderProxy.DebugDrawSphere((m_character.AnimationController.CharacterBones[m_character.WeaponBone].AbsoluteTransform * m_character.PositionComp.WorldMatrix).Translation, 0.02f, Color.White, 1, false);
                VRageRender.MyRenderProxy.DebugDrawText3D((m_character.AnimationController.CharacterBones[m_character.WeaponBone].AbsoluteTransform * m_character.PositionComp.WorldMatrix).Translation, "Weapon Bone", Color.White, 1f, false);
            }

            if (MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_MISC && m_character.IsUsing != null)
            {
                Matrix characterMatrix = m_character.IsUsing.WorldMatrix;
                characterMatrix.Translation = Vector3.Zero;
                characterMatrix             = characterMatrix * Matrix.CreateFromAxisAngle(characterMatrix.Up, MathHelper.Pi);

                Vector3 position = m_character.IsUsing.PositionComp.GetPosition() - m_character.IsUsing.WorldMatrix.Up * MyDefinitionManager.Static.GetCubeSize(MyCubeSize.Large) / 2.0f;
                position = position + characterMatrix.Up * 0.28f - characterMatrix.Forward * 0.22f;
                characterMatrix.Translation = position;
                VRageRender.MyRenderProxy.DebugDrawAxis(characterMatrix, 1.4f, false);
            }

            if (MyDebugDrawSettings.DEBUG_DRAW_SUIT_BATTERY_CAPACITY)
            {
                var world = m_character.PositionComp.WorldMatrix;

                VRageRender.MyRenderProxy.DebugDrawText3D(world.Translation + 2f * world.Up, string.Format("{0} MWh", m_character.SuitBattery.ResourceSource.RemainingCapacity),
                                                          Color.White, 1f, true, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);
            }

            m_simulatedBonesDebugDraw.Clear();
            m_simulatedBonesAbsoluteDebugDraw.Clear();

            if (MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_BONES)
            {
                m_character.AnimationController.UpdateTransformations();
                for (int s = 0; s < m_character.AnimationController.CharacterBones.Length; s++)
                {
                    MyCharacterBone bone2 = m_character.AnimationController.CharacterBones[s];
                    if (bone2.Parent == null)
                    {
                        continue;
                    }

                    //bone2.ComputeAbsoluteTransform();

                    var     p2m = Matrix.CreateScale(0.1f) * bone2.AbsoluteTransform * m_character.PositionComp.WorldMatrix;
                    Vector3 p2  = p2m.Translation;

                    MyCharacterBone bone1 = bone2.Parent;
                    //bone1.Rotation = Quaternion.Identity;
                    //bone1.Translation = Vector3.Zero;

                    // bone1.ComputeAbsoluteTransform();
                    Vector3 p1 = (bone1.AbsoluteTransform * m_character.PositionComp.WorldMatrix).Translation;

                    VRageRender.MyRenderProxy.DebugDrawLine3D(p1, p2, Color.White, Color.White, false);

                    Vector3 pCenter = (p1 + p2) * 0.5f;
                    VRageRender.MyRenderProxy.DebugDrawText3D(pCenter, bone2.Name + " (" + s.ToString() + ")", Color.Red, 0.5f, false);

                    VRageRender.MyRenderProxy.DebugDrawAxis(p2m, 0.1f, false);
                }
            }
        }
        public void InitLight(MyCharacterDefinition definition)
        {
            m_light = MyLights.AddLight();

            m_lightGlareSize = definition.LightGlareSize;

            m_light.Start(MyLight.LightTypeEnum.PointLight | MyLight.LightTypeEnum.Spotlight, 0.5f);

            /// todo: defaults should be supplied from Environemnt.sbc
            m_light.GlossFactor        = 0;
            m_light.DiffuseFactor      = 3.14f;
            m_light.UseInForwardRender = true;
            m_light.LightOwner         = MyLight.LightOwnerEnum.SmallShip;
            m_light.ShadowDistance     = 20;
            m_light.ReflectorFalloff   = 10;

            m_light.ReflectorTexture         = "Textures\\Lights\\dual_reflector_2.dds";
            m_light.ReflectorColor           = MyCharacter.REFLECTOR_COLOR;
            m_light.ReflectorConeMaxAngleCos = MyCharacter.REFLECTOR_CONE_ANGLE;
            m_light.ReflectorRange           = MyCharacter.REFLECTOR_RANGE;
            m_light.ReflectorGlossFactor     = MyCharacter.REFLECTOR_GLOSS_FACTOR;
            m_light.ReflectorDiffuseFactor   = MyCharacter.REFLECTOR_DIFFUSE_FACTOR;
            m_light.Color         = MyCharacter.POINT_COLOR;
            m_light.SpecularColor = new Vector3(MyCharacter.POINT_COLOR_SPECULAR);
            m_light.Range         = MyCharacter.POINT_LIGHT_RANGE;

            MyCharacterBone leftGlareBone = null;

            if (definition.LeftLightBone != String.Empty)
            {
                leftGlareBone = m_skinnedEntity.AnimationController.FindBone(definition.LeftLightBone, out m_leftLightIndex);
            }
            if (leftGlareBone != null)
            {
                m_leftGlare = MyLights.AddLight();
                m_leftGlare.Start(MyLight.LightTypeEnum.None, 1.5f);
                m_leftGlare.LightOn            = false;
                m_leftGlare.LightOwner         = MyLight.LightOwnerEnum.SmallShip;
                m_leftGlare.UseInForwardRender = false;
                m_leftGlare.GlareOn            = false;
                m_leftGlare.GlareQuerySize     = 0.2f;
                m_leftGlare.GlareType          = VRageRender.Lights.MyGlareTypeEnum.Directional;
                m_leftGlare.GlareMaterial      = definition.LeftGlare;
            }

            MyCharacterBone rightGlareBone = null;

            if (definition.RightLightBone != String.Empty)
            {
                rightGlareBone = m_skinnedEntity.AnimationController.FindBone(definition.RightLightBone, out m_rightLightIndex);
            }
            if (rightGlareBone != null)
            {
                m_rightGlare = MyLights.AddLight();
                m_rightGlare.Start(MyLight.LightTypeEnum.None, 1.5f);
                m_rightGlare.LightOn            = false;
                m_rightGlare.LightOwner         = MyLight.LightOwnerEnum.SmallShip;
                m_rightGlare.UseInForwardRender = false;
                m_rightGlare.GlareOn            = false;
                m_rightGlare.GlareQuerySize     = 0.2f;
                m_rightGlare.GlareType          = VRageRender.Lights.MyGlareTypeEnum.Directional;
                m_rightGlare.GlareMaterial      = definition.RightGlare;
            }
        }
        public override bool DebugDraw()
        {
            if (MyDebugDrawSettings.DEBUG_DRAW_SHOW_DAMAGE)
            {
                m_counter++;
                if (m_character.CharacterAccumulatedDamage != m_lastDamage)
                {
                    m_counter = 0;
                }
                VRageRender.MyRenderProxy.DebugDrawText3D(((MyEntity)m_character).WorldMatrix.Translation + ((MyEntity)m_character).WorldMatrix.Up, "Total damage:" + m_lastDamage + " velocity:" + m_lastCharacterVelocity, Color.Red, 1.5f, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);
                if (m_counter > 200)
                {
                    m_character.CharacterAccumulatedDamage = 0;
                    m_lastCharacterVelocity = 0;
                    m_counter = 0;
                }
                m_lastDamage            = m_character.CharacterAccumulatedDamage;
                m_lastCharacterVelocity = Math.Max(m_lastCharacterVelocity, m_character.Physics.LinearVelocity.Length());
            }

            if (MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_MISC && m_character.CurrentWeapon != null)
            {
                VRageRender.MyRenderProxy.DebugDrawAxis(((MyEntity)m_character.CurrentWeapon).WorldMatrix, 1.4f, false);
                VRageRender.MyRenderProxy.DebugDrawText3D(((MyEntity)m_character.CurrentWeapon).WorldMatrix.Translation, "Weapon", Color.White, 0.7f, false, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);

                VRageRender.MyRenderProxy.DebugDrawSphere((m_character.Bones[m_character.WeaponBone].AbsoluteTransform * m_character.PositionComp.WorldMatrix).Translation, 0.02f, Color.White, 1, false);
                VRageRender.MyRenderProxy.DebugDrawText3D((m_character.Bones[m_character.WeaponBone].AbsoluteTransform * m_character.PositionComp.WorldMatrix).Translation, "Weapon Bone", Color.White, 1f, false);
            }

            if (MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_MISC && m_character.IsUsing != null)
            {
                Matrix characterMatrix = m_character.IsUsing.WorldMatrix;
                characterMatrix.Translation = Vector3.Zero;
                characterMatrix             = characterMatrix * Matrix.CreateFromAxisAngle(characterMatrix.Up, MathHelper.Pi);

                Vector3 position = m_character.IsUsing.PositionComp.GetPosition() - m_character.IsUsing.WorldMatrix.Up * MyDefinitionManager.Static.GetCubeSize(MyCubeSize.Large) / 2.0f;
                position = position + characterMatrix.Up * 0.28f - characterMatrix.Forward * 0.22f;
                characterMatrix.Translation = position;
                VRageRender.MyRenderProxy.DebugDrawAxis(characterMatrix, 1.4f, false);
            }

            if (MyDebugDrawSettings.DEBUG_DRAW_SUIT_BATTERY_CAPACITY)
            {
                var world = m_character.PositionComp.WorldMatrix;

                VRageRender.MyRenderProxy.DebugDrawText3D(world.Translation + 2f * world.Up, string.Format("{0} MWh", m_character.SuitBattery.RemainingCapacity),
                                                          Color.White, 1f, true, MyGuiDrawAlignEnum.HORISONTAL_CENTER_AND_VERTICAL_CENTER);
            }

            // return true;

            /*
             * Matrix headMatrix = m_headMatrix * WorldMatrix;
             * VRageRender.MyRenderProxy.DebugDrawAxis(headMatrix, 2.4f, false);
             *
             * VRageRender.MyRenderProxy.DebugDrawAxis(m_weaponDummyMatrix, 2.4f, false);
             *
             * VRageRender.MyRenderProxy.DebugDrawAxis(Matrix.CreateWorld(headMatrix.Translation, Vector3.Forward, Vector3.Up), 2.4f, false);
             */
            //return true;

            m_simulatedBonesDebugDraw.Clear();
            m_simulatedBonesAbsoluteDebugDraw.Clear();
            //Physics.CharacterProxy.GetPoseModelSpace(m_simulatedBonesDebugDraw);
            //Physics.CharacterProxy.GetPoseLocalSpace(m_simulatedBones);

            if (MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_BONES)
            {
                if (MyFakes.USE_HAVOK_ANIMATION_HANDS)
                {
                    for (int s = 0; s < m_simulatedBonesDebugDraw.Count; s++)
                    {
                        MyCharacterBone bone2 = m_character.Bones[s];

                        Matrix absolute2 = m_simulatedBonesDebugDraw[s];// *bone2.BindTransform;

                        if (bone2.Parent == null)
                        {
                            m_simulatedBonesAbsoluteDebugDraw.Add(absolute2);
                            continue;
                        }


                        MyCharacterBone bone1 = bone2.Parent;

                        Matrix absolute1 = m_simulatedBonesAbsoluteDebugDraw[m_character.Bones.IndexOf(bone1)];
                        //absolute2 = absolute2 * absolute1;

                        m_simulatedBonesAbsoluteDebugDraw.Add(absolute2);

                        var     p2m = absolute2 * m_character.PositionComp.WorldMatrix;
                        Vector3 p2  = p2m.Translation;


                        //bone1.Rotation = Quaternion.Identity;
                        //bone1.Translation = Vector3.Zero;

                        Vector3 p1 = (absolute1 * m_character.PositionComp.WorldMatrix).Translation;

                        VRageRender.MyRenderProxy.DebugDrawLine3D(p1, p2, Color.White, Color.White, false);

                        Vector3 pCenter = (p1 + p2) * 0.5f;
                        VRageRender.MyRenderProxy.DebugDrawText3D(pCenter, bone2.Name + " (" + s.ToString() + ")", Color.White, 0.5f, false);

                        VRageRender.MyRenderProxy.DebugDrawAxis(p2m, 0.5f, false);
                    }
                }
                else
                {
                    for (int s = 0; s < m_character.Bones.Count; s++)
                    {
                        MyCharacterBone bone2 = m_character.Bones[s];
                        if (bone2.Parent == null)
                        {
                            continue;
                        }

                        bone2.ComputeAbsoluteTransform();

                        var     p2m = Matrix.CreateScale(0.1f) * bone2.AbsoluteTransform * m_character.PositionComp.WorldMatrix;
                        Vector3 p2  = p2m.Translation;

                        MyCharacterBone bone1 = bone2.Parent;
                        //bone1.Rotation = Quaternion.Identity;
                        //bone1.Translation = Vector3.Zero;

                        // bone1.ComputeAbsoluteTransform();
                        Vector3 p1 = (bone1.AbsoluteTransform * m_character.PositionComp.WorldMatrix).Translation;

                        VRageRender.MyRenderProxy.DebugDrawLine3D(p1, p2, Color.White, Color.White, false);

                        Vector3 pCenter = (p1 + p2) * 0.5f;
                        VRageRender.MyRenderProxy.DebugDrawText3D(pCenter, bone2.Name + " (" + s.ToString() + ")", Color.White, 0.5f, false);

                        VRageRender.MyRenderProxy.DebugDrawAxis(p2m, 0.1f, false);

                        if (s == 0)
                        {
                            //  MyDebugDraw.DrawAxis((bone2.AbsoluteTransform * WorldMatrix), 1000, 1, false);
                        }
                    }
                }
            }
            return(true);
        }
 private void DrawBoneHierarchy(ref MatrixD parentTransform, MyCharacterBone[] characterBones, List<MyAnimationClip.BoneState> rawBones, int boneIndex)
 {
     MatrixD currentTransform = Matrix.CreateTranslation(rawBones[boneIndex].Translation) * parentTransform;
     currentTransform = Matrix.CreateFromQuaternion(rawBones[boneIndex].Rotation) * currentTransform;
     MyRenderProxy.DebugDrawLine3D(currentTransform.Translation, parentTransform.Translation, Color.Green, Color.Green, false);
     if (characterBones[boneIndex].Parent == null)
         MyRenderProxy.DebugDrawText3D(currentTransform.Translation, characterBones[boneIndex].Name, Color.Green, 1.0f, false);
     for (int i = 0; characterBones[boneIndex].GetChildBone(i) != null; i++)
     {
         var childBone = characterBones[boneIndex].GetChildBone(i);
         DrawBoneHierarchy(ref currentTransform, characterBones, rawBones,
             m_boneRefToIndex[childBone]);
     }
 }
        /// <summary>
        /// Get the bones from the model and create a bone class object for
        /// each bone. We use our bone class to do the real animated bone work.
        /// </summary>
        private void ObtainBones()
        {
            m_bones.Clear();
            foreach (MyModelBone bone in Model.Bones)
            {
                Matrix boneTransform = bone.Transform;

                if (Model.DataVersion < 01047001)
                {
                    if (bone.Name.Contains("Dummy"))
                    {   //0.009860006
                        boneTransform = boneTransform * Matrix.CreateScale(0.009860006f);
                    }
                }

                // Create the bone object and add to the heirarchy
                MyCharacterBone newBone = new MyCharacterBone(bone.Name, boneTransform, bone.Parent != -1 ? m_bones[bone.Parent] : null);

                if (Model.DataVersion < 01050001)
                {
                    newBone.CompatibilityMode = true;
                }

                // Add to the bones for this model
                m_bones.Add(newBone);
            }
        }
 // Rebuild mapping clip bone indices to character bone indices.
 private void RebuildBoneIndices(MyCharacterBone[] characterBones)
 {
     // find indices of clip bones 
     // optimize? see m_boneIndices declaration
     m_boneIndicesMapping = new int[m_animationClip.Bones.Count];
     for (int i = 0; i < m_animationClip.Bones.Count; i++)
     {
         m_boneIndicesMapping[i] = -1;
         for (int j = 0; j < characterBones.Length; j++)
         {
             if (m_animationClip.Bones[i].Name == characterBones[j].Name)
             {
                 m_boneIndicesMapping[i] = j;
                 break;
             }
         }
         if (m_boneIndicesMapping[i] == -1)
         {
             // VRAGE TODO: at least log it? this is unfortunatelly a common situation
             //Debug.Fail(String.Format("Clip bone not found in character. {0} in {1}", 
             //    m_animationClip.Bones[i].Name,
             //    string.Join(",", (from item in characterBones select item.Name).ToArray())));
         }
     }
 }
Esempio n. 16
0
        public static bool SolveTwoJointsIkCCD(MyCharacterBone[] characterBones, int firstBoneIndex, int secondBoneIndex, int endBoneIndex, 
            ref Matrix finalTransform, ref MatrixD worldMatrix, MyCharacterBone finalBone = null, bool allowFinalBoneTranslation = true)
        {
            if (finalBone == null)
                return false;

            Vector3 desiredEnd = finalTransform.Translation;
            //VRageRender.MyRenderProxy.DebugDrawSphere(Vector3D.Transform(desiredEnd, worldMatrix), 0.015f, Color.LightGoldenrodYellow, 1, false);
            Vector3 rootPos, curEnd;
            Vector3 curVector;
            double cosAngle, turnAngle;

            int tries = 0;
            int maxTries = 50;
            float stopDistanceSq = 0.005f * 0.005f;
            float gain = 0.65f;

            MyCharacterBone firstBone = characterBones[firstBoneIndex];
            MyCharacterBone secondBone = characterBones[secondBoneIndex];
            MyCharacterBone endBone = characterBones[endBoneIndex];
                
            //unsafe
            {
                //int* boneIndices = stackalloc int[3];
                int[] boneIndices = new int[3];
                boneIndices[2] = firstBoneIndex;
                boneIndices[1] = secondBoneIndex;
                boneIndices[0] = endBoneIndex;
                curEnd = Vector3.Zero;

                for (int i = 0; i < 3; i++)
                {
                    var bone = characterBones[boneIndices[i]];
                    Vector3 tempTranslation = bone.BindTransform.Translation;
                    Quaternion tempRotation = Quaternion.CreateFromRotationMatrix(bone.BindTransform);
                    bone.SetCompleteTransform(ref tempTranslation, ref tempRotation);
                    bone.ComputeAbsoluteTransform();
                }

                endBone.ComputeAbsoluteTransform();
                curEnd = endBone.AbsoluteTransform.Translation;
                float initialDistSqInv = 1 / (float)Vector3D.DistanceSquared(curEnd, desiredEnd);

                do
                {
                    for (int i = 0; i < 3; i++)
                    {
                        var bone = characterBones[boneIndices[i]];

                        // first recalculate current final transformation
                        endBone.ComputeAbsoluteTransform();

                        // compute the position of the root
                        Matrix currentMatrix = bone.AbsoluteTransform;
                        rootPos = currentMatrix.Translation; // this is this bone root position
                        Vector3 lastEnd = curEnd;
                        curEnd = endBone.AbsoluteTransform.Translation;
                            // this is our current end of the final bone                  

                        // get the difference from desired and and current final position
                        double distanceSq = Vector3D.DistanceSquared(curEnd, desiredEnd);
                        
                        //{
                        //    Color c = Color.FromNonPremultiplied(new Vector4(4 * (float) (distanceSq),
                        //        1 - 4 * (float) (distanceSq), 0, 1));
                        //    VRageRender.MyRenderProxy.DebugDrawLine3D(
                        //        Vector3D.Transform(lastEnd, worldMatrix),
                        //        Vector3D.Transform(curEnd, worldMatrix), c, c, false);
                        //}

                        // see if i'm already close enough
                        if (distanceSq > stopDistanceSq)
                        {
                            // create the vector to the current effector posm this is the difference vector
                            curVector = curEnd - rootPos;
                            // create the desired effector position vector
                            var targetVector = desiredEnd - rootPos;

                            // normalize the vectors (expensive, requires a sqrt)
                            // MZ: we don't need to do that
                            // curVector.Normalize();
                            // targetVector.Normalize();

                            double curVectorLenSq = curVector.LengthSquared();
                            double targetVectorLenSq = targetVector.LengthSquared();

                            // the dot product gives me the cosine of the desired angle
                            // cosAngle = curVector.Dot(targetVector);

                            double dotCurTarget = curVector.Dot(targetVector);

                            // if the dot product returns 1.0, i don't need to rotate as it is 0 degrees
                            // MZ: yes, but when does this happen to be exactly 1???
                            // if (cosAngle < 1.0)
                            if (dotCurTarget < 0 || dotCurTarget * dotCurTarget < curVectorLenSq * targetVectorLenSq * (1 - MyMathConstants.EPSILON))
                            {
                                // use the cross product to check which way to rotate
                                //var rotationAxis = curVector.Cross(targetVector);
                                //rotationAxis.Normalize();
                                //turnAngle = System.Math.Acos(cosAngle); // get the angle

                                // get the matrix needed to rotate to the desired position
                                //Matrix rotation = Matrix.CreateFromAxisAngle((Vector3) rotationAxis,
                                //    (float) turnAngle * gain);

                                // get the absolute matrix rotation ie - rotation including all the bones before
                                Matrix rotation;
                                float weight = 1 / (initialDistSqInv * (float)distanceSq + 1);
                                Vector3 weightedTarget = Vector3.Lerp(curVector, targetVector, weight);
                                Matrix.CreateRotationFromTwoVectors(ref curVector, ref weightedTarget, out rotation);
                                Matrix absoluteTransform = Matrix.Normalize(currentMatrix).GetOrientation() * rotation;

                                // MZ: faster
                                
                                // compute just the local matrix for the bone - need to multiply with inversion ot its parent matrix and original bind transform      

                                Matrix parentMatrix = Matrix.Identity;
                                if (bone.Parent != null) parentMatrix = bone.Parent.AbsoluteTransform;
                                parentMatrix = Matrix.Normalize(parentMatrix); // may have different scale

                                Matrix localTransform = Matrix.Multiply(absoluteTransform,
                                    Matrix.Invert(bone.BindTransform * parentMatrix));

                                // now change the current matrix rotation                           
                                bone.Rotation = Quaternion.CreateFromRotationMatrix(localTransform);

                                // and recompute the transformation
                                bone.ComputeAbsoluteTransform();
                            }
                        }

                    }

                    // quit if i am close enough or been running long enough
                } while (tries++ < maxTries &&
                         Vector3D.DistanceSquared(curEnd, desiredEnd) > stopDistanceSq);
            }

            // solve the last bone
            if (finalTransform.IsValid())
            {
                // get the related transformation to original binding posefirstBoneAbsoluteTransform
                MatrixD localTransformRelated;

                if (allowFinalBoneTranslation) 
                    localTransformRelated = finalTransform * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);
                else
                    localTransformRelated = finalTransform.GetOrientation() * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);

                // localTransformRelated = Matrix.Normalize(localTransformRelated);
                // from there get the rotation and translation
                finalBone.Rotation = Quaternion.CreateFromRotationMatrix(Matrix.Normalize((Matrix)localTransformRelated.GetOrientation()));
                if (allowFinalBoneTranslation) 
                    finalBone.Translation = (Vector3)localTransformRelated.Translation;

                finalBone.ComputeAbsoluteTransform();
            }

            return true;//Vector3D.DistanceSquared(curEnd, desiredEnd) <= stopDistanceSq;
        }
        /// <summary>
        /// Updates feet bones positions, locations and rotation using IK, based on current character state
        /// </summary>
        private void UpdateFeet()
        {
            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("UpdateFeetPlacement standing");

            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_SETTINGS)
            {
                MyFeetIKSettings feetDebugSettings;
                CharacterDefinition.FeetIKSettings.TryGetValue(MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_MOVEMENT_STATE, out feetDebugSettings);
                Matrix  leftFootMatrix          = Bones[m_leftAnkleBone].AbsoluteTransform;
                Matrix  rightFootMatrix         = Bones[m_rightAnkleBone].AbsoluteTransform;
                Vector3 upDirection             = WorldMatrix.Up;
                Vector3 leftFootGroundPosition  = new Vector3(leftFootMatrix.Translation.X, 0, leftFootMatrix.Translation.Z);
                Vector3 rightFootGroundPosition = new Vector3(rightFootMatrix.Translation.X, 0, rightFootMatrix.Translation.Z);
                Vector3 fromL = Vector3.Transform(leftFootGroundPosition, WorldMatrix);  // we get this position in the world
                Vector3 fromR = Vector3.Transform(rightFootGroundPosition, WorldMatrix);
                VRageRender.MyRenderProxy.DebugDrawLine3D(fromL, fromL + upDirection * feetDebugSettings.AboveReachableDistance, Color.Yellow, Color.Yellow, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(fromL, fromL - upDirection * feetDebugSettings.BelowReachableDistance, Color.Red, Color.Red, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(fromR, fromR + upDirection * feetDebugSettings.AboveReachableDistance, Color.Yellow, Color.Yellow, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(fromR, fromR - upDirection * feetDebugSettings.BelowReachableDistance, Color.Red, Color.Red, false);
                Matrix leftFoot  = Matrix.CreateScale(feetDebugSettings.FootSize) * WorldMatrix;
                Matrix rightFoot = Matrix.CreateScale(feetDebugSettings.FootSize) * WorldMatrix;
                leftFoot.Translation  = fromL;
                rightFoot.Translation = fromR;
                VRageRender.MyRenderProxy.DebugDrawOBB(leftFoot, Color.White, 1f, false, false);
                VRageRender.MyRenderProxy.DebugDrawOBB(rightFoot, Color.White, 1f, false, false);
            }

            MyFeetIKSettings feetSettings;

            var characterBones = Character.AnimationController.CharacterBones;

            if (CharacterDefinition.FeetIKSettings.TryGetValue(MovementState, out feetSettings))
            {
                // If Feet IK placement is enabled for this character movement state, let's calculate new foot positions
                if (feetSettings.Enabled)
                {
                    UpdateFeetPlacement(WorldMatrix.Up,
                                        feetSettings.BelowReachableDistance,
                                        feetSettings.AboveReachableDistance,
                                        feetSettings.VerticalShiftUpGain,
                                        feetSettings.VerticalShiftDownGain,
                                        feetSettings.FootSize);
                }
            }
            else if (characterBones[m_rootBone].Translation != Vector3.Zero)
            {
                // Otherwise remove the applied translation on the root bone
                characterBones[m_rootBone].Translation = characterBones[m_rootBone].Translation.LengthSquared() > 0.001f ? characterBones[m_rootBone].Translation * 0.1f : Vector3.Zero;
                characterBones[m_rootBone].ComputeAbsoluteTransform();
            }

            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();

            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("Storing bones transforms");

            // After the feet placement we need to save new bone transformations
            for (int i = 0; i < Bones.Length; i++)
            {
                MyCharacterBone bone = Bones[i];
                bone.ComputeBoneTransform();
                Character.BoneRelativeTransforms[i] = bone.RelativeTransform;
            }

            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();
        }
        public static bool SolveTwoJointsIkCCD(ref Vector3 desiredEnd, MyCharacterBone firstBone, MyCharacterBone secondBone, MyCharacterBone endBone, ref Matrix finalTransform, Matrix WorldMatrix, MyCharacterBone finalBone = null, bool allowFinalBoneTranslation = true)
        {
            Vector3D rootPos, curEnd, targetVector, curVector, crossResult;
            double cosAngle, turnAngle;
            List<MyCharacterBone> bones = new List<MyCharacterBone>();
            bones.Add(firstBone);
            bones.Add(secondBone);
            bones.Add(endBone);

          
            int tries = 0;
            int maxTries = 50;
            float stopDistance = 0.00001f;
            float gain = 0.6f;

            curEnd = Vector3.Zero;

            do
            {
                foreach (MyCharacterBone bone in bones.Reverse<MyCharacterBone>())
                {
                    // first recalculate current final transformation
                    endBone.ComputeAbsoluteTransform();

                    // compute the position of the root
                    Matrix currentMatrix = bone.AbsoluteTransform;
                    rootPos = (Vector3D)currentMatrix.Translation;  // this is this bone root position
                    curEnd = (Vector3D)endBone.AbsoluteTransform.Translation;   // this is our current end of the final bone                  

                    // get the difference from desired and and current final position
                    double distance = Vector3D.DistanceSquared(curEnd, desiredEnd);

                    // see if i'm already close enough
                    if (distance > stopDistance)
                    {
                        // create the vector to the current effector posm this is the difference vector
                        curVector = curEnd - rootPos;
                        // create the desired effector position vector
                        targetVector = desiredEnd - rootPos;

                        // normalize the vectors (expensive, requires a sqrt)
                        curVector.Normalize();
                        targetVector.Normalize();

                        // the dot product gives me the cosine of the desired angle
                        cosAngle = curVector.Dot(targetVector);

                        // if the dot product returns 1.0, i don't need to rotate as it is 0 degrees
                        if (cosAngle < 1.0)
                        {
                            // use the cross product to check which way to rotate
                            crossResult = curVector.Cross(targetVector);
                            crossResult.Normalize();
                            turnAngle = System.Math.Acos(cosAngle);	// get the angle

                            // get the matrix needed to rotate to the desired position
                            Matrix rotation = Matrix.CreateFromAxisAngle((Vector3)crossResult, (float)turnAngle * gain);

                            // get the absolute matrix rotation ie - rotation including all the bones before
                            Matrix absoluteTransform = Matrix.Normalize(currentMatrix).GetOrientation() * rotation;

                            // compute just the local matrix for the bone - need to multiply with inversion ot its parent matrix and original bind transform      

                            Matrix parentMatrix = Matrix.Identity;
                            if (bone.Parent != null) parentMatrix = bone.Parent.AbsoluteTransform;
                            parentMatrix = Matrix.Normalize(parentMatrix); // may have different scale

                            Matrix localTransform = Matrix.Multiply(absoluteTransform, Matrix.Invert(bone.BindTransform * parentMatrix));

                            // now change the current matrix rotation                           
                            bone.Rotation = Quaternion.CreateFromRotationMatrix(localTransform);

                            // and recompute the transformation
                            bone.ComputeAbsoluteTransform();
                        }
                    }

                }

                // quit if i am close enough or been running long enough
            } while (tries++ < maxTries &&
                Vector3D.DistanceSquared(curEnd, desiredEnd) > stopDistance);

            // solve the last bone
            if (finalBone != null && finalTransform.IsValid())
            {
                //MatrixD absoluteTransformEnd = finalBone.AbsoluteTransform * finalTransform; // this is our local final transform ( rotation)

                // get the related transformation to original binding posefirstBoneAbsoluteTransform
                MatrixD localTransformRelated;

                if (allowFinalBoneTranslation) localTransformRelated = finalTransform * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);
                else localTransformRelated = finalTransform.GetOrientation() * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);

                //localTransformRelated = Matrix.Normalize(localTransformRelated);
                // from there get the rotation and translation
                finalBone.Rotation = Quaternion.CreateFromRotationMatrix(Matrix.Normalize((Matrix)localTransformRelated.GetOrientation()));
                if (allowFinalBoneTranslation) finalBone.Translation = (Vector3)localTransformRelated.Translation;
                finalBone.ComputeAbsoluteTransform();
            }

            return Vector3D.DistanceSquared(curEnd, desiredEnd) <= stopDistance;
        }
        /// <summary>
        /// This updates the foot placement in the world using raycasting and finding closest support.
        /// </summary>
        /// <param name="upDirection">This direction is used to raycast from feet - must be normalized!</param>
        /// <param name="underFeetReachableDistance">How below the original position can character reach down with legs</param>
        /// <param name="maxFootHeight">How high from the original position can be foot placed</param>
        /// <param name="verticalChangeGainUp">How quickly we raise up the character</param>
        /// <param name="verticalChangeGainDown">How quickly we crouch down</param>
        /// <param name="maxDistanceSquared">This is the maximal error in foot placement</param>
        /// <param name="footDimensions">This is foot dimensions, in Y axis is the ankle's height</param>
        /// <param name="footPlacementDistanceSquared">This is the distance limit between calculated and current position to start IK on foot placement</param>
        void UpdateFeetPlacement(Vector3 upDirection, float belowCharacterReachableDistance, float aboveCharacterReachableDistance, float verticalShiftUpGain, float verticalShiftDownGain, Vector3 footDimensions)
        {
            Debug.Assert(footDimensions != Vector3.Zero, "void UpdateFeetPlacement(...) : foot dimensions can not be zero!");

            // angle height above ground
            float ankleHeight = footDimensions.Y;

            // get the current foot matrix and location
            Matrix          invWorld            = Character.PositionComp.WorldMatrixInvScaled;
            MyCharacterBone rootBone            = Bones[m_rootBone]; // root bone is used to transpose the model up or down
            Matrix          modelRootBoneMatrix = rootBone.AbsoluteTransform;
            // current model shift in local coords - this is not changed by animations
            float verticalShift = modelRootBoneMatrix.Translation.Y;
            // current local feet matrices
            Matrix leftFootMatrix  = Bones[m_leftAnkleBone].AbsoluteTransform;
            Matrix rightFootMatrix = Bones[m_rightAnkleBone].AbsoluteTransform;

            // ok first we get the closest support to feet and we need to know from where to raycast for each foot in world coords
            // we need to raycast from original ground position of the feet, no from the character shifted position
            // we cast from the ground of the model space, assuming the model's local space up vector is in Y axis
            Vector3 leftFootGroundPosition  = new Vector3(leftFootMatrix.Translation.X, 0, leftFootMatrix.Translation.Z);
            Vector3 rightFootGroundPosition = new Vector3(rightFootMatrix.Translation.X, 0, rightFootMatrix.Translation.Z);
            Vector3 fromLWrld = Vector3.Transform(leftFootGroundPosition, WorldMatrix);  // we get this position in the world
            Vector3 fromRWrld = Vector3.Transform(rightFootGroundPosition, WorldMatrix);

            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("GetClosestFootPosition");

            // find the closest ground support, raycasting from Up to Down
            var contactLeftWrld  = MyInverseKinematics.GetClosestFootSupportPosition(Character, null, fromLWrld, upDirection, footDimensions, WorldMatrix, belowCharacterReachableDistance, aboveCharacterReachableDistance, Character.Physics.CharacterCollisionFilter);       // this returns world coordinates of support for left foot
            var contactRightWrld = MyInverseKinematics.GetClosestFootSupportPosition(Character, null, fromRWrld, upDirection, footDimensions, WorldMatrix, belowCharacterReachableDistance, aboveCharacterReachableDistance, Character.Physics.CharacterCollisionFilter);

            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();


            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("Characters root shift estimation");

            // if we got hit only for one feet, we do nothing, but slowly return back root bone (character vertical shift) position if it was changed from original
            // that happends very likely when the support below is too far for one leg
            if (contactLeftWrld == null || contactRightWrld == null)
            {
                rootBone.Translation -= rootBone.Translation * verticalShiftUpGain;
                rootBone.ComputeAbsoluteTransform();
                VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();
                return;
            }

            // Here we recalculate if we shift the root of the character to reach bottom or top
            // get the desired foot world coords

            Vector3 supportLWrld = contactLeftWrld.Value.Position;
            Vector3 supportRWrld = contactRightWrld.Value.Position;

            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_CLOSESTSUPPORTPOSITION)
            {
                VRageRender.MyRenderProxy.DebugDrawText3D(supportLWrld, "Foot support position", Color.Blue, 1, false);
                VRageRender.MyRenderProxy.DebugDrawText3D(supportRWrld, "Foot support position", Color.Blue, 1, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(supportLWrld, 0.03f, Color.Blue, 0, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(supportRWrld, 0.03f, Color.Blue, 0, false);
            }

            // If the terrain is slope we need to shift the desired position up a little..
            float leftCrossProd         = Vector3.Dot(WorldMatrix.Up, contactLeftWrld.Value.Normal);
            float rightCrossProd        = Vector3.Dot(WorldMatrix.Up, contactRightWrld.Value.Normal);
            float leftSlopeShiftFactor  = (1f - leftCrossProd) * footDimensions.Z * 0.5f;
            float rightSlopeShiftFactor = (1f - rightCrossProd) * footDimensions.Z * 0.5f;

            // First get the local coords of the ankles as if were driven by animation only - correct it if root bone location was shifted
            Vector3 leftAnklePosFromAnim  = Vector3.Up * (leftFootMatrix.Translation.Y - verticalShift);
            Vector3 rightAnklePosFromAnim = Vector3.Up * (rightFootMatrix.Translation.Y - verticalShift);

            // Now compute the desired ankle's positions in the model's local space
            Vector3 leftAnkleDesiredPosition  = Vector3.Transform(supportLWrld, invWorld) + leftAnklePosFromAnim + Vector3.Up * (FEET_ABOVE_GROUND_OFFSET + leftSlopeShiftFactor);
            Vector3 rightAnkleDesiredPosition = Vector3.Transform(supportRWrld, invWorld) + rightAnklePosFromAnim + Vector3.Up * (FEET_ABOVE_GROUND_OFFSET + rightSlopeShiftFactor);

            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_ANKLE_DESIREDPOSITION)
            {
                VRageRender.MyRenderProxy.DebugDrawText3D(Vector3.Transform(leftAnkleDesiredPosition, WorldMatrix), "Ankle desired position", Color.Purple, 1, false);
                VRageRender.MyRenderProxy.DebugDrawText3D(Vector3.Transform(rightAnkleDesiredPosition, WorldMatrix), "Ankle desired position", Color.Purple, 1, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(Vector3.Transform(leftAnkleDesiredPosition, WorldMatrix), 0.03f, Color.Purple, 0, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(Vector3.Transform(rightAnkleDesiredPosition, WorldMatrix), 0.03f, Color.Purple, 0, false);
            }

            // Get the height of found support related to character's position in model's local space, assuming it's Y axis
            float leftAnkleDesiredHeight  = leftAnkleDesiredPosition.Y;
            float rightAnkleDesiredHeight = rightAnkleDesiredPosition.Y;
            float currentLeftAnkleHeight  = leftFootMatrix.Translation.Y;
            float currentRightAnkleHeight = rightFootMatrix.Translation.Y;

            // if we the distances are too big, so we will not be able to set the position, we can skip it
            if (Math.Abs(leftAnkleDesiredHeight - rightAnkleDesiredHeight) > aboveCharacterReachableDistance)
            {
                rootBone.Translation = modelRootBoneMatrix.Translation -= modelRootBoneMatrix.Translation * verticalShiftUpGain;
                rootBone.ComputeAbsoluteTransform();
                VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();
                return;
            }

            // if we got one of the supports below the character root, we must check whether we can reach it, if yes, we need to crouch to reach it
            if ((((leftAnkleDesiredHeight > -belowCharacterReachableDistance) && (leftAnkleDesiredHeight < ankleHeight)) ||      // left support is below model and is reachable
                 ((rightAnkleDesiredHeight > -belowCharacterReachableDistance) && (rightAnkleDesiredHeight < ankleHeight))) &&   // right support is below model and is reachable
                // finally check if character is shifted down, the other feet won't get too high
                (Math.Max(leftAnkleDesiredHeight, rightAnkleDesiredHeight) - Math.Min(leftAnkleDesiredHeight, rightAnkleDesiredHeight) < aboveCharacterReachableDistance))
            {
                // then we can try to reach down according to the difference
                float   distanceBelow       = Math.Min(leftAnkleDesiredHeight - currentLeftAnkleHeight, rightAnkleDesiredHeight - currentRightAnkleHeight);// -verticalShift;// -ankleHeight;
                Vector3 verticalTranslation = Vector3.Up * distanceBelow;
                Vector3 translation         = Vector3.Zero;
                translation.Interpolate3(modelRootBoneMatrix.Translation, modelRootBoneMatrix.Translation + verticalTranslation, verticalShiftDownGain);

                if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_ANKLE_DESIREDPOSITION)
                {
                    VRageRender.MyRenderProxy.DebugDrawLine3D(WorldMatrix.Translation, Vector3.Transform(Vector3.Up * distanceBelow, WorldMatrix), Color.Purple, Color.Purple, false);
                    VRageRender.MyRenderProxy.DebugDrawText3D(WorldMatrix.Translation, "Computed height", Color.Purple, 1, false);
                }

                rootBone.Translation = modelRootBoneMatrix.Translation = translation;
                rootBone.ComputeAbsoluteTransform();
            }
            else // if both supports are up, we need to get up, however, that should be done by rigid body as well.. we limit it only by reachable distance, so it is bounded to rigid body position
            if ((leftAnkleDesiredHeight > ankleHeight) && (leftAnkleDesiredHeight < aboveCharacterReachableDistance) &&
                (rightAnkleDesiredHeight > ankleHeight) && (rightAnkleDesiredHeight < aboveCharacterReachableDistance))
            {
                // move up to reach the highest support
                float   distanceAbove       = Math.Max(leftAnkleDesiredHeight - currentLeftAnkleHeight, rightAnkleDesiredHeight - currentRightAnkleHeight);// -verticalShift;// -ankleHeight;
                Vector3 verticalTranslation = Vector3.Up * distanceAbove;
                Vector3 translation         = Vector3.Zero;
                translation.Interpolate3(modelRootBoneMatrix.Translation, modelRootBoneMatrix.Translation + verticalTranslation, verticalShiftUpGain);
                rootBone.Translation = modelRootBoneMatrix.Translation = translation;
                rootBone.ComputeAbsoluteTransform();
            }
            // finally if we can not get into right vertical position for foot placement, slowly reset the vertical shift
            else
            {
                modelRootBoneMatrix.Translation -= modelRootBoneMatrix.Translation * verticalShiftUpGain;
                rootBone.Translation             = modelRootBoneMatrix.Translation;
                rootBone.ComputeAbsoluteTransform();
            }

            // Hard limit to root's shift in vertical position
            //if (characterVerticalShift < -underFeetReachableDistance)
            //{
            //    modelRootBoneMatrix.Translation = -upDirection * underFeetReachableDistance;
            //    rootBone.SetBindTransform(modelRootBoneMatrix);
            //    characterVerticalShift = -underFeetReachableDistance; // get the new height
            //}
            //if (characterVerticalShift > underFeetReachableDistance)
            //{
            //    modelRootBoneMatrix.Translation = upDirection * underFeetReachableDistance;
            //    rootBone.SetBindTransform(modelRootBoneMatrix);
            //    characterVerticalShift = underFeetReachableDistance; // get the new height
            //}

            // Then we need to recalculate all other bones matrices so we get proper data for children, since we changed the root position
            //foreach (var b in m_bones) b.ComputeAbsoluteTransform();
            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();

            VRageRender.MyRenderProxy.GetRenderProfiler().StartProfilingBlock("CalculateFeetPlacement");

            // Then recalculate feet positions only if we can reach the final and if we are in the limits
            if ((-belowCharacterReachableDistance < leftAnkleDesiredHeight) && (leftAnkleDesiredHeight < aboveCharacterReachableDistance)) // and the found foot support height is not over limit
            {
                CalculateFeetPlacement(
                    m_leftHipBone,
                    m_leftKneeBone,
                    m_leftAnkleBone,
                    leftAnkleDesiredPosition,
                    contactLeftWrld.Value.Normal,
                    footDimensions,
                    leftFootMatrix.Translation.Y - verticalShift <= ankleHeight);
            }

            if ((-belowCharacterReachableDistance < rightAnkleDesiredHeight) && (rightAnkleDesiredHeight < aboveCharacterReachableDistance))
            {
                CalculateFeetPlacement(
                    m_rightHipBone,
                    m_rightKneeBone,
                    m_rightAnkleBone,
                    rightAnkleDesiredPosition,
                    contactRightWrld.Value.Normal,
                    footDimensions,
                    rightFootMatrix.Translation.Y - verticalShift <= ankleHeight);
            }

            VRageRender.MyRenderProxy.GetRenderProfiler().EndProfilingBlock();

            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_BONES)
            {
                List <Matrix> left = new List <Matrix> {
                    Bones[m_leftHipBone].AbsoluteTransform, Bones[m_leftKneeBone].AbsoluteTransform, Bones[m_leftAnkleBone].AbsoluteTransform
                };
                List <Matrix> right = new List <Matrix> {
                    Bones[m_rightHipBone].AbsoluteTransform, Bones[m_rightKneeBone].AbsoluteTransform, Bones[m_rightAnkleBone].AbsoluteTransform
                };
                DebugDrawBones(left);
                DebugDrawBones(right);
                VRageRender.MyRenderProxy.DebugDrawText3D(WorldMatrix.Translation, "Rigid body", Color.Yellow, 1, false);
                VRageRender.MyRenderProxy.DebugDrawSphere(WorldMatrix.Translation, 0.05f, Color.Yellow, 0, false);
                VRageRender.MyRenderProxy.DebugDrawText3D((modelRootBoneMatrix * WorldMatrix).Translation, "Character root bone", Color.Yellow, 1, false);
                VRageRender.MyRenderProxy.DebugDrawSphere((modelRootBoneMatrix * WorldMatrix).Translation, 0.07f, Color.Red, 0, false);
            }
        }
        /// <summary>
        /// Analytic solutions useful fo hands or feet, all in local model space
        /// </summary>
        /// <param name="desiredEnd">in local model space</param>
        /// <param name="firstBone"></param>
        /// <param name="secondBone"></param>
        /// <param name="finalTransform"></param>
        /// <param name="finalBone"></param>
        /// <param name="allowFinalBoneTranslation"></param>
        /// <returns></returns>
        public static bool SolveTwoJointsIk(ref Vector3 desiredEnd, MyCharacterBone firstBone, MyCharacterBone secondBone, MyCharacterBone endBone, ref Matrix finalTransform, Matrix WorldMatrix, MyCharacterBone finalBone = null, bool allowFinalBoneTranslation = true)
        {
            Matrix firstBoneAbsoluteTransform = firstBone.AbsoluteTransform;
            Matrix secondBoneAbsoluteTransform = secondBone.AbsoluteTransform;
            Matrix endBoneAbsoluteTransform = endBone.AbsoluteTransform;

            Vector3 origin = firstBoneAbsoluteTransform.Translation;
            Vector3 originToCurrentEnd = endBoneAbsoluteTransform.Translation - origin;
            Vector3 originToDesiredEnd = desiredEnd - origin;
            Vector3 firstBoneVector = secondBoneAbsoluteTransform.Translation - origin;
            Vector3 secondBoneVector = originToCurrentEnd - firstBoneVector;
            float firstBoneLength = firstBoneVector.Length();
            float secondBoneLength = secondBoneVector.Length();
            float originToDesiredEndLength = originToDesiredEnd.Length();
            float originToCurrentEndLength = originToCurrentEnd.Length();

            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_IKSOLVERS)
            {
                VRageRender.MyRenderProxy.DebugDrawSphere(Vector3.Transform(desiredEnd, WorldMatrix), 0.01f, Color.Red, 1, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + originToCurrentEnd, WorldMatrix), Color.Yellow, Color.Yellow, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + originToDesiredEnd, WorldMatrix), Color.Red, Color.Red, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + firstBoneVector, WorldMatrix), Color.Green, Color.Green, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin + firstBoneVector, WorldMatrix), Vector3.Transform(origin + firstBoneVector + secondBoneVector, WorldMatrix), Color.Blue, Color.Blue, false);
            }

            // only two cases, the desired position is reachable or not
            bool isDesiredEndReachable = firstBoneLength + secondBoneLength > originToDesiredEndLength;

            // alpha = angle between the first bone and originToDesiredEnd vector
            double finalAlpha = 0;

            // beta = the angle between the first and second bone
            double finalBeta = 0;

            if (isDesiredEndReachable)
            {   // we find proper angles 
                // cosine law c^2 = a^2 + b^2 - 2*a*b*cos(gamma)
                // gamma = acos ( - (c^2 - a^2 - b^2) / (2*a*b) )

                // alpha = angle between the first bone and originToDesiredEnd vector
                double cosAlpha = -(secondBoneLength * secondBoneLength - firstBoneLength * firstBoneLength - originToDesiredEndLength * originToDesiredEndLength) /
                    (2 * firstBoneLength * originToDesiredEndLength);
                cosAlpha = MathHelper.Clamp(cosAlpha, -1, 1);
                finalAlpha = Math.Acos(cosAlpha);

                // beta = the angle between the first and second bone
                double cosBeta = -(originToDesiredEndLength * originToDesiredEndLength - firstBoneLength * firstBoneLength - secondBoneLength * secondBoneLength) /
                    (2 * firstBoneLength * secondBoneLength);
                cosBeta = MathHelper.Clamp(cosBeta, -1, 1);
                finalBeta = Math.Acos(cosBeta);
                // now get it to the root bone axis no
                finalBeta = Math.PI - finalBeta;
            }


            // get the current angles
            double cCosAlpha = -(secondBoneLength * secondBoneLength - firstBoneLength * firstBoneLength - originToCurrentEndLength * originToCurrentEndLength) /
                (2 * firstBoneLength * originToCurrentEndLength);
            cCosAlpha = MathHelper.Clamp(cCosAlpha, -1, 1);
            double currentAlpha = Math.Acos(cCosAlpha);
            double cCosBeta = -(originToCurrentEndLength * originToCurrentEndLength - firstBoneLength * firstBoneLength - secondBoneLength * secondBoneLength) /
                (2 * firstBoneLength * secondBoneLength);
            cCosBeta = MathHelper.Clamp(cCosBeta, -1, 1);
            double currentBeta = Math.Acos(cCosBeta);
            currentBeta = Math.PI - currentBeta;

            Vector3 currentPlaneNormal = Vector3.Cross(firstBoneVector, originToCurrentEnd);
            currentPlaneNormal.Normalize();

            // we can now rotate the bones in current plane as if the desired end was on the currentEnd axis
            float alphaDif = (float)(finalAlpha - currentAlpha);
            float betaDif = (float)(finalBeta - currentBeta);
            Matrix firstBoneRotation = Matrix.CreateFromAxisAngle(-currentPlaneNormal, alphaDif);
            Matrix secondBoneRotation = Matrix.CreateFromAxisAngle(currentPlaneNormal, betaDif);


            // now get the angle between original and final position plane normal
            originToCurrentEnd.Normalize();
            originToDesiredEnd.Normalize();
            double dotProd = originToCurrentEnd.Dot(originToDesiredEnd);

            dotProd = MathHelper.Clamp(dotProd, -1, 1);
            double delta = Math.Acos(dotProd);
            Vector3 planeRotationAxis = Vector3.Cross(originToCurrentEnd, originToDesiredEnd);
            planeRotationAxis.Normalize();

            // find the rotation matrices for bones in the original plane
            Matrix planeRotation = Matrix.CreateFromAxisAngle(planeRotationAxis, (float)delta);

            // compute the final rotations
            firstBoneRotation = planeRotation * firstBoneRotation;
            secondBoneRotation = secondBoneRotation * firstBoneRotation;

            // draw the final positions if debug enabled
            if (MyDebugDrawSettings.ENABLE_DEBUG_DRAW && MyDebugDrawSettings.DEBUG_DRAW_CHARACTER_IK_IKSOLVERS)
            {
                Vector3 rotatedFirst = Vector3.Transform(firstBoneVector, firstBoneRotation);
                Vector3 rotatedSecond = Vector3.Transform(secondBoneVector, secondBoneRotation);
                VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin, WorldMatrix), Vector3.Transform(origin + rotatedFirst, WorldMatrix), Color.Purple, Color.Purple, false);
                VRageRender.MyRenderProxy.DebugDrawLine3D(Vector3.Transform(origin + rotatedFirst, WorldMatrix), Vector3.Transform(origin + rotatedFirst + rotatedSecond, WorldMatrix), Color.White, Color.White, false);
            }

            // Now we compute the final absolute transforms for the bones
            Matrix firstBoneFinalAbsoluteTransform = firstBoneAbsoluteTransform * firstBoneRotation;
            Matrix firstBoneParentAbsoluteTransform = firstBone.Parent.AbsoluteTransform;
            Matrix localFirstBoneTransform = Matrix.Multiply(firstBoneFinalAbsoluteTransform, Matrix.Invert(firstBone.BindTransform * firstBoneParentAbsoluteTransform));
            firstBone.Rotation = Quaternion.CreateFromRotationMatrix(localFirstBoneTransform);
            firstBone.ComputeAbsoluteTransform();

            Matrix secondBoneFinalAbsoluteTransform = secondBoneAbsoluteTransform * secondBoneRotation;
            Matrix secondBoneParentAbsoluteTransform = secondBone.Parent.AbsoluteTransform;
            Matrix localSecondBoneTransform = Matrix.Multiply(secondBoneFinalAbsoluteTransform, Matrix.Invert(secondBone.BindTransform * secondBoneParentAbsoluteTransform));

            secondBone.Rotation = Quaternion.CreateFromRotationMatrix(localSecondBoneTransform);
            secondBone.ComputeAbsoluteTransform();

            // solve the last bone 
            if (finalBone != null && finalTransform.IsValid() && isDesiredEndReachable)
            {
                //MatrixD absoluteTransformEnd = finalBone.AbsoluteTransform * finalTransform; // this is our local final transform ( rotation)

                // get the related transformation to original binding pose
                MatrixD localTransformRelated;

                if (allowFinalBoneTranslation) localTransformRelated = finalTransform * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);
                else localTransformRelated = finalTransform.GetOrientation() * MatrixD.Invert((MatrixD)finalBone.BindTransform * finalBone.Parent.AbsoluteTransform);

                //localTransformRelated = Matrix.Normalize(localTransformRelated);
                // from there get the rotation and translation
                finalBone.Rotation = Quaternion.CreateFromRotationMatrix(Matrix.Normalize((Matrix)localTransformRelated.GetOrientation()));
                if (allowFinalBoneTranslation) finalBone.Translation = (Vector3)localTransformRelated.Translation;
                finalBone.ComputeAbsoluteTransform();
            }

            return isDesiredEndReachable;
        }
Esempio n. 21
0
        private void IKFeetStepSounds(MyEntity3DSoundEmitter walkEmitter, MySoundPair cueEnum)
        {
            var movementState = m_character.GetCurrentMovementState();

            if (movementState.GetMode() == MyCharacterMovement.Flying)
            {
                return;
            }

            if (movementState.GetSpeed() != m_lastUpdateMovementState.GetSpeed())
            {
                walkEmitter.StopSound(true);
                m_lastStepTime = 0;
            }

            int usedMinimumDelay = int.MaxValue;

            if (movementState.GetDirection() != MyCharacterMovement.NoDirection)
            {
                switch (movementState.GetSpeed())
                {
                case MyCharacterMovement.NormalSpeed:
                    usedMinimumDelay = m_stepMinimumDelayWalk;
                    break;

                case MyCharacterMovement.Fast:
                    usedMinimumDelay = m_stepMinimumDelayRun;
                    break;

                case MyCharacterMovement.VeryFast:
                    usedMinimumDelay = m_stepMinimumDelaySprint;
                    break;
                }
            }

            bool minimumDelayExceeded = false;

            minimumDelayExceeded = (MySandboxGame.TotalGamePlayTimeInMilliseconds - m_lastStepTime) >= usedMinimumDelay;
            //MyRenderProxy.DebugDrawAABB(m_character.PositionComp.WorldAABB, Color.White);

            if (minimumDelayExceeded)
            {
                int             leftAnkleBoneIndex, rightAnkleBoneIndex;
                MyCharacterBone leftAnkleBone = m_character.AnimationController != null
                    ? m_character.AnimationController.FindBone(m_character.Definition.LeftAnkleBoneName, out leftAnkleBoneIndex)
                    : null;

                MyCharacterBone rightAnkleBone = m_character.AnimationController != null
                    ? m_character.AnimationController.FindBone(m_character.Definition.RightAnkleBoneName, out rightAnkleBoneIndex)
                    : null;

                Vector3 posLeftFoot = leftAnkleBone != null
                    ? leftAnkleBone.AbsoluteTransform.Translation
                    : m_character.PositionComp.LocalAABB.Center;
                Vector3 posRightFoot = rightAnkleBone != null
                    ? rightAnkleBone.AbsoluteTransform.Translation
                    : m_character.PositionComp.LocalAABB.Center;
                float            ankleHeight;
                MyFeetIKSettings settingsIK;
                if (m_character.Definition.FeetIKSettings != null &&
                    m_character.Definition.FeetIKSettings.TryGetValue(MyCharacterMovementEnum.Standing, out settingsIK))
                {
                    ankleHeight = settingsIK.FootSize.Y;
                }
                else
                {
                    ankleHeight = DEFAULT_ANKLE_HEIGHT;
                }
                float charSpeed = 0f;
                if (m_character.AnimationController != null)
                {
                    m_character.AnimationController.Variables.GetValue(MyAnimationVariableStorageHints.StrIdSpeed, out charSpeed);
                }
                if (posLeftFoot.Y - ankleHeight < m_character.PositionComp.LocalAABB.Min.Y ||
                    posRightFoot.Y - ankleHeight < m_character.PositionComp.LocalAABB.Min.Y)
                {
                    if (charSpeed > 0.05f)
                    {
                        walkEmitter.PlaySound(cueEnum);
                    }
                    m_lastStepTime = MySandboxGame.TotalGamePlayTimeInMilliseconds;
                }
            }

            m_lastUpdateMovementState = movementState;
        }
Esempio n. 22
0
            /// <summary>
            /// Assign this bone to the correct bone in the model
            /// </summary>
            /// <param name="model"></param>
            public void SetModel(MySkinnedEntity skinnedEntity)
            {
                if (ClipBone == null)
                    return;

                // Find this bone
                int index;
                m_assignedBone = skinnedEntity.FindBone(ClipBone.Name, out index);
            }
Esempio n. 23
0
 public unsafe void BlendWeight(ref float weight, MyCharacterBone bone, IMyVariableStorage <float> controllerVariables)
 {
     if (this.m_boneIndexToData.Length > bone.Index)
     {
         float    num;
         float    num2;
         BoneData data = this.m_boneIndexToData[bone.Index];
         if (!controllerVariables.GetValue(this.m_defautlBlendTimeId, out this.m_defaultBlendTime))
         {
             this.m_defaultBlendTime = 2.5f;
         }
         if (!controllerVariables.GetValue(data.WeightId, out num) || (num < 0f))
         {
             num = -1f;
         }
         if (!controllerVariables.GetValue(data.BlendTimeId, out num2) || (num2 < 0f))
         {
             num2 = -1f;
         }
         if ((num < 0f) || (num2 < 0f))
         {
             float       maxValue = float.MaxValue;
             float       num6     = float.MaxValue;
             LayerData[] layers   = data.Layers;
             int         index    = 0;
             while (true)
             {
                 float num8;
                 float num9;
                 if (index >= layers.Length)
                 {
                     if (num < 0f)
                     {
                         if (maxValue == float.MaxValue)
                         {
                             return;
                         }
                         num = maxValue;
                     }
                     if (num2 < 0f)
                     {
                         num2 = (num6 == float.MaxValue) ? this.m_defaultBlendTime : num6;
                     }
                     break;
                 }
                 LayerData data2 = layers[index];
                 if (controllerVariables.GetValue(data2.LayerId, out num8))
                 {
                     maxValue = Math.Min(maxValue, num8);
                 }
                 if (controllerVariables.GetValue(data2.LayerBlendTimeId, out num9))
                 {
                     num6 = Math.Min(num6, num9);
                 }
                 index++;
             }
         }
         double totalMilliseconds = TIMER.ElapsedTimeSpan.TotalMilliseconds;
         data.BlendTimeMs = num2 * 1000f;
         if (num != data.TargetWeight)
         {
             data.StartedMs = totalMilliseconds;
             BoneData *dataPtr1 = (BoneData *)ref data;
             dataPtr1->StartingWeight = (data.PrevWeight == -1f) ? weight : data.PrevWeight;
             data.TargetWeight        = num;
         }
         double amount = MathHelper.Clamp((double)((totalMilliseconds - data.StartedMs) / data.BlendTimeMs), (double)0.0, (double)1.0);
         weight          = (float)MathHelper.Lerp((double)data.StartingWeight, (double)data.TargetWeight, amount);
         data.PrevWeight = weight;
         this.m_boneIndexToData[bone.Index] = data;
     }
 }