Beispiel #1
0
        public static IList <MuscleJoint> CopyHierarchy(IList <MuscleJoint> joints)
        {
            IList <MuscleJoint> mirrorJoints = new MuscleJoint[joints.Count];

            for (int i = 0; i < joints.Count; i++)
            {
                MuscleJoint originalJoint   = joints[i];
                Transform   mirrorTransform = new GameObject(joints[i].name + "_IK").transform;
                mirrorTransform.position = originalJoint.transform.position;
                mirrorTransform.rotation = originalJoint.transform.rotation;

                MuscleJoint mirrorJoint = mirrorTransform.gameObject.AddComponent <MuscleJoint>();
                mirrorJoint.Initialize(originalJoint);

                GameObject.Destroy(mirrorJoint.GetComponent <SphereCollider>()); // Todo: superhacky

                if (i > 0)
                {
                    mirrorTransform.parent = mirrorJoints[i - 1].transform;
                }

                mirrorJoints[i] = mirrorJoint;
            }
            return(mirrorJoints);
        }
Beispiel #2
0
 public static void MirrorHierarchy(IList <MuscleJoint> source, IList <MuscleJoint> target)
 {
     for (int i = 0; i < source.Count; i++)
     {
         MuscleJoint originalJoint   = source[i];
         MuscleJoint mirrorTransform = target[i];
         mirrorTransform.transform.position = originalJoint.transform.position;
         mirrorTransform.transform.rotation = originalJoint.transform.rotation;
     }
 }
Beispiel #3
0
        private static void RandomizeChain(MuscleJoint joint, float amount)
        {
            if (!joint.transform.parent)
            {
                return;
            }

            joint.transform.parent.localRotation = Quaternion.Slerp(
                joint.transform.parent.localRotation,
                Random.rotationUniform,
                amount);
        }
Beispiel #4
0
        private static Quaternion ClampLimitsEllipse(MuscleJoint joint, Quaternion proposedRotation)
        {
            Quaternion jointRotation = Quaternion.Inverse(joint.BaseLocalRotation) * proposedRotation;

            Vector3 proposedForward = jointRotation * Vector3.forward;

            Vector3 swingAxis = Vector3.Cross(Vector3.forward, proposedForward).normalized;
            float   angle     = MathUtils.AngleAroundAxis(Vector3.forward, proposedForward, swingAxis);

            angle = Mathf.Clamp(angle, -45f, 45f);

            return(joint.BaseLocalRotation * Quaternion.AngleAxis(angle, swingAxis));
        }
    /** Instantiates a muscle at the specified point. */
    private void CreateMuscleFromJoint(MuscleJoint joint)
    {
        Vector3 point = joint.position;

        point.z = 0;

        /*GameObject muscleEmpty = new GameObject();
        *  muscleEmpty.name = "Muscle";
        *  currentMuscle = muscleEmpty.AddComponent<Muscle>();
        *  currentMuscle.AddLineRenderer();
        *  currentMuscle.SetMaterial(muscleMaterial);*/
        //currentMuscle = ((GameObject) Instantiate(musclePreset, point, Quaternion.identity)).GetComponent<Muscle>();
        currentMuscle = Muscle.Create();
        currentMuscle.startingJoint = joint;
        currentMuscle.SetLinePoints(joint.position, joint.position);
    }
