public Color Trace(Ray ray, TraceData traceData) { RaycastHit forwardHit; Color color; traceData.Counters.Raycasts++; if (Physics.Raycast(ray, out forwardHit)) { if (traceData.PenetrationStack.Count != 0) { Vector3 pushedOutOrigin = forwardHit.point + forwardHit.normal * PushOutMagnitude; Ray backwardRay = new Ray(pushedOutOrigin, -ray.direction); if (TraceBackward(ray, backwardRay, forwardHit.distance, traceData, out color)) { return(color); } } color = GetColor(ray, forwardHit, traceData); traceData.AddHistoryItem(ray, forwardHit, color); return(color); } else { if (traceData.PenetrationStack.Count != 0) { var soughtCollider = traceData.PenetrationStack.Peek().collider; var bounds = soughtCollider.bounds; Vector3 extents = bounds.extents; float boundingSphereRadius = extents.magnitude; Vector3 vToBbCenter = bounds.center - ray.origin; float projLen = Vector3.Dot(vToBbCenter, ray.direction); Vector3 pushedOutOrigin = ray.origin + ray.direction * (projLen + boundingSphereRadius + PushOutMagnitude); Ray backwardRay = new Ray(pushedOutOrigin, -ray.direction); if (TraceBackward(ray, backwardRay, Vector3.Distance(ray.origin, pushedOutOrigin), traceData, out color)) { return(color); } } traceData.AddHistoryItem(ray, null, traceData.BackgroundColor); return(traceData.BackgroundColor); } }
private bool TraceBackward(Ray forwardRay, Ray backwardRay, float maxDistance, TraceData traceData, out Color color) { var soughtCollider = traceData.PenetrationStack.Peek().collider; traceData.Counters.Backtraces++; /* Sometimes, due to imprecision of calculations, * maxDistance is less than or equal to zero. * We can fix this issue by setting it to some small value, * it will not cause any error since origin point and * ray direction are fine. */ if (maxDistance < MinRaycastDistance) { maxDistance = MinRaycastDistance; } var hits = Physics.RaycastAll(backwardRay, maxDistance) .OrderByDescending(h => h.distance) .Where( h => h.collider == soughtCollider && h.distance < maxDistance // TODO: necessary? We already requested hits not farther than maxDistance. Test it. ) .ToArray(); if (hits.Length != 0) { RaycastHit backwardHit = hits [0]; backwardHit.distance = maxDistance - backwardHit.distance; color = GetColor(forwardRay, backwardHit, traceData); traceData.AddHistoryItem(forwardRay, backwardHit, color); return(true); } else { color = default(Color); return(false); } }