Пример #1
0
        /// <summary>
        /// this method tests for an intersection. It will try to find the closest
        /// object that intersects with the ray.
        /// it will inspect every object in the scene. also here there is room for increased performance.
        /// </summary>
        /// <param name="ray"></param>
        /// <param name="scene"></param>
        /// <param name="exclude"></param>
        /// <returns></returns>
        private IntersectInfo TestIntersection(Ray ray, Scene scene, IShape exclude)
        {
            var hitcount = 0;
            var best     = new IntersectInfo()
            {
                Distance = double.MaxValue
            };

            foreach (var elt in scene.Shapes)
            {
                if (elt == exclude)
                {
                    continue;
                }

                var info = elt.Intersect(ray);
                if (info.IsHit && info.Distance < best.Distance && info.Distance >= 0)
                {
                    best = info;
                    hitcount++;
                }
            }
            best.HitCount = hitcount;
            return(best);
        }
Пример #2
0
        /// <summary>
        /// This is the main RayTrace controller algorithm, the core of the RayTracer
        /// recursive method setup
        /// this does the actual tracing of the ray and determines the color of each pixel
        /// supports:
        /// - ambient lighting
        /// - diffuse lighting
        /// - Gloss lighting
        /// - shadows
        /// - reflections
        /// </summary>
        /// <param name="info"></param>
        /// <param name="ray"></param>
        /// <param name="scene"></param>
        /// <param name="depth"></param>
        /// <returns></returns>
        private Vector RayTrace(IntersectInfo info, Ray ray, Scene scene, int depth)
        {
            // calculate ambient light
            var color = info.Color * scene.Background.Ambience;
            // Console.WriteLine($"color ({color}) from info.color({info.Color})");
            var shininess = Math.Pow(10, info.Element.Material.Gloss + 1);

            foreach (var light in scene.Lights)
            {
                // calculate diffuse lighting
                var v = (light.Position - info.Position).Normalize();

                if (scene.RenderDiffuse)
                {
                    var l = v.DotProduct(info.Normal);
                    if (l > 0.0f)
                    {
                        color += info.Color * light.Color * l;
                    }
                }

                // this is the max depth of raytracing.
                // increasing depth will calculate more accurate color, however it will
                // also take longer (exponentially)
                if (depth < _traceDepth)
                {
                    // calculate reflection ray
                    if (scene.RenderReflection && info.Element.Material.Reflection > 0)
                    {
                        var reflectionray = GetReflectionRay(info.Position, info.Normal, ray.Direction);
                        var refl          = TestIntersection(reflectionray, scene, info.Element);
                        if (refl.IsHit && refl.Distance > 0)
                        {
                            // recursive call, this makes reflections expensive
                            refl.Color = RayTrace(refl, reflectionray, scene, depth + 1);
                        }
                        else // does not reflect an object, then reflect background color
                        {
                            refl.Color = scene.Background.Color;
                        }
                        color = color.Blend(refl.Color, info.Element.Material.Reflection);
                    }

                    //calculate refraction ray
                    if (scene.RenderRefraction && info.Element.Material.Transparency > 0)
                    {
                        var refractionray = GetRefractionRay(info.Position, info.Normal, ray.Direction, info.Element.Material.Refraction);
                        var refr          = info.Element.Intersect(refractionray);
                        if (refr.IsHit)
                        {
                            //refractionray = new Ray(refr.Position, ray.Direction);
                            refractionray = GetRefractionRay(refr.Position, refr.Normal, refractionray.Direction, refr.Element.Material.Refraction);
                            refr          = TestIntersection(refractionray, scene, info.Element);
                            if (refr.IsHit && refr.Distance > 0)
                            {
                                // recursive call, this makes refractions expensive
                                refr.Color = RayTrace(refr, refractionray, scene, depth + 1);
                            }
                            else
                            {
                                refr.Color = scene.Background.Color;
                            }
                        }
                        else
                        {
                            refr.Color = scene.Background.Color;
                        }
                        color = color.Blend(refr.Color, info.Element.Material.Transparency);
                    }
                }

                var shadow = new IntersectInfo();
                if (scene.RenderShadow)
                {
                    // calculate shadow, create ray from intersection point to light
                    var shadowray = new Ray(info.Position, v);

                    // find any element in between intersection point and light
                    shadow = TestIntersection(shadowray, scene, info.Element);
                    if (shadow.IsHit && shadow.Element != info.Element)
                    {
                        // only cast shadow if the found interesection is another
                        // element than the current element
                        color *= 0.5 + 0.5 * Math.Pow(shadow.Element.Material.Transparency, 0.5); // Math.Pow(.5, shadow.HitCount);
                    }
                }

                // only show highlights if it is not in the shadow of another object
                if (scene.RenderHighlights && !shadow.IsHit && info.Element.Material.Gloss > 0)
                {
                    // only show Gloss light if it is not in a shadow of another element.
                    // calculate Gloss lighting (Phong)
                    var lv = (info.Element.Position - light.Position).Normalize();
                    var e  = (scene.Camera.Position - info.Element.Position).Normalize();
                    var h  = (e - lv).Normalize();

                    var glossweight = 0.0;
                    glossweight = Math.Pow(Math.Max(info.Normal.DotProduct(h), 0), shininess);
                    color      += light.Color * (glossweight);
                }
            }

            return(color);
        }