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);
        }
        public override ISect Intersect(Ray ray)
        {
            Vector eo = Vector.Minus(Center, ray.Start);
            double v  = Vector.Dot(eo, ray.Dir);
            double dist;

            if (v < 0)
            {
                dist = 0;
            }
            else
            {
                double disc = Math.Pow(Radius, 2) - (Vector.Dot(eo, eo) - Math.Pow(v, 2));
                dist = disc < 0 ? 0 : v - Math.Sqrt(disc);
            }
            if (dist == 0)
            {
                return(null);
            }
            return(new ISect()
            {
                Thing = this,
                Ray = ray,
                Dist = dist
            });
        }
Beispiel #3
0
        public static Camera Create(Vector pos, Vector lookAt)
        {
            Vector forward = Vector.Norm(Vector.Minus(lookAt, pos));
            Vector down    = new Vector(0, -1, 0);
            Vector right   = Vector.Times(1.5, Vector.Norm(Vector.Cross(forward, down)));
            Vector up      = Vector.Times(1.5, Vector.Norm(Vector.Cross(forward, right)));

            return(new Camera()
            {
                Pos = pos, Forward = forward, Up = up, Right = right
            });
        }
        private Color Shade(ISect isect, Scene scene, int depth)
        {
            var   d          = isect.Ray.Dir;
            var   pos        = Vector.Plus(Vector.Times(isect.Dist, isect.Ray.Dir), isect.Ray.Start);
            var   normal     = isect.Thing.Normal(pos);
            var   reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal));
            Color ret        = Color.DefaultColor;

            ret = Color.Plus(ret, GetNaturalColor(isect.Thing, pos, normal, reflectDir, scene));
            if (depth >= MaxDepth)
            {
                return(Color.Plus(ret, Color.Make(.5, .5, .5)));
            }
            return(Color.Plus(ret, GetReflectionColor(isect.Thing, Vector.Plus(pos, Vector.Times(.001, reflectDir)), normal, reflectDir, scene, depth)));
        }
        public static Camera Create(Vector pos, Vector lookAt)
        {
            Vector forward = Vector.Norm(Vector.Minus(lookAt, pos));
            Vector down    = new Vector(0, -1, 0);
            Vector right   = Vector.Times(1.5, Vector.Norm(Vector.Cross(forward, down)));
            Vector up      = Vector.Times(1.5, Vector.Norm(Vector.Cross(forward, right)));

            //Console.WriteLine($"eye {pos.X} {pos.Y} {pos.Z}");
            //Console.WriteLine($"lookAt {lookAt.X} {lookAt.Y} {lookAt.Z}");
            //Console.WriteLine($"up {up.X} {up.Y} {up.Z}");

            return(new Camera()
            {
                Pos = pos, Forward = forward, Up = up, Right = right
            });
        }
 public override Vector Normal(Vector pos)
 {
     return(Vector.Norm(Vector.Minus(pos, Center)));
 }
Beispiel #7
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);
                }
            }
        }