Beispiel #6
0
    private void ActivateMusclesJoint(float[] angles, MuscleJoint joint)
    {
        //YZ
        if (joint.musclesYZ != null && joint.musclesYZ.Length > 0)
        {
            if (angles[0] > 0)
            {
                joint.musclesYZ[0].targetLength = GetMuscleLengthFromAngle(joint.musclesYZ[0], angles[0]);
                joint.musclesYZ[0].Activate();
            }
            else
            {
                joint.musclesYZ[1].targetLength = GetMuscleLengthFromAngle(joint.musclesYZ[1], Mathf.Abs(angles[0]));
                joint.musclesYZ[1].Activate();
            }
        }

        //ZX
        if (joint.musclesZX != null && joint.musclesZX.Length > 0)
        {
            if (angles[1] > 0)
            {
                joint.musclesZX[0].targetLength = GetMuscleLengthFromAngle(joint.musclesZX[0], angles[1]);
                joint.musclesZX[0].Activate();
            }
            else
            {
                joint.musclesZX[1].targetLength = GetMuscleLengthFromAngle(joint.musclesZX[1], Mathf.Abs(angles[1]));
                joint.musclesZX[1].Activate();
            }
        }

        //XY
        if (joint.musclesXY != null && joint.musclesXY.Length > 0)
        {
            if (angles[2] > 0)
            {
                joint.musclesXY[0].targetLength = GetMuscleLengthFromAngle(joint.musclesXY[0], angles[2]);
                joint.musclesXY[0].Activate();
            }
            else
            {
                joint.musclesXY[1].targetLength = GetMuscleLengthFromAngle(joint.musclesXY[1], Mathf.Abs(angles[2]));
                joint.musclesXY[1].Activate();
            }
        }
    }
Beispiel #7
0
    // Todo: Locking joints by clicking on them
    private void Update()
    {
        // TODO Buttons don't work anymore
        bool mouseLeftDown = Input.GetButtonDown("unity_mouse_0");
        bool mouseLeftUp   = Input.GetButtonUp("unity_mouse_0");
        bool mouseLeft     = Input.GetButton("unity_mouse_0");

        Vector3 cursorPosition = Input.mousePosition;

        if (mouseLeftDown)
        {
            GameObject selectedObject = QueryCursor(cursorPosition);
            if (selectedObject)
            {
                MuscleJoint joint = selectedObject.GetComponent <MuscleJoint>();
                if (joint)
                {
                    StartDragging(joint);
                }
                else
                {
                    _camera.Center = selectedObject.transform.position;
                }
            }
        }
        if (mouseLeftUp)
        {
            StopDragging();
        }

        if (mouseLeft)
        {
            if (_isDragging)
            {
                Drag(cursorPosition);
            }
            else
            {
                Look();
            }
        }

        if (_jointHierarchy != null && _ikHierarchy != null)
        {
            IKSolver.Slerp(_ikHierarchy, _jointHierarchy, 10f * _clock.DeltaTime);
        }
    }
Beispiel #8
0
        private static Quaternion ClampLimitsEuler(MuscleJoint joint, Quaternion proposedRotation)
        {
            Quaternion jointRotation = Quaternion.Inverse(joint.BaseLocalRotation) * proposedRotation;

            float angleX = jointRotation.eulerAngles.x;
            float angleY = jointRotation.eulerAngles.y;
            float angleZ = jointRotation.eulerAngles.z;

            angleX = WrapAngle(angleX);
            angleY = WrapAngle(angleY);
            angleZ = WrapAngle(angleZ);

            angleX = Mathf.Clamp(angleX, joint.Limits.X.Min, joint.Limits.X.Max);
            angleY = Mathf.Clamp(angleY, joint.Limits.Y.Min, joint.Limits.Y.Max);
            angleZ = Mathf.Clamp(angleZ, joint.Limits.Z.Min, joint.Limits.Z.Max);

            return(joint.BaseLocalRotation * Quaternion.Euler(angleX, angleY, angleZ));
        }
Beispiel #9
0
    private void StartDragging(MuscleJoint joint)
    {
        _isDragging = true;

        if (_ikHierarchy != null)
        {
            DestroyHierarchy(_ikHierarchy);
        }

        _jointHierarchy    = IKSolver.GetHierarchy(joint);
        _ikHierarchy       = IKSolver.CopyHierarchy(_jointHierarchy);
        _ikTarget.position = joint.transform.position;
        _ikTarget.rotation = joint.transform.rotation;

        Vector3 screenSpacePosition = _camera.GetComponent <Camera>().WorldToScreenPoint(joint.transform.position);

        _dragDepth = screenSpacePosition.z;
        Vector3 cursorPosition = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpacePosition.z);

        _dragOffset = joint.transform.position - _camera.GetComponent <Camera>().ScreenToWorldPoint(cursorPosition);
    }
