Example #1
0
        private void UpdateJoints()
        {
            for (int i = 0; i < joints.Length; ++i)
            {
                if (joints[i] != null && links[i].body != null && links[i + 1].body != null)
                {
                    CableJoint joint = joints[i];

                    Vector3 t1, t2;
                    FindCommonTangents(links[i], links[i + 1], out t1, out t2);

                    Vector2 currentT1 = joint.body1.WorldSpaceToCablePlane(joint.WorldSpaceAttachment1);
                    Vector2 currentT2 = joint.body2.WorldSpaceToCablePlane(joint.WorldSpaceAttachment2);

                    // Get surface distances between old and new tangents:
                    float d1 = joint.body1.SurfaceDistance(currentT1, joint.body1.WorldSpaceToCablePlane(t1), links[i].orientation);
                    float d2 = joint.body2.SurfaceDistance(currentT2, joint.body2.WorldSpaceToCablePlane(t2), links[i + 1].orientation);

                    // Update stored lengths:
                    links[i].storedCable     -= d1;
                    links[i + 1].storedCable += d2;

                    // Update rest lengths:
                    joint.restLength += d1;
                    joint.restLength -= d2;

                    // Update tangent points:
                    joint.offset1 = joint.body1.transform.InverseTransformPoint(t1 - joint.body1.GetCablePlaneNormal() * links[i].storedCable * links[i].spoolSeparation);
                    joint.offset2 = joint.body2.transform.InverseTransformPoint(t2 - joint.body2.GetCablePlaneNormal() * links[i + 1].storedCable * links[i + 1].spoolSeparation);
                }
            }
        }
Example #2
0
        public void Setup()
        {
            joints = null;
            if (links != null && links.Length > 0)
            {
                joints = new CableJoint[links.Length - 1];

                for (int i = 0; i < links.Length - 1; ++i)
                {
                    if (links[i].body != null && links[i + 1].body != null)
                    {
                        Vector3 t1, t2;
                        FindCommonTangents(links[i], links[i + 1], out t1, out t2);

                        t1 -= links[i].body.GetCablePlaneNormal() * links[i].storedCable * links[i].spoolSeparation;
                        t2 -= links[i + 1].body.GetCablePlaneNormal() * links[i + 1].storedCable * links[i + 1].spoolSeparation;

                        joints[i] = new CableJoint(links[i].body, links[i + 1].body,
                                                   links[i].body.transform.InverseTransformPoint(t1),
                                                   links[i + 1].body.transform.InverseTransformPoint(t2),
                                                   (t2 - t1).magnitude);
                    }
                }
            }

            CalculateRestLength();
        }
Example #3
0
        private void CalculateRestLength()
        {
            restLength = 0;
            if (joints == null)
            {
                return;
            }

            bool closed = (links[0].body == links[links.Count - 1].body);

            for (int i = 0; i < links.Count; ++i)
            {
                Link link = links[i];

                if (link.body != null)
                {
                    CableJoint prevJoint = GetPreviousJoint(i, closed);
                    CableJoint nextJoint = GetNextJoint(i, closed);

                    if (nextJoint != null && prevJoint != null && (!(i == 0 && closed)))
                    {
                        link.storedCable = Mathf.Abs(link.body.SurfaceDistance(link.body.WorldSpaceToCablePlane(prevJoint.WorldSpaceAttachment2),
                                                                               link.body.WorldSpaceToCablePlane(nextJoint.WorldSpaceAttachment1),
                                                                               link.orientation));
                        restLength += link.storedCable;
                    }
                    else if (link.type == Link.LinkType.Hybrid)
                    {
                        restLength += link.storedCable;

                        if (nextJoint != null)
                        {
                            Vector2 tangent = link.body.WorldSpaceToCablePlane(nextJoint.WorldSpaceAttachment1);
                            int     j       = 0;

                            link.outAnchor = link.body.transform.InverseTransformPoint(link.body.SurfacePointAtDistance(tangent, link.storedCable, link.orientation, out j));
                        }
                        else if (prevJoint != null)
                        {
                            Vector2 tangent = link.body.WorldSpaceToCablePlane(prevJoint.WorldSpaceAttachment2);
                            int     j       = 0;
                            link.inAnchor = link.body.transform.InverseTransformPoint(link.body.SurfacePointAtDistance(tangent, link.storedCable, !link.orientation, out j));
                        }
                    }

                    if (i < links.Count - 1 && joints[i] != null)
                    {
                        restLength += joints[i].restLength;
                    }
                }

                links[i] = link;
            }
        }
