Beispiel #1
0
        private void CreateShadowPolygonPoints()
        {
            ShadowPolygonPoints = ShadowPolygonPoints ?? new List <Vector2>();
            ShadowPolygonPoints.Clear();
            if (_visiblitySet.Output.Any())
            {
                Vector2 previous = Vector2.one * 1000000;
                for (int index = 0; index < _visiblitySet.Output.Count; index += 1)
                {
                    Vector2 point = _visiblitySet.Output[index];
                    if (!ShadowMathUtils.Approximately(point, previous))
                    {
                        ShadowPolygonPoints.Add(point);
                    }
                    previous = point;
                }
                ShadowPolygonPoints.Add(_visiblitySet.Output.First());
            }

            if (_drawGizmos)
            {
                Gizmos.color = Color.yellow;
                for (int index = 0; index < ShadowPolygonPoints.Count - 1; index++)
                {
                    Vector2 va = ShadowPolygonPoints[index];
                    Vector2 vb = ShadowPolygonPoints[index + 1];
                    Gizmos.DrawLine(va * 1.05f, vb * 1.05f);
                }
                Gizmos.DrawLine(ShadowPolygonPoints.Last() * 1.05f, ShadowPolygonPoints.First() * 1.05f);
            }
        }
Beispiel #2
0
        private void AddTriangle(float angle1, float angle2, Segment segment, Segment previous)
        {
            Vector2 delta1 = new Vector2(Mathf.Cos(angle1), Mathf.Sin(angle1));
            Vector2 delta2 = new Vector2(Mathf.Cos(angle2), Mathf.Sin(angle2));

            Vector2 p1 = Center;
            Vector2 p2 = p1 + delta1;
            Vector2 p3 = new Vector2(0.0f, 0.0f);
            Vector2 p4 = new Vector2(0.0f, 0.0f);

            Gizmos.color = Color.blue;
            if (segment != null)
            {
                // Stop the triangle at the intersecting segment
                p3 = segment.Start.Point;
                p4 = segment.End.Point;
            }
            else
            {
                // Stop the triangle at a fixed distance; this probably is
                // not what we want, but it never gets used in the demo
                p3 = p1 + delta1 * 500;
                p4 = p1 + delta2 * 500;
            }

            Vector2 pBegin = ShadowMathUtils.LineIntersection(p3, p4, p1, p2);

            p2 = p1 + delta2;
            Vector2 pEnd = ShadowMathUtils.LineIntersection(p3, p4, p1, p2);

            if (_drawGizmos)
            {
                Gizmos.color = Color.green;
                Gizmos.DrawLine(p1, pBegin);
                Gizmos.DrawLine(p2, pEnd);

                //Gizmos.DrawLine(pBegin, pEnd);
                Gizmos.color = Color.yellow;
                Gizmos.DrawSphere(pBegin, 0.1f);
                Gizmos.color = Color.blue;
                Gizmos.DrawSphere(pEnd, 0.1f);
            }

            if (previous != null &&
                ShadowMathUtils.Approximately(segment.Slope, previous.Slope) &&
                ShadowMathUtils.Approximately(Output.Last(), pBegin))
            {
                // It's a continuation of the previous segment!
                Output.RemoveAt(Output.Count - 1);
                Output.Add(pEnd);
            }
            else
            {
                Output.Add(pBegin);
                Output.Add(pEnd);
            }
        }
Beispiel #3
0
        public bool GetIsPointInLight(Vector2 position)
        {
            if (!_bounds.Contains(position))
            {
                return(false);
            }

            if (!ShadowPolygonPoints.Any())
            {
                return(false);
            }

            return(ShadowMathUtils.GetIsPointInPoly(position, ShadowPolygonPoints));
        }