Beispiel #10
0
        public static IList <MuscleJoint> GetHierarchy(MuscleJoint root)
        {
            IList <MuscleJoint> joints = new List <MuscleJoint>();

            MuscleJoint joint = root;

            while (joint != null)
            {
                joints.Add(joint);
                joint = joint.transform.parent ? joint.transform.parent.GetComponent <MuscleJoint>() : null;
            }

            IList <MuscleJoint> orderedJoints = new List <MuscleJoint>();

            for (int i = 0; i < joints.Count; i++)
            {
                orderedJoints.Add(joints[joints.Count - 1 - i]);
            }

            return(orderedJoints);
        }
Beispiel #11
0
        private static bool IsWithinLimits(MuscleJoint joint, Quaternion proposedRotation)
        {
            Quaternion jointRotation = Quaternion.Inverse(joint.BaseLocalRotation) * proposedRotation;

            float angleX = jointRotation.eulerAngles.x;
            float angleY = jointRotation.eulerAngles.y;
            float angleZ = jointRotation.eulerAngles.z;

            angleX = WrapAngle(angleX);
            angleY = WrapAngle(angleY);
            angleZ = WrapAngle(angleZ);

            if (angleX > joint.Limits.X.Min || angleX < joint.Limits.X.Max ||
                angleY > joint.Limits.Y.Min || angleY < joint.Limits.Y.Max ||
                angleZ > joint.Limits.Z.Min || angleZ < joint.Limits.Z.Max)
            {
                return(false);
            }

            return(false);
        }
