コード例 #1
0
        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);
        }
コード例 #2
0
        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);
        }
コード例 #3
0
        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);
                        }
                    }
                }
            }
        }
コード例 #4
0
 public abstract void HandleRay(LightRay ray, List <RayHit <LightRay> > hits, List <LightRay> secondaryRays);
コード例 #5
0
        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;
            }
        }