Beispiel #4
0
        // Helper: do we know that segment a is in front of b?
        // Implementation not anti-symmetric (that is to say,
        // _segment_in_front_of(a, b) != (!_segment_in_front_of(b, a)).
        // Also note that it only has to work in a restricted set of cases
        // in the visibility algorithm; I don't think it handles all
        // cases. See http://www.redblobgames.com/articles/visibility/segment-sorting.html
        public static IntersectionResult IsInFrontOf(Segment a, Segment b, Vector2 relativeTo)
        {
            // NOTE: we slightly shorten the segments so that
            // intersections of the endpoints (common) don't count as
            // intersections in this algorithm
            const float epsilon = 0.01f;
            bool        A1      = ShadowMathUtils.GetIsLeft(a, ShadowMathUtils.Interpolate(b.Start.Point, b.End.Point, epsilon));
            bool        A2      = ShadowMathUtils.GetIsLeft(a, ShadowMathUtils.Interpolate(b.End.Point, b.Start.Point, epsilon));
            bool        A3      = ShadowMathUtils.GetIsLeft(a, relativeTo);
            bool        B1      = ShadowMathUtils.GetIsLeft(b, ShadowMathUtils.Interpolate(a.Start.Point, a.End.Point, epsilon));
            bool        B2      = ShadowMathUtils.GetIsLeft(b, ShadowMathUtils.Interpolate(a.End.Point, a.Start.Point, epsilon));
            bool        B3      = ShadowMathUtils.GetIsLeft(b, relativeTo);

            // NOTE: this algorithm is probably worthy of a short article
            // but for now, draw it on paper to see how it works. Consider
            // the line A1-A2. If both B1 and B2 are on one side and
            // relativeTo is on the other side, then A is in between the
            // viewer and B. We can do the same with B1-B2: if A1 and A2
            // are on one side, and relativeTo is on the other side, then
            // B is in between the viewer and A.
            if (B1 == B2 && B2 != B3)
            {
                return(IntersectionResult.InFront);
            }
            if (A1 == A2 && A2 == A3)
            {
                return(IntersectionResult.InFront);
            }
            if (A1 == A2 && A2 != A3)
            {
                return(IntersectionResult.Behind);
            }
            if (B1 == B2 && B2 == B3)
            {
                return(IntersectionResult.Behind);
            }

            // If A1 != A2 and B1 != B2 then we have an intersection.
            // Expose it for the GUI to show a message. A more robust
            // implementation would split segments at intersections so
            // that part of the segment is in front and part is behind.
            //demo_intersectionsDetected.push([a.p1, a.p2, b.p1, b.p2]);
            return(IntersectionResult.Intersects);

            // NOTE: previous implementation was a.d < b.d. That's simpler
            // but trouble when the segments are of dissimilar sizes. If
            // you're on a grid and the segments are similarly sized, then
            // using distance will be a simpler and faster implementation.
        }
Beispiel #5
0
        public void LateUpdate()
        {
            _meshRenderer = _meshRenderer ?? GetComponent <MeshRenderer>();


            if (_meshRenderer != null && onlyUpdateWhenVisible && !_meshRenderer.isVisible)
            {
                return;
            }

            _visiblitySet = _visiblitySet ?? new VisiblitySet();

            // Can't rotate the lights at the moment
            transform.rotation = Quaternion.identity;

            Vector2 newPosition   = transform.position;
            Vector2 oldScreenSize = _screenSize;

            _screenSize = new Vector2(Screen.width, Screen.height);

            bool rebuild = updateOnEachUpdate;

            rebuild = rebuild || _screenSize != oldScreenSize || !Mathf.Approximately(size, _oldSize);
            rebuild = rebuild || !Mathf.Approximately(Camera.main.orthographicSize, _oldOrthographicSize);
            rebuild = rebuild || !Mathf.Approximately(Camera.main.fieldOfView, _oldFieldOfView);
            rebuild = rebuild || updateOnChangedLocation && !ShadowMathUtils.Approximately(_oldPosition, newPosition);
            rebuild = rebuild || updateWhenCollidersChange && GetHaveCollidersChanged();

            _oldSize = size;

            if (rebuild)
            {
                RebuildShadow();
                _oldOrthographicSize = Camera.main.orthographicSize;
                _oldFieldOfView      = Camera.main.fieldOfView;
            }
            else
            {
                if (updateUvs &&
                    !ShadowMathUtils.Approximately(Camera.main.transform.position, _oldCameraPosition))
                {
                    _visiblitySet.UpdateUvs();
                    _oldCameraPosition = Camera.main.transform.position;
                }
            }

            _oldPosition = newPosition;
        }
Beispiel #6
0
        private bool InnerUpdateColliders(Vector2 topLeft, Vector2 bottomRight, LayerMask layerMask)
        {
            _updateOnFrame = Time.frameCount;

            Collider2D[] oldColliders = colliders;
            colliders = Physics2D.OverlapAreaAll(topLeft, bottomRight, layerMask);
            // Sort them so we get them in the same order as before. This is required for the comparison we do later on.
            Array.Sort(colliders, (c1, c2) => c1.GetInstanceID() - c2.GetInstanceID());

            Vector3[] oldPositions = positions;
            positions = colliders.Select(c => c.transform.position).ToArray();
            Quaternion[] oldRotations = rotations;
            rotations = colliders.Select(c => c.transform.rotation).ToArray();

            // Ease fast checks first
            if (oldColliders == null || oldColliders.Length != colliders.Length)
            {
                return(true);
            }

            for (int index = 0; index < colliders.Length; index++)
            {
                Collider2D newCollider = colliders[index];
                Collider2D oldCollider = oldColliders[index];

                if (newCollider != oldCollider)
                {
                    return(true);
                }

                if (!ShadowMathUtils.Approximately(oldPositions[index], newCollider.transform.position))
                {
                    return(true);
                }

                if (!ShadowMathUtils.Approximately(oldRotations[index], newCollider.transform.rotation))
                {
                    return(true);
                }
            }

            return(false);
        }