Beispiel #12
0
 public void Initialize(MuscleJoint joint)
 {
     _joint    = joint;
     _children = new List <IKJoint>();
 }
    /// <summary>
    /// Checks for click / touch events and handles them appropiately depending on the
    /// currently selected body part.
    /// </summary>
    private void HandleClicks()
    {
        // Middle click or two touches to move the camera
        if ((Input.GetMouseButton(2) && Input.touchCount == 0) || Input.touchCount == 2)
        {
            //if (EventSystem.current.IsPointerOverGameObject() || isPointerOverUIObject()) return;

            var position = Input.mousePosition;

            if (Input.touchCount == 2)
            {
                position = GetPinchCenter(Input.touches[0].position, Input.touches[1].position);
            }

            //position = ScreenToWorldPoint(position);


            var distance = lastTouchPos - position;
            lastTouchPos = position;

            if (firstMovementTouch)
            {
                firstMovementTouch = false;
                return;
            }

            firstMovementTouch = false;

            // move the camera by the distance
            distance = ScreenToWorldDistance(distance);
            buttonManager.MoveCamera(distance);

            return;
        }
        else
        {
            firstMovementTouch = true;
            lastTouchPos       = Vector3.zero;
        }

        if (Input.GetMouseButtonDown(0))                // user clicked

        {
            if (EventSystem.current.IsPointerOverGameObject())
            {
                return;
            }
            if (isPointerOverUIObject())
            {
                return;
            }

            if (selectedPart == BuildSelection.Joint)                                   // Place a JOINT

            {
                var pos = ScreenToWorldPoint(Input.mousePosition);
                pos.z = 0;
                // Grid logic
                if (grid.gameObject.activeSelf)
                {
                    pos = grid.ClosestPointOnGrid(pos);
                }

                // Make sure the joint doesn't overlap another one
                bool noOverlap = true;
                foreach (var joint in joints)
                {
                    if ((joint.center - pos).magnitude < jointNonOverlapRadius)
                    {
                        noOverlap = false;
                        break;
                    }
                }

                if (noOverlap)
                {
                    PlaceJoint(pos);
                }
            }
            else if (selectedPart == BuildSelection.Bone)                       // Start placing BONE
            // find the selected joint
            {
                Joint joint = GetHoveringObject <Joint>(joints);

                if (joint != null)
                {
                    CreateBoneFromJoint(joint);
                    PlaceConnectionBetweenPoints(currentBone.gameObject, joint.center, ScreenToWorldPoint(Input.mousePosition), CONNECTION_WIDHT);
                }
            }
            else if (selectedPart == BuildSelection.Muscle)                     // Start placing MUSCLE
            // find the selected bone
            {
                Bone bone = GetHoveringObject <Bone>(bones);

                if (bone != null)
                {
                    Vector3     mousePos = ScreenToWorldPoint(Input.mousePosition);
                    MuscleJoint joint    = bone.muscleJoint;

                    CreateMuscleFromJoint(joint);
                    //PlaceConnectionBetweenPoints(currentMuscle.gameObject, joint.position, mousePos, CONNECTION_WIDHT);
                    currentMuscle.SetLinePoints(joint.position, mousePos);
                }
            }
            else if (selectedPart == BuildSelection.Delete)                 // Delete selected object

            //UpdateDeletedObjects();

            {
                BodyComponent joint  = GetHoveringObject <Joint>(joints);
                BodyComponent bone   = GetHoveringObject <Bone>(bones);
                BodyComponent muscle = GetHoveringObject <Muscle>(muscles);

                BodyComponent toDelete = joint != null ? joint : (bone != null ? bone : muscle);

                if (toDelete != null)
                {
                    toDelete.Delete();
                    UpdateDeletedObjects();

                    ResetCurrentCreatureName();                     // The creature was modified

                    Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
                }

                //UpdateDeletedObjects();
            }
            else if (selectedPart == BuildSelection.Move)
            {
                // Make sure the user is hovering over a joint
                Joint joint = GetHoveringObject <Joint>(joints);

                if (joint != null)
                {
                    currentMovingJoint = joint;

                    ResetCurrentCreatureName();                     // The creature was modified
                }
            }
        }
        else if (Input.GetMouseButton(0))
        {
            // Mouse click & hold
            if (selectedPart == BuildSelection.Bone)
            {
                if (currentBone != null)
                {
                    // check if user is hovering over an ending joint which is not the same as the starting
                    // joint of the currentBone
                    Joint   joint       = GetHoveringObject <Joint>(joints);
                    Vector3 endingPoint = ScreenToWorldPoint(Input.mousePosition);

                    if (joint != null && !joint.Equals(currentBone.startingJoint))
                    {
                        endingPoint             = joint.center;
                        currentBone.endingJoint = joint;
                    }

                    PlaceConnectionBetweenPoints(currentBone.gameObject, currentBone.startingPoint, endingPoint, CONNECTION_WIDHT);
                }
            }
            else if (selectedPart == BuildSelection.Muscle)
            {
                if (currentMuscle != null)
                {
                    // check if user is hovering over an ending joint which is not the same as the starting
                    // joint of the currentMuscle
                    Bone    bone        = GetHoveringObject <Bone>(bones);
                    Vector3 endingPoint = ScreenToWorldPoint(Input.mousePosition);

                    if (bone != null)
                    {
                        MuscleJoint joint = bone.muscleJoint;

                        if (!joint.Equals(currentMuscle.startingJoint))
                        {
                            endingPoint = joint.position;
                            currentMuscle.endingJoint = joint;
                        }
                        else
                        {
                            currentMuscle.endingJoint = null;
                        }
                    }
                    else
                    {
                        currentMuscle.endingJoint = null;
                    }

                    //PlaceConnectionBetweenPoints(currentMuscle.gameObject, currentMuscle.startingPoint, endingPoint, CONNECTION_WIDHT);
                    currentMuscle.SetLinePoints(currentMuscle.startingPoint, endingPoint);
                }
            }
            else if (selectedPart == BuildSelection.Move)
            {
                if (currentMovingJoint != null)
                {
                    // Move the joint to the mouse position.
                    var newPoint = ScreenToWorldPoint(Input.mousePosition);

                    if (grid.gameObject.activeSelf)
                    {
                        newPoint = grid.ClosestPointOnGrid(newPoint);
                    }
                    newPoint.z = 0;

                    currentMovingJoint.MoveTo(newPoint);

                    ResetCurrentCreatureName();                     // The creature was modified
                }
            }
        }
        else if (Input.GetMouseButtonUp(0))
        {
            if (selectedPart == BuildSelection.Bone)
            {
                PlaceCurrentBone();
            }
            else if (selectedPart == BuildSelection.Muscle)
            {
                PlaceCurrentMuscle();
            }
            else if (selectedPart == BuildSelection.Move)
            {
                currentMovingJoint = null;
            }
        }
    }
