示例#1
0
        internal void Render(Scene scene)
        {
            var pixelsQuery =
                from y in Enumerable.Range(0, screenHeight)
                let recenterY = -(y - (screenHeight / 2.0)) / (2.0 * screenHeight)
                                select from x in Enumerable.Range(0, screenWidth)
                                let recenterX                         = (x - (screenWidth / 2.0)) / (2.0 * screenWidth)
                                                            let point =
                    Vector.Norm(Vector.Plus(scene.Camera.Forward,
                                            Vector.Plus(Vector.Times(recenterX, scene.Camera.Right),
                                                        Vector.Times(recenterY, scene.Camera.Up))))
                    let ray = new Ray()
            {
                Start = scene.Camera.Pos, Dir = point
            }
            let computeTraceRay = (Func <Func <TraceRayArgs, Color>, Func <TraceRayArgs, Color> >)
                                      (f => traceRayArgs =>
                                      (from isect in
                                       from thing in traceRayArgs.Scene.Things
                                       select thing.Intersect(traceRayArgs.Ray)
                                       where isect != null
                                       orderby isect.Dist
                                       let d = isect.Ray.Dir
                                               let pos = Vector.Plus(Vector.Times(isect.Dist, isect.Ray.Dir), isect.Ray.Start)
                                                         let normal = isect.Thing.Normal(pos)
                                                                      let reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal))
                                                                                       let naturalColors =
                                           from light in traceRayArgs.Scene.Lights
                                           let ldis = Vector.Minus(light.Pos, pos)
                                                      let livec = Vector.Norm(ldis)
                                                                  let testRay = new Ray()
            {
                Start = pos, Dir = livec
            }
                                       let testIsects = from inter in
                                                        from thing in traceRayArgs.Scene.Things
                                                        select thing.Intersect(testRay)
                                                        where inter != null
                                                        orderby inter.Dist
                                                        select inter
                                                        let testIsect = testIsects.FirstOrDefault()
                                                                        let neatIsect = testIsect == null ? 0 : testIsect.Dist
                                                                                        let isInShadow = !((neatIsect > Vector.Mag(ldis)) || (neatIsect == 0))
                                                                                                         where !isInShadow
                                                                                                         let illum = Vector.Dot(livec, normal)
                                                                                                                     let lcolor = illum > 0 ? Color.Times(illum, light.Color) : Color.Make(0, 0, 0)
                                                                                                                                  let specular = Vector.Dot(livec, Vector.Norm(reflectDir))
                                                                                                                                                 let scolor = specular > 0
                                                                                         ? Color.Times(Math.Pow(specular, isect.Thing.Surface.Roughness),
                                                                                                       light.Color)
                                                                                         : Color.Make(0, 0, 0)
                                                                                                                                                              select Color.Plus(Color.Times(isect.Thing.Surface.Diffuse(pos), lcolor),
                                                                                                                                                                                Color.Times(isect.Thing.Surface.Specular(pos), scolor))
                                                                                                                                                              let reflectPos = Vector.Plus(pos, Vector.Times(.001, reflectDir))
                                                                                                                                                                               let reflectColor = traceRayArgs.Depth >= MaxDepth
                                                                                          ? Color.Make(.5, .5, .5)
                                                                                          : Color.Times(isect.Thing.Surface.Reflect(reflectPos),
                                                                                                        f(new TraceRayArgs(new Ray()
            {
                Start = reflectPos,
                Dir = reflectDir
            },
                                                                                                                           traceRayArgs.Scene,
                                                                                                                           traceRayArgs.Depth + 1)))
                                                                                                                                                                                                  select naturalColors.Aggregate(reflectColor,
                                                                                                                                                                                                                                 (color, natColor) => Color.Plus(color, natColor))
                                      ).DefaultIfEmpty(Color.Background).First())
                                  let traceRay = Y(computeTraceRay)
                                                 select new { X = x, Y = y, Color = traceRay(new TraceRayArgs(ray, scene, 0)) };

            foreach (var row in pixelsQuery)
            {
                foreach (var pixel in row)
                {
                    setPixel(pixel.X, pixel.Y, pixel.Color);
                }
            }
        }
示例#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 Color RayTrace(IntersectInfo info, Ray ray, Scene scene, int depth)
        {
            // calculate ambient light
            Color  color     = info.Color * scene.Background.Ambience;
            double shininess = Math.Pow(10, info.Element.Material.Gloss + 1);

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

                if (RenderDiffuse)
                {
                    double L = v.Dot(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 < 3)
                {
                    // calculate reflection ray
                    if (RenderReflection && info.Element.Material.Reflection > 0)
                    {
                        Ray           reflectionray = GetReflectionRay(info.Position, info.Normal, ray.Direction);
                        IntersectInfo 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 (RenderRefraction && info.Element.Material.Transparency > 0)
                    {
                        Ray           refractionray = GetRefractionRay(info.Position, info.Normal, ray.Direction, info.Element.Material.Refraction);
                        IntersectInfo 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);
                    }
                }


                IntersectInfo shadow = new IntersectInfo();
                if (RenderShadow)
                {
                    // calculate shadow, create ray from intersection point to light
                    Ray 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 (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)
                    Vector Lv = (info.Element.Position - light.Position).Normalize();
                    Vector E  = (scene.Camera.Position - info.Element.Position).Normalize();
                    Vector H  = (E - Lv).Normalize();

                    double Glossweight = 0.0;
                    Glossweight = Math.Pow(Math.Max(info.Normal.Dot(H), 0), shininess);
                    color      += light.Color * (Glossweight);
                }
            }

            // normalize the color
            color.Limit();
            return(color);
        }