Example #4
0
        private void SampleLink(CableJoint prevJoint, Link link, CableJoint nextJoint)
        {
            Vector3?t1 = null, t2 = null;

            if (prevJoint != null)
            {
                t1 = prevJoint.body2.WorldToCable(prevJoint.WorldSpaceAttachment2);
            }
            if (nextJoint != null)
            {
                t2 = nextJoint.body1.WorldToCable(nextJoint.WorldSpaceAttachment1);
            }

            // Hybrid links (only at the start or the end of the cable)
            if (link.type == Link.LinkType.Hybrid)
            {
                if (t1.HasValue)
                {
                    link.body.AppendSamples(sampledCable, t1.Value, link.storedCable, link.spoolSeparation, false, link.orientation);
                }
                else if (t2.HasValue)
                {
                    link.body.AppendSamples(sampledCable, t2.Value, link.storedCable, link.spoolSeparation, true, link.orientation);
                }
            }
            // Rolling links (only mid-cable)
            else if (link.type == Link.LinkType.Rolling)
            {
                if (t1.HasValue && t2.HasValue)
                {
                    float distance = link.body.SurfaceDistance(t1.Value, t2.Value, !link.orientation, false);
                    link.body.AppendSamples(sampledCable, t1.Value, distance, 0, false, link.orientation);
                }
            }
            // Attachment, source and pinhole links:
            else
            {
                if (t1.HasValue)
                {
                    sampledCable.AppendSample(prevJoint.body2.transform.TransformPoint(link.inAnchor));
                }

                if (t1.HasValue && t2.HasValue && t1.Value != t2.Value)
                {
                    sampledCable.NewSegment();
                }

                if (t2.HasValue)
                {
                    sampledCable.AppendSample(nextJoint.body1.transform.TransformPoint(link.outAnchor));
                }
            }
        }
Example #5
0
        private void SampleJoint(CableJoint joint)
        {
            Vector3 p1 = joint.WorldSpaceAttachment1;
            Vector3 p2 = joint.WorldSpaceAttachment2;

            if (joint.length < joint.restLength)
            {
                Vector3 point = p2 - p1;
                Vector3 dir   = Vector3.Scale(point, new Vector3(1, 0, 1));

                if (loosenessScale > 0)
                {
                    float sampledLength = Mathf.Lerp(joint.length, Mathf.Min(joint.restLength, joint.length + maxLooseCable), loosenessScale);

                    if (dir.sqrMagnitude > verticalThreshold)
                    {
                        Quaternion rot  = Quaternion.LookRotation(dir);
                        Quaternion irot = Quaternion.Inverse(rot);
                        Vector3    n    = irot * point;

                        if (Utils.Catenary(Vector2.zero, new Vector2(n.z, n.y), sampledLength, ref catenaryBuffer))
                        {
                            for (int j = 1; j < catenaryBuffer.Length - 1; ++j)
                            {
                                sampledCable.AppendSample(p1 + rot * new Vector3(0, catenaryBuffer[j].y, catenaryBuffer[j].x));
                            }
                        }
                    }
                    else
                    {
                        if (Utils.Sinusoid(p1, point, sampledLength, verticalCurlyness, ref sinusoidBuffer))
                        {
                            for (int j = 1; j < sinusoidBuffer.Length - 1; ++j)
                            {
                                sampledCable.AppendSample(sinusoidBuffer[j]);
                            }
                        }
                    }
                }
            }
        }