Beispiel #14
0
        // Cyclic Coordinate Descent
        public static void Evaluate(IList <MuscleJoint> joints, Transform target)
        {
            MuscleJoint endEffector = joints[joints.Count - 1];

            float error = (target.position - endEffector.transform.position).magnitude;

            if (error <= MaxError)
            {
                return;
            }

            bool done          = false;
            int  numIterations = 0;

            while (!done && numIterations < MaxIterations)
            {
                // From tip to root, skipping end effector
                for (int i = joints.Count - 2; i >= 0; i--)
                {
                    MuscleJoint joint = joints[i];

                    Vector3 localJointNormal = joints[i + 1].transform.localPosition.normalized;

                    // Find rotation to target
                    Vector3 targetDirection      = target.position - joint.transform.position;
                    Vector3 localTargetDirection = joint.transform.parent
                                                       ? joint.transform.parent.InverseTransformDirection(
                        targetDirection)
                                                       : targetDirection;
                    Quaternion targetDelta = Quaternion.FromToRotation(joint.transform.localRotation * localJointNormal,
                                                                       localTargetDirection);

                    // Find rotation to end effector
                    Vector3 endDirection      = endEffector.transform.position - joint.transform.position;
                    Vector3 localEndDirection = joint.transform.parent
                                                    ? joint.transform.parent.InverseTransformDirection(endDirection)
                                                    : endDirection;
                    Quaternion endDelta = Quaternion.FromToRotation(joint.transform.localRotation * localJointNormal,
                                                                    localEndDirection);

                    // Construct a rotation that puts end effector on the line to (e.g. closest to) the target
                    Quaternion proposedLocalRotation = targetDelta * Quaternion.Inverse(endDelta) *
                                                       joint.transform.localRotation;

                    // Enforce joint limits

                    // Ensure bone rotation stays within limits

                    if (!IsWithinLimits(joint, proposedLocalRotation))
                    {
                        proposedLocalRotation = ClampToLimits(joint, proposedLocalRotation);
                        //RandomizeChain(joint, 0.01f);
                    }

                    joint.transform.localRotation = proposedLocalRotation;
                }

                // Early out if we've reached a local minimum
                float newError = (target.position - endEffector.transform.position).magnitude;
                if (newError <= MaxError || error - newError < 0.01f)
                {
                    done = true;
                }
                error = newError;

                numIterations++;
            }

            UnityEngine.Debug.Log(numIterations);
        }
Beispiel #15
0
 public static void Slerp(MuscleJoint source, MuscleJoint target, float lerp)
 {
     target.transform.localRotation = Quaternion.Slerp(target.transform.localRotation,
                                                       source.transform.localRotation, lerp);
 }
Beispiel #16
0
 public void Initialize(MuscleJoint joint)
 {
     _baseLocalRotation = joint.BaseLocalRotation;
     _limits            = joint.Limits;
 }
Beispiel #17
0
 private static Quaternion ClampToLimits(MuscleJoint joint, Quaternion proposedRotation)
 {
     return(ClampLimitsEuler(joint, proposedRotation));
 }