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 }); }
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))); }
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); } } }