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); } }
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); } }