public static void Start() #endif { // create objects var scene = new Scene(); scene.Objects = new Sphere[] { new Sphere(new Vec3(0.0f, -10002.0f, -20.0f), 10000, new Vec3(.8f, .8f, .8f)), new Sphere(new Vec3(0.0f, 2.0f, -20.0f), 4, new Vec3(.8f, .5f, .5f), 0.5f), new Sphere(new Vec3(5.0f, 0.0f, -15.0f), 2, new Vec3(.3f, .8f, .8f), 0.2f), new Sphere(new Vec3(-5.0f, 0.0f, -15.0f), 2, new Vec3(.3f, .5f, .8f), 0.2f), new Sphere(new Vec3(-2.0f, -1.0f, -10.0f), 1, new Vec3(.1f, .1f, .1f), 0.1f, 0.8f) }; scene.Lights = new Light[]{new Light(new Vec3(-10, 20, 30), new Vec3(2, 2, 2))}; int pixelsLength = Benchmark.Width * Benchmark.Height * 3; byte[] pixels = new byte[pixelsLength]; // give the system a little time #if !JSIL GC.Collect(); Console.WriteLine("Give the system a little time..."); Thread.Sleep(2000); #endif Console.WriteLine("Starting test..."); // run test #if WIN32 Win32OptimizedStopwatch(); #endif var watch = new Stopwatch(); watch.Start(); var data = Benchmark.Render(scene, pixels); watch.Stop(); Console.WriteLine("Sec: " + (watch.ElapsedMilliseconds / 1000d)); #if WIN32 Win32EndOptimizedStopwatch(); #endif // save image #if WIN8 || WP8 || WP7 || ANDROID || IOS || VITA if (SaveImageCallback != null) SaveImageCallback(data); #elif !JSIL Console.ReadLine(); using (var file = new FileStream("Image.raw", FileMode.Create, FileAccess.Write)) using (var writer = new BinaryWriter(file)) { for (int i = 0; i != pixelsLength; ++i) { file.WriteByte(data[i]); } } #else return pixels; #endif }
public static byte[] Render(Scene scene, byte[] pixels) { var eye = Vec3.Zero; Num h = (Num)Math.Tan(((fov / 360) * (2 * PI)) / 2) * 2; Num w = h * Width / Height; for (int y = 0; y != Height; ++y) { for (int x = 0; x != Width; ++x) { Num xx = x, yy = y, ww = Width, hh = Height; Vec3 dir; dir.X = ((xx - (ww / 2.0f)) / ww) * w; dir.Y = (((hh/2.0f) - yy) / hh) * h; dir.Z = -1.0f; dir = Vec3.Normalize(dir); Ray r; r.Org = eye; r.Dir = dir; var pixel = trace(r, scene, 0); int i = (x*3) + (y*Width*3); pixels[i] = (byte)Math.Min(pixel.X * 255, 255); pixels[i+1] = (byte)Math.Min(pixel.Y * 255, 255); pixels[i+2] = (byte)Math.Min(pixel.Z * 255, 255); } } return pixels; }
public static void Start() #endif { // create objects var scene = new Scene(); scene.Objects = new Sphere[] { new Sphere(new Vec3(0.0f, -10002.0f, -20.0f), 10000, new Vec3(.8f, .8f, .8f)), new Sphere(new Vec3(0.0f, 2.0f, -20.0f), 4, new Vec3(.8f, .5f, .5f), 0.5f), new Sphere(new Vec3(5.0f, 0.0f, -15.0f), 2, new Vec3(.3f, .8f, .8f), 0.2f), new Sphere(new Vec3(-5.0f, 0.0f, -15.0f), 2, new Vec3(.3f, .5f, .8f), 0.2f), new Sphere(new Vec3(-2.0f, -1.0f, -10.0f), 1, new Vec3(.1f, .1f, .1f), 0.1f, 0.8f) }; scene.Lights = new Light[] { new Light(new Vec3(-10, 20, 30), new Vec3(2, 2, 2)) }; int pixelsLength = Benchmark.Width * Benchmark.Height * 3; byte[] pixels = new byte[pixelsLength]; // give the system a little time #if !JSIL GC.Collect(); Console.WriteLine("Give the system a little time..."); Thread.Sleep(2000); #endif Console.WriteLine("Starting test..."); // run test #if WIN32 Win32OptimizedStopwatch(); #endif var watch = new Stopwatch(); watch.Start(); var data = Benchmark.Render(scene, pixels); watch.Stop(); Console.WriteLine("Sec: " + (watch.ElapsedMilliseconds / 1000d)); #if WIN32 Win32EndOptimizedStopwatch(); #endif // save image #if UWP || WIN8 || WP8 || WP7 || ANDROID || IOS || VITA if (SaveImageCallback != null) { SaveImageCallback(data); } #elif !JSIL Console.ReadLine(); using (var file = new FileStream("Image.raw", FileMode.Create, FileAccess.Write)) using (var writer = new BinaryWriter(file)) { for (int i = 0; i != pixelsLength; ++i) { file.WriteByte(data[i]); } } #else return(pixels); #endif }
private static Vec3 trace (Ray ray, Scene scene, int depth) { var nearest = Num.MaxValue; Sphere obj = null; // search the scene for nearest intersection foreach(var o in scene.Objects) { var distance = Num.MaxValue; if (Sphere.Intersect(o, ray, out distance)) { if (distance < nearest) { nearest = distance; obj = o; } } } if (obj == null) return Vec3.Zero; var point_of_hit = ray.Org + (ray.Dir * nearest); var normal = Sphere.Normal(obj, point_of_hit); bool inside = false; if (Vec3.Dot(normal, ray.Dir) > 0) { inside = true; normal = -normal; } Vec3 color = Vec3.Zero; var reflection_ratio = obj.Reflection; foreach(var l in scene.Lights) { var light_direction = Vec3.Normalize(l.Position - point_of_hit); Ray r; r.Org = point_of_hit + (normal * 1e-5f); r.Dir = light_direction; // go through the scene check whether we're blocked from the lights bool blocked = false; foreach (var o in scene.Objects) { if (Sphere.Intersect(o, r)) { blocked = true; break; } } if (!blocked) { color += l.Color * Math.Max(0, Vec3.Dot(normal, light_direction)) * obj.Color * (1.0f - reflection_ratio); } } var rayNormDot = Vec3.Dot(ray.Dir, normal); Num facing = Math.Max(0, -rayNormDot); Num fresneleffect = reflection_ratio + ((1 - reflection_ratio) * (Num)Math.Pow((1 - facing), 5)); // compute reflection if (depth < maxDepth && reflection_ratio > 0) { var reflection_direction = ray.Dir + (normal * 2 * rayNormDot * (-1.0f)); Ray r; r.Org = point_of_hit + (normal * 1e-5f); r.Dir = reflection_direction; var reflection = trace(r, scene, depth + 1); color += reflection * fresneleffect; } // compute refraction if (depth < maxDepth && (obj.Transparency > 0)) { var ior = 1.5f; var CE = Vec3.Dot(ray.Dir, normal) * (-1.0f); ior = inside ? (1.0f) / ior : ior; var eta = (1.0f) / ior; var GF = (ray.Dir + normal * CE) * eta; var sin_t1_2 = 1 - (CE * CE); var sin_t2_2 = sin_t1_2 * (eta * eta); if (sin_t2_2 < 1) { var GC = normal * (Num)Math.Sqrt(1 - sin_t2_2); var refraction_direction = GF - GC; Ray r; r.Org = point_of_hit - (normal * 1e-4f); r.Dir = refraction_direction; var refraction = trace(r, scene, depth + 1); color += refraction * (1 - fresneleffect) * obj.Transparency; } } return color; }
private static Vec3 trace(Ray ray, Scene scene, int depth) { var nearest = Num.MaxValue; Sphere obj = null; // search the scene for nearest intersection foreach (var o in scene.Objects) { var distance = Num.MaxValue; if (Sphere.Intersect(o, ray, out distance)) { if (distance < nearest) { nearest = distance; obj = o; } } } if (obj == null) { return(Vec3.Zero); } var point_of_hit = ray.Org + (ray.Dir * nearest); var normal = Sphere.Normal(obj, point_of_hit); bool inside = false; if (Vec3.Dot(normal, ray.Dir) > 0) { inside = true; normal = -normal; } Vec3 color = Vec3.Zero; var reflection_ratio = obj.Reflection; foreach (var l in scene.Lights) { var light_direction = Vec3.Normalize(l.Position - point_of_hit); Ray r; r.Org = point_of_hit + (normal * 1e-5f); r.Dir = light_direction; // go through the scene check whether we're blocked from the lights bool blocked = false; foreach (var o in scene.Objects) { if (Sphere.Intersect(o, r)) { blocked = true; break; } } if (!blocked) { color += l.Color * Math.Max(0, Vec3.Dot(normal, light_direction)) * obj.Color * (1.0f - reflection_ratio); } } var rayNormDot = Vec3.Dot(ray.Dir, normal); Num facing = Math.Max(0, -rayNormDot); Num fresneleffect = reflection_ratio + ((1 - reflection_ratio) * (Num)Math.Pow((1 - facing), 5)); // compute reflection if (depth < maxDepth && reflection_ratio > 0) { var reflection_direction = ray.Dir + (normal * 2 * rayNormDot * (-1.0f)); Ray r; r.Org = point_of_hit + (normal * 1e-5f); r.Dir = reflection_direction; var reflection = trace(r, scene, depth + 1); color += reflection * fresneleffect; } // compute refraction if (depth < maxDepth && (obj.Transparency > 0)) { var ior = 1.5f; var CE = Vec3.Dot(ray.Dir, normal) * (-1.0f); ior = inside ? (1.0f) / ior : ior; var eta = (1.0f) / ior; var GF = (ray.Dir + normal * CE) * eta; var sin_t1_2 = 1 - (CE * CE); var sin_t2_2 = sin_t1_2 * (eta * eta); if (sin_t2_2 < 1) { var GC = normal * (Num)Math.Sqrt(1 - sin_t2_2); var refraction_direction = GF - GC; Ray r; r.Org = point_of_hit - (normal * 1e-4f); r.Dir = refraction_direction; var refraction = trace(r, scene, depth + 1); color += refraction * (1 - fresneleffect) * obj.Transparency; } } return(color); }