Beispiel #7
0
        private void SplitSegmentsThatOverlap()
        {
            // O(N^2)
            Queue <Segment> open = new Queue <Segment>(Segments);

            Segments.Clear();
            while (open.Any())
            {
                if (Segments.Count > 300)
                {
                    Debug.Log("Too many segment splits!");
                    return;
                }
                Segment segment   = open.Dequeue();
                bool    splitFree = true;
                foreach (Segment testing in Segments)
                {
                    Segment.IntersectionResult intersection = Segment.IsInFrontOf(segment, testing, Center);

                    if (intersection == Segment.IntersectionResult.Intersects)
                    {
                        // Do they *really* overlap, there seems to be some issues with the IsInFrontOf method.
                        if (ShadowMathUtils.Approximately(testing.Start.Point, segment.Start.Point) ||
                            ShadowMathUtils.Approximately(testing.End.Point, segment.End.Point) ||
                            ShadowMathUtils.Approximately(testing.End.Point, segment.Start.Point) ||
                            ShadowMathUtils.Approximately(testing.Start.Point, segment.End.Point))
                        {
                            //intersection = Segment.IsInFrontOf(segment, testing, Center);
                            //Debug.Log("They're the same point!"+intersection);
                            continue;
                        }

                        // segment && testing overlap, we must split one of them but both must go back on the queue
                        Segments.Remove(testing);
                        open.Enqueue(testing);

                        Vector2 position =
                            ShadowMathUtils.LineIntersection(
                                segment.Start.Point,
                                segment.End.Point,
                                testing.Start.Point,
                                testing.End.Point);

                        if (_drawGizmos)
                        {
                            Gizmos.color = Color.red;
                            Gizmos.DrawSphere(position, 0.2f);
                        }

                        // Split segments and add both parts back to the queue
                        Split(segment, position, open);
                        splitFree = false;
                        break;
                    }
                }
                if (splitFree)
                {
                    Segments.Add(segment);
                }
            }
        }
Beispiel #8
0
        private void DoMergeCollinearSegments()
        {
            if (!MergeCollinearSegments)
            {
                return;
            }
            //int merges = 0;
            //int compares = 0;
            //int before = Segments.Count;

            //Stopwatch stopwatch = Stopwatch.StartNew();

            // Log of performance optimization of this very rouine.
            // Merged 287 to 149 segments (138 merges, 1710596 compares). 322 ms.
            // Merged 287 to 149 segments (138 merges, 105329 compares). 14 ms.
            // Merged 287 to 149 segments (138 merges, 84767 compares, 2 tries). 14 ms.
            // Merged 287 to 149 segments (138 merges, 84767 compares, 2 tries). 13 ms.
            // Merged 287 to 149 segments (138 merges, 1968 compares, 6 tries). 5 ms.
            // Merged 287 to 149 segments (138 merges, 1968 compares, 6 tries). 4 ms.

            int tries = 0;
            ILookup <Vector2, Segment> startpointLookup =
                Segments
                .ToLookup(s => s.Start.Point, s => s);

            while (tries++ < 4)
            {
                bool merged = false;
                for (int index = 0; index < Segments.Count; index++)
                {
                    Segment segment = Segments[index];
                    if (segment.Merged)
                    {
                        continue;
                    }

                    IEnumerable <Segment> startpoints = startpointLookup[segment.End.Point];

                    foreach (Segment other in startpoints)
                    {
                        //compares++;
                        if (other.Merged)
                        {
                            continue;
                        }

                        if (ShadowMathUtils.Approximately(segment.Slope, other.Slope))
                        {
                            other.Merged      = true;
                            segment.End.Point = other.End.Point;
                            //merges++;
                            merged = true;
                        }
                    }
                }

                Segments.RemoveAll(s => s.Merged);
                if (!merged)
                {
                    break;
                }
            }

            //Debug.LogFormat("Merged {0} to {1} segments ({2} merges, {3} compares, {5} tries). {4} ms.", before, Segments.Count, merges, compares, stopwatch.ElapsedMilliseconds, tries);
        }