Example #6
0
        private void UpdatePinhole(CableJoint joint1, CableJoint joint2)
        {
            if (joint1 != null && joint2 != null)
            {
                float restLenght1 = joint1.restLength;
                float restLength2 = joint2.restLength;

                if (joint1.length > restLenght1)
                {
                    float delta = joint1.length - restLenght1;
                    joint1.restLength += delta;
                    joint2.restLength -= delta;
                }
                if (joint2.length > restLength2)
                {
                    float delta = joint2.length - restLength2;
                    joint1.restLength -= delta;
                    joint2.restLength += delta;
                }
            }
        }
Example #7
0
        private void Update()
        {
            sampledCable.Clear();

            if (joints == null || links.Length == 0)
            {
                return;
            }

            bool closed = (links[0].body == links[links.Length - 1].body);

            for (int i = 0; i < links.Length; ++i)
            {
                if (links[i].body != null)
                {
                    CableJoint prevJoint = GetPreviousJoint(i, closed);
                    CableJoint nextJoint = GetNextJoint(i, closed);

                    // Sample the link, except if the cable is closed and this is the first link.
                    if (!(i == 0 && closed) || links[i].type == Link.LinkType.Attachment || links[i].type == Link.LinkType.Pinhole)
                    {
                        SampleLink(prevJoint, links[i], nextJoint);
                    }

                    // Sample the joint (only adds sample points if cable is not tense):
                    if (i < joints.Length && joints[i] != null)
                    {
                        SampleJoint(joints[i]);
                    }
                }
            }

            if (closed)
            {
                sampledCable.Close();
            }
        }
Example #8
0
        private void SplitMerge()
        {
            if (!dynamicSplitMerge)
            {
                return;
            }

            // merge links with negative stored cable:
            for (int i = 1; i < links.Count - 1; ++i)
            {
                CableJoint prevJoint = joints[i - 1];
                CableJoint nextJoint = joints[i];

                if (links[i].type == Link.LinkType.Rolling && links[i].body != null && prevJoint != null && nextJoint != null)
                {
                    if (links[i].storedCable < 0)
                    {
                        prevJoint.restLength += nextJoint.restLength;
                        prevJoint.Body2       = nextJoint.Body2;

                        // Update joint attachment points:
                        Vector3 t1, t2;
                        FindCommonTangents(links[i - 1], links[i + 1], out t1, out t2);
                        prevJoint.offset1 = prevJoint.Body1.transform.InverseTransformPoint(t1);
                        prevJoint.offset2 = prevJoint.Body2.transform.InverseTransformPoint(t2);
                        prevJoint.Initialize();

                        links.RemoveAt(i);
                        joints.RemoveAt(i);
                    }
                }
            }

            // split joints that intersect a body:
            for (int i = 0; i < joints.Count; ++i)
            {
                CableJoint currentJoint = joints[i];

                if (currentJoint != null)
                {
                    RaycastHit hit;

                    if (Physics.Raycast(new Ray(currentJoint.WorldSpaceAttachment1, currentJoint.WorldSpaceAttachment2 - currentJoint.WorldSpaceAttachment1), out hit, currentJoint.length))
                    {
                        CableBody body = hit.collider.GetComponent <CableBody>();

                        // Only split if the body is a disc or a convex shape, and the raycast hit is sane.
                        if ((body is CableDisc || body is CableShape) && hit.distance > 0.1f && hit.distance + 0.1f < currentJoint.length)
                        {
                            float initialRestLength = currentJoint.restLength;

                            // Create new joint and link:
                            CableJoint newJoint = new CableJoint(body, currentJoint.Body2, Vector3.zero, Vector3.zero, currentJoint.restLength);
                            currentJoint.Body2 = body;

                            Link newLink = new Link();
                            newLink.type = Link.LinkType.Rolling;
                            newLink.body = body;

                            // Calculate orientation.
                            Vector3 v     = body.transform.position - currentJoint.WorldSpaceAttachment1;
                            Vector3 cross = Vector3.Cross(body.GetCablePlaneNormal(), v);
                            newLink.orientation = Vector3.Dot(cross, hit.point - currentJoint.WorldSpaceAttachment1) < 0;

                            // Update joint attachment points:
                            Vector3 t1, t2;
                            FindCommonTangents(links[i], newLink, out t1, out t2);
                            currentJoint.offset1 = currentJoint.Body1.transform.InverseTransformPoint(t1);
                            currentJoint.offset2 = currentJoint.Body2.transform.InverseTransformPoint(t2);

                            FindCommonTangents(newLink, links[i + 1], out t1, out t2);
                            newJoint.offset1 = newJoint.Body1.transform.InverseTransformPoint(t1);
                            newJoint.offset2 = newJoint.Body2.transform.InverseTransformPoint(t2);

                            currentJoint.Initialize();
                            newJoint.Initialize();

                            // Adjust rest lengths so that tensions are equal:
                            float tension = initialRestLength / (currentJoint.length + newJoint.length);
                            currentJoint.restLength = currentJoint.length * tension;
                            newJoint.restLength     = newJoint.length * tension;

                            // Insert new joint/link:
                            joints.Insert(i + 1, newJoint);
                            links.Insert(i + 1, newLink);
                        }
                    }
                }
            }
        }
