public static (LightRay reflection, LightRay refraction, bool isFullRefraction) ReflectAndRefract(LightRay ray, Vector2 normal, Vector2 point, float n1, float n2) { var incidenceAngle = (float)(Math.Atan2(normal.Y, normal.X) - Math.Atan2(-ray.Direction.Y, -ray.Direction.X)); while (Math.Abs(incidenceAngle) > Math.PI / 2f) { incidenceAngle = incidenceAngle - 2f * (float)Math.PI * Math.Sign(incidenceAngle); } var refractionAngle = (float)Math.Asin(Math.Sin(incidenceAngle) * n1 / n2); float reflCoeficent = (float)(Math.Sin(Math.Abs(incidenceAngle) - Math.Abs(refractionAngle)) / (Math.Sin(Math.Abs(incidenceAngle) + Math.Abs(refractionAngle)))); bool isFullReflection = false; if (float.IsNaN(refractionAngle)) { isFullReflection = true; reflCoeficent = 1; } if (incidenceAngle == 0f) { reflCoeficent = 0; isFullReflection = false; } var reflectionDirection = Vector2.Reflect(ray.Direction, normal); var reflection = new LightRay(point, reflectionDirection, ray.Intensity * reflCoeficent * reflCoeficent); var refraction = new LightRay(point, Vector2.Transform(-normal, Matrix3x2.CreateRotation(-refractionAngle)), ray.Intensity - reflection.Intensity); return(reflection, refraction, isFullReflection); }
HandleSide(LightRay ray, ILine side, bool isInner, bool ignoreFirst = false) { var hit = side.Intersection(ray, ignoreFirst); if (hit) { Vector2 normal; var n = refractiveIndex(hit.Y); if (isInner) { normal = -side.Normal(hit.Y); n = 1f / n; } else { normal = side.Normal(hit.Y); } var(reflection, refraction, isFullReflection) = ReflectAndRefract(ray, normal, hit.Point, 1, n); return(hit, refraction, reflection, isFullReflection); } return(hit, ray, ray, false); }
public void HandleRay(LightRay ray, List <RayHit <LightRay> > hits, List <LightRay> rays) { Stack <(LightRay ray, int indexOfSender)> raysToHandle = new Stack <(LightRay ray, int index)>(); raysToHandle.Push((ray, -1)); List <LightRay> tmpRays = new List <LightRay>(); List <RayHit <LightRay> > tmpHits = new List <RayHit <LightRay> >(); while (raysToHandle.Count > 0) { (LightRay r, int currentIndex) = raysToHandle.Pop(); int[] mayIntersect = { currentIndex - 1, currentIndex + 1 }; foreach (var i in mayIntersect) { tmpHits.Clear(); tmpRays.Clear(); if (i >= 0 && i < lenses.Count) { lenses[i].HandleRay(r, tmpHits, tmpRays); if (tmpHits.Count > 0) { foreach (var rayToHandle in tmpRays) { raysToHandle.Push((rayToHandle, i)); } foreach (var hit in tmpHits) { hits.Add(hit); } break; } else { rays.Add(r); } } } } }
public abstract void HandleRay(LightRay ray, List <RayHit <LightRay> > hits, List <LightRay> secondaryRays);
public override void HandleRay(LightRay rayToHandle, List <RayHit <LightRay> > hits, List <LightRay> secondaryRays) { Stack <LightRay> raysToHandle = new Stack <LightRay>(); ILine side = toLeft(rayToHandle.Origin) ? leftSurface : rightSurface; ILine otherSide = toRight(rayToHandle.Origin) ? leftSurface : rightSurface; var(hit, innerRefraction, mainReflection, fullRef) = HandleSide(rayToHandle, side, false); if (hit) { if (!float.IsNaN(mainReflection.Intensity) && mainReflection.Intensity > 0f) { secondaryRays.Add(mainReflection); } hits.Add(hit); if (fullRef) { return; } raysToHandle.Push(innerRefraction); int reflectionDepth = 0; bool reflectsOnSameSide = false; bool previousHit = false; // all are inside while (raysToHandle.Count > 0 && reflectionDepth < 128) { var ray = raysToHandle.Pop(); var(newHit, newRefraction, newReflection, fullref) = HandleSide(ray, otherSide, true, reflectsOnSameSide); reflectsOnSameSide = false; if (newHit) { previousHit = true; reflectionDepth++; if (newReflection.Intensity >= 0.001f) { raysToHandle.Push(newReflection); } hits.Add(newHit); if (fullref) { } else { if (newRefraction.Intensity >= 0.001f) { secondaryRays.Add(newRefraction); } } } else { if (previousHit == false) { throw new Exception(); } raysToHandle.Push(ray); reflectsOnSameSide = true; previousHit = false; } flipSides(); } } void flipSides() { var tmp = side; side = otherSide; otherSide = tmp; } }