private Color GetNaturalColor(SceneObject thing, Vector pos, Vector norm, Vector rd, Scene scene)
        {
            Color ret = Color.Make(0, 0, 0);

            foreach (Light light in scene.Lights)
            {
                Vector ldis      = Vector.Minus(light.Pos, pos);
                Vector livec     = Vector.Norm(ldis);
                double neatIsect = TestRay(new Ray()
                {
                    Start = pos, Dir = livec
                }, scene);
                bool isInShadow = !((neatIsect > Vector.Mag(ldis)) || (neatIsect == 0));
                if (!isInShadow)
                {
                    double illum    = Vector.Dot(livec, norm);
                    Color  lcolor   = illum > 0 ? Color.Times(illum, light.Color) : Color.Make(0, 0, 0);
                    double specular = Vector.Dot(livec, Vector.Norm(rd));
                    Color  scolor   = specular > 0 ? Color.Times(Math.Pow(specular, thing.Surface.Roughness), light.Color) : Color.Make(0, 0, 0);
                    ret = Color.Plus(ret, Color.Plus(Color.Times(thing.Surface.Diffuse(pos), lcolor),
                                                     Color.Times(thing.Surface.Specular(pos), scolor)));
                }
            }
            return(ret);
        }
 private Color GetReflectionColor(SceneObject thing, Vector pos, Vector norm, Vector rd, Scene scene, int depth)
 {
     return(Color.Times(thing.Surface.Reflect(pos), TraceRay(new Ray()
     {
         Start = pos, Dir = rd
     }, scene, depth + 1)));
 }
Пример #3
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);
                }
            }
        }