Example #9
0
        private void UpdateJoints()
        {
            for (int i = 0; i < joints.Count; ++i)
            {
                if (joints[i] != null && links[i].body != null && links[i + 1].body != null)
                {
                    CableJoint joint = joints[i];
                    Link       link1 = links[i];
                    Link       link2 = links[i + 1];

                    Vector3 t1, t2;
                    FindCommonTangents(links[i], links[i + 1], out t1, out t2);

                    Vector2 currentT1 = joint.body1.WorldSpaceToCablePlane(joint.WorldSpaceAttachment1);
                    Vector2 currentT2 = joint.body2.WorldSpaceToCablePlane(joint.WorldSpaceAttachment2);

                    // Get surface distances between old and new tangents:
                    float d1 = joint.body1.SurfaceDistance(currentT1, joint.body1.WorldSpaceToCablePlane(t1), links[i].orientation);
                    float d2 = joint.body2.SurfaceDistance(currentT2, joint.body2.WorldSpaceToCablePlane(t2), links[i + 1].orientation);

                    // Spawn more cable if necessary
                    if (links[i].type == Link.LinkType.Attachment)
                    {
                        d1         += links[i].cableSpawnSpeed;
                        restLength += links[i].cableSpawnSpeed;
                    }

                    if (links[i + 1].type == Link.LinkType.Attachment)
                    {
                        d2         -= links[i + 1].cableSpawnSpeed;
                        restLength += links[i + 1].cableSpawnSpeed;
                    }

                    // Update stored lengths:
                    link1.storedCable -= d1;
                    link2.storedCable += d2;

                    // Update rest lengths:
                    joint.restLength += d1;
                    joint.restLength -= d2;

                    // Update hybrid link attachment points (displace along the plane normal based on amount of stored cable):
                    if (links[i].type == Link.LinkType.Hybrid)
                    {
                        t1 -= joint.body1.GetCablePlaneNormal() * links[i].storedCable * links[i].spoolSeparation;
                    }

                    if (links[i + 1].type == Link.LinkType.Hybrid)
                    {
                        t2 -= joint.body2.GetCablePlaneNormal() * links[i + 1].storedCable * links[i + 1].spoolSeparation;
                    }

                    // Update tangent points:
                    joint.offset1 = joint.body1.transform.InverseTransformPoint(t1);
                    joint.offset2 = joint.body2.transform.InverseTransformPoint(t2);

                    links[i]     = link1;
                    links[i + 1] = link2;
                }
            }
        }