/**
         * Now, we need to consider the arrangement of our vertices
         * They're ordered by angle, but what if things have the same or nearly the same angle?
         * We might have two vertices that came from cast points at different locations in the same direction
         * but that end up casting to the same surface, and this can be visually very buggy
         * since these are sorted, they'll be right next to each other if this is the case!!!
         */
        private void fixVertOrder()
        {
            //it's first important to now order every single vertext from 0-2pi
            allVertices.Sort((v1, v2) => (v1.angleRelToLight.CompareTo(v2.angleRelToLight)));
            if (drawDebugLines && uniformColoredSortOrder)
            {
                orderedColoredDebug();
            }

            const float rangeAngleComparision = 0.0001f;

            for (int i = 0; i < allVertices.Count - 1; i += 1)
            {
                LightInteractVertex first  = allVertices[i];
                LightInteractVertex second = allVertices[i + 1];



                if (almostEquals(first.angleRelToLight, second.angleRelToLight, rangeAngleComparision))
                {
                    //This needs to happen because of our implementation of checkEdge
                    if (first.sig == LightInteractVertex.Significance.HIGHANGLE && second.positionRelToLight.sqrMagnitude > first.positionRelToLight.sqrMagnitude)
                    {
                        allVertices [i]     = second;
                        allVertices [i + 1] = first;
                    }

                    if (second.sig == LightInteractVertex.Significance.LOWANGLE && first.positionRelToLight.sqrMagnitude > second.positionRelToLight.sqrMagnitude)
                    {
                        allVertices [i]     = second;
                        allVertices [i + 1] = first;
                    }
                }
            }
        }
        private void sendEquidistentRays()
        {
            float theta  = (angledLight) ? angleFacingRad : 0;
            float amount = ((angledLight) ? angleLimRad : Mathf.PI * 2) / (float)lightSegments;

            for (int i = 0; i < lightSegments; i++)
            {
                LightInteractVertex vert = new LightInteractVertex();

                //Creates a position vector of magnitude lightRadius in the angle defined by this loop
                float sine   = (approximateTrigVals) ? FastTrigCalculator.SinRadApprox(theta) : Mathf.Sin(theta);
                float cosine = (approximateTrigVals) ? FastTrigCalculator.CosRadApprox(theta) : Mathf.Cos(theta);
                vert.positionRelToLight  = new Vector3(cosine, sine, 0);
                vert.positionRelToLight *= lightRadius;
                //Must save angle calculated by same fxn for every vert
                vert.angleRelToLight = FastTrigCalculator.getAngleTo(vert.positionRelToLight.x, vert.positionRelToLight.y, approximateTrigVals);
                //Now, send a ray from the lightsource to the position we just created
                RaycastHit2D ray = Physics2D.Raycast(transform.position, vert.positionRelToLight, lightRadius, interactionLayers);

                if (ray)
                {
                    //it will still have the same exact angle as before but just a new position
                    vert.positionRelToLight = transform.InverseTransformPoint(ray.point);
                }
                allVertices.Add(vert);
                if (drawEqRays && !uniformColoredSortOrder)
                {
                    Debug.DrawLine(transform.position, transform.TransformPoint(vert.positionRelToLight), Color.magenta);
                }

                theta = (theta + amount) % (Mathf.PI * 2);
            }
        }
Beispiel #3
0
        private List <LightInteractVertex> raycastAtCollider(PolygonCollider2D collider)
        {
            List <LightInteractVertex> thisCollider = new List <LightInteractVertex> ();

            for (int i = 0; i < collider.GetTotalPointCount(); i++)
            {
                LightInteractVertex vert = new LightInteractVertex();
                // The collider.points[i] vector contains positions relative to the collider itslef
                // We transform the point like this to bring it from colliderN.transform's locality to world locality
                Vector3 worldPoint = collider.transform.TransformPoint(collider.points[i]);
                Vector3 direction  = worldPoint - transform.position;                //Offset from worldPoint
                vert.angleRelToLight = FastTrigCalculator.getAngleTo(direction.x, direction.y, approximateTrigVals);

                //If we're using angled light and this point isn't in the angle, don't bother doing any of this
                if (angledLight && !withinRange(vert.angleRelToLight, angleFacingRad, angleFacingRad + angleLimRad))
                {
                    continue;
                }

                //TODO: consider doing this instead: float dist = Mathf.Sqrt(Mathf.Min (lightRadius*lightRadius, direction.sqrMagnitude));
                float        dist = direction.magnitude;
                RaycastHit2D ray  = Physics2D.Raycast(transform.position, direction, dist, interactionLayers);

                if (ray)                   //If this hit anything at all (it's possible to miss when a collider has a point further than lightradius but has one within lightradius
                {
                    if (transform.InverseTransformPoint(ray.point).sqrMagnitude > lightRadius * lightRadius)
                    {
                        vert.positionRelToLight = direction.normalized * lightRadius;
                    }
                    else
                    {
                        if (almostEquals(ray.point.sqrMagnitude, worldPoint.sqrMagnitude, 0.15f))
                        {
                            //very fast way of seeing if the point in the mesh was the point hit by the raycast
                            //if that's not the case, then we know this vertexNI blocks the path from light to colliderN.points[i]
                            vert.hitIntendedPolygon = true;
                        }
                        vert.positionRelToLight = transform.InverseTransformPoint(ray.point);
                    }
                }
                else
                {
                    //If we hit nothing, this is only because of floating point rounding error causing us to miss
                    //So we can simply assume that we did actually hit the corner
                    vert.positionRelToLight = (direction.sqrMagnitude > lightRadius * lightRadius) ? direction.normalized * lightRadius : direction;
                    vert.hitIntendedPolygon = true;
                }
                thisCollider.Add(vert);
                //We need the angle rel to collider for sorting, but vec3.angle gives only positive angles
                vert.angleRelToCollider = Vector3.Angle(thisCollider [0].positionRelToLight, vert.positionRelToLight);
                //Solution: use cross product.
                vert.angleRelToCollider = (Vector3.Cross(thisCollider [0].positionRelToLight, vert.positionRelToLight).z < 0) ? vert.angleRelToCollider : -vert.angleRelToCollider;
                if (drawDebugLines && !uniformColoredSortOrder)
                {
                    Debug.DrawLine(transform.position, transform.TransformPoint(vert.positionRelToLight), Color.white);
                }
            }
            return(thisCollider);
        }
        /**
         * This function is sort of confusing, so to document:
         *
         *  We take the position (world coordinates) of the vertex on the edge of the polygon
         *  We take the direction from the light to the polygon
         *  Then, we fudge the location of that vertex by a bit in that same direction,
         *      and since that direction is the direction that got us there, if this is a corner,
         *      we will slip just slightly past the corner and see what is past it.
         *  We then raycast from that fudged point in the same direction by the amount
         *  that we can reach with our lightradius defined minus how far the vertex was
         *
         *  After that, we either hit something, and we can add that point, or we didn't,
         *  and we need to add the point at lightradius away from light in same direction
         */
        private void checkEdge(LightInteractVertex vert)
        {
            if (vert.hitIntendedPolygon)             //If it was obstructed at the very edge angles, we don't need to bother
            {
                Vector2 from = transform.TransformPoint(vert.positionRelToLight);
                Vector2 dir  = (Vector2)vert.positionRelToLight;
                Vector2 off  = dir * 0.01f;
                from += off;
                float        dist    = lightRadius - dir.magnitude;
                RaycastHit2D peekRay = Physics2D.Raycast(from, dir, dist, interactionLayers);

                Vector3 worldPointNewVert;

                LightInteractVertex vL = new LightInteractVertex();

                if (peekRay)
                {
                    //This means that fudging the edge very slightly made us hit another object which we want to shine light on
                    worldPointNewVert = peekRay.point;
                }
                else
                {
                    worldPointNewVert = from + dir.normalized * dist;
                }

                if (drawDebugLines && !uniformColoredSortOrder)
                {
                    Debug.DrawLine(from - off, worldPointNewVert, Color.green);
                }


                vL.positionRelToLight = transform.InverseTransformPoint(worldPointNewVert);
                vL.angleRelToLight    = FastTrigCalculator.getAngleTo(vL.positionRelToLight.x, vL.positionRelToLight.y, approximateTrigVals);
                allVertices.Add(vL);
            }
        }