/// <summary> /// Creates a new empty geometry. /// </summary> public Geometry(SceneFlags sceneFlags, TraversalFlags traversalFlags = TraversalFlags.Single) { RTC.Register(); this.sceneFlags = sceneFlags; this.traversalFlags = traversalFlags; scenePtr = RTC.NewScene(sceneFlags, traversalFlags); }
/// <summary> /// Creates a new empty geometry. /// </summary> public Geometry(Device device, SceneFlags sceneFlags, TraversalFlags traversalFlags = TraversalFlags.Single) { this.device = device; this.sceneFlags = sceneFlags; this.traversalFlags = traversalFlags; scenePtr = RTC.NewScene(device.DevicePtr, sceneFlags, traversalFlags); }
private static void CreateGeometry(Device device, SceneFlags sceneFlags, TraversalFlags traversalFlags, MeshFlags meshFlags, TriangleMesh sphere, int numMeshes) { using (var scene = new Scene <Sphere>(device, sceneFlags, traversalFlags)) { for (var t = 0; t < numMeshes; ++t) { scene.Add(new Sphere(device, sceneFlags, traversalFlags, sphere, meshFlags)); for (int v = 0; v < sphere.Vertices.Count; ++v) { sphere.Vertices[v] = (Vector)sphere.Vertices[v] + new Vector(1, 1, 1); } } scene.Commit(); } }
/// <summary> /// Parses command-line arguments for traversal flags. /// </summary> private static TraversalFlags ParseCommandLineArguments(String[] args) { TraversalFlags flags = 0; foreach (var arg in args) { int v; if (int.TryParse(arg, out v)) { switch (v) { case 1: flags |= TraversalFlags.Single; break; case 4: flags |= TraversalFlags.Packet4; break; case 8: flags |= TraversalFlags.Packet8; break; case 16: flags |= TraversalFlags.Packet16; break; default: throw new ArgumentException("Unknown ray packet size argument"); } } else if (!arg.Equals("verbose")) { throw new ArgumentException("Failed to parse ray packet size argument"); } } if (flags == 0) // If no arguments, fall back to 1/8 { flags = TraversalFlags.Single | TraversalFlags.Packet4 | TraversalFlags.Packet8; } return(flags); }
/// <summary> /// Parses command-line arguments for traversal flags. /// </summary> private static void ParseCommandLineArguments(String[] args) { if (args.Length == 0) // If no arguments, fall back to 1/4 { Flags = TraversalFlags.Single | TraversalFlags.Packet4; } else { foreach (var arg in args) { try { switch (int.Parse(arg)) { case 1: Flags |= TraversalFlags.Single; break; case 4: Flags |= TraversalFlags.Packet4; break; case 8: Flags |= TraversalFlags.Packet8; break; case 16: Flags |= TraversalFlags.Packet16; break; default: throw new ArgumentException("Unknown ray packet size argument"); } } catch (FormatException) { throw new ArgumentException("Failed to parse ray packet size argument"); } } } }
/// <summary> /// Parses command-line arguments for traversal flags. /// </summary> private static void ParseCommandLineArguments(String[] args) { if (args.Length == 0) // If no arguments, fall back to 1/4 Flags = TraversalFlags.Single | TraversalFlags.Packet4; else { foreach (var arg in args) { try { switch (int.Parse(arg)) { case 1: Flags |= TraversalFlags.Single; break; case 4: Flags |= TraversalFlags.Packet4; break; case 8: Flags |= TraversalFlags.Packet8; break; case 16: Flags |= TraversalFlags.Packet16; break; default: throw new ArgumentException("Unknown ray packet size argument"); } } catch (FormatException) { throw new ArgumentException("Failed to parse ray packet size argument"); } } } }
public Sphere(SceneFlags sceneFlags, TraversalFlags traversalFlags, IMesh mesh, MeshFlags meshFlags = MeshFlags.Static) { geometry = new Geometry(sceneFlags, traversalFlags); geometry.Add(mesh, meshFlags); }
public Sphere(SceneFlags sceneFlags, TraversalFlags traversalFlags, int numPhi, MeshFlags meshFlags = MeshFlags.Static) { geometry = new Geometry(sceneFlags, traversalFlags); geometry.Add(GenerateSphere(numPhi), meshFlags); }
public static extern IntPtr NewScene(SceneFlags flags, TraversalFlags aFlags);
public static IEnumerable<Tuple<String, Action, Func<Double, String>>> Geometries(SceneFlags sceneFlags, TraversalFlags traversalFlags) { var items = new Dictionary<String, Tuple<int, int>> { { "120", new Tuple<int, int>(6, 1) }, { "1k", new Tuple<int, int>(17, 1) }, { "10k", new Tuple<int, int>(51, 1) }, { "100k", new Tuple<int, int>(159, 1) }, { "1000k_1", new Tuple<int, int>(501, 1) }, { "100k_10", new Tuple<int, int>(159, 10) }, { "10k_100", new Tuple<int, int>(51, 100) }, { "1k_1000", new Tuple<int, int>(17, 1000) }, //{ "120_10000", new Tuple<int, int>(6, 8334) }, }; foreach (var item in items) { var sphere = (TriangleMesh)Sphere.GenerateSphere(item.Value.Item1); yield return new Tuple<String, Action, Func<Double, String>>("create_static_geometry_" + item.Key, () => CreateGeometry(sceneFlags, traversalFlags, MeshFlags.Static, sphere, item.Value.Item2), (t) => String.Format("{0:N3} Mtris/s", 1e-6 * item.Value.Item2 * sphere.Indices.Count / 3)); } foreach (var item in items) { var sphere = (TriangleMesh)Sphere.GenerateSphere(item.Value.Item1); yield return new Tuple<String, Action, Func<Double, String>>("create_dynamic_geometry_" + item.Key, () => CreateGeometry(sceneFlags, traversalFlags, MeshFlags.Dynamic, sphere, item.Value.Item2), (t) => String.Format("{0:N3} Mtris/s", 1e-6 * item.Value.Item2 * sphere.Indices.Count / 3)); } }
public static IEnumerable<Tuple<String, Action, Func<Double, String>>> Occlusions(SceneFlags sceneFlags, TraversalFlags traversalFlags, int numPhi, int w, int h) { Func<Double, String> timer = (t) => String.Format("{0:N3} Mrays/s", 1e-6 * w * h / t); using (var scene = new Scene<Sphere>(sceneFlags, traversalFlags)) { scene.Add(new Sphere(sceneFlags, traversalFlags, numPhi)); scene.Commit(); if (traversalFlags.HasFlag(TraversalFlags.Single)) yield return new Tuple<String, Action, Func<Double, String>>("coherent_occlusion1", () => CoherentOcclusion1(scene, w, h), timer); if (traversalFlags.HasFlag(TraversalFlags.Packet4)) yield return new Tuple<String, Action, Func<Double, String>>("coherent_occlusion4", () => CoherentOcclusion4(scene, w, h), timer); if (traversalFlags.HasFlag(TraversalFlags.Packet8)) yield return new Tuple<String, Action, Func<Double, String>>("coherent_occlusion8", () => CoherentOcclusion8(scene, w, h), timer); if (traversalFlags.HasFlag(TraversalFlags.Packet16)) yield return new Tuple<String, Action, Func<Double, String>>("coherent_occlusion16", () => CoherentOcclusion16(scene, w, h), timer); var random = new Random(); var rays = new Ray[w * h]; for (var t = 0; t < w * h; ++t) rays[t] = new Ray(Vector.Zero, new Vector(2 * (float)random.NextDouble() - 1, 2 * (float)random.NextDouble() - 1, 2 * (float)random.NextDouble() - 1)); if (traversalFlags.HasFlag(TraversalFlags.Single)) yield return new Tuple<String, Action, Func<Double, String>>("incoherent_occlusion1", () => IncoherentOcclusion1(scene, w * h, rays), timer); if (traversalFlags.HasFlag(TraversalFlags.Packet4)) yield return new Tuple<String, Action, Func<Double, String>>("incoherent_occlusion4", () => IncoherentOcclusion4(scene, w * h, rays), timer); if (traversalFlags.HasFlag(TraversalFlags.Packet8)) yield return new Tuple<String, Action, Func<Double, String>>("incoherent_occlusion8", () => IncoherentOcclusion8(scene, w * h, rays), timer); if (traversalFlags.HasFlag(TraversalFlags.Packet16)) yield return new Tuple<String, Action, Func<Double, String>>("incoherent_occlusion16", () => IncoherentOcclusion16(scene, w * h, rays), timer); } }
private static void CreateGeometry(SceneFlags sceneFlags, TraversalFlags traversalFlags, MeshFlags meshFlags, TriangleMesh sphere, int numMeshes) { using (var scene = new Scene<Sphere>(sceneFlags, traversalFlags)) { for (var t = 0; t < numMeshes; ++t) { scene.Add(new Sphere(sceneFlags, traversalFlags, sphere, meshFlags)); for (int v = 0; v < sphere.Vertices.Count; ++v) sphere.Vertices[v] = (Vector)sphere.Vertices[v] + new Vector(1, 1, 1); } scene.Commit(); } }
public static IEnumerable <Tuple <String, Action, Func <Double, String> > > Occlusions(Device device, SceneFlags sceneFlags, TraversalFlags traversalFlags, int numPhi, int w, int h) { Func <Double, String> timer = (t) => String.Format("{0:N3} Mrays/s", 1e-6 * w * h / t); using (var scene = new Scene <Sphere>(device, sceneFlags, traversalFlags)) { scene.Add(new Sphere(scene.Device, sceneFlags, traversalFlags, numPhi)); scene.Commit(); if (traversalFlags.HasFlag(TraversalFlags.Single)) { yield return(new Tuple <String, Action, Func <Double, String> >("coherent_occlusion1", () => CoherentOcclusion1(scene, w, h), timer)); } if (traversalFlags.HasFlag(TraversalFlags.Packet4)) { yield return(new Tuple <String, Action, Func <Double, String> >("coherent_occlusion4", () => CoherentOcclusion4(scene, w, h), timer)); } if (traversalFlags.HasFlag(TraversalFlags.Packet8)) { yield return(new Tuple <String, Action, Func <Double, String> >("coherent_occlusion8", () => CoherentOcclusion8(scene, w, h), timer)); } if (traversalFlags.HasFlag(TraversalFlags.Packet16)) { yield return(new Tuple <String, Action, Func <Double, String> >("coherent_occlusion16", () => CoherentOcclusion16(scene, w, h), timer)); } var random = new Random(); var rays = new Ray[w * h]; for (var t = 0; t < w * h; ++t) { rays[t] = new Ray(Vector.Zero, new Vector(2 * (float)random.NextDouble() - 1, 2 * (float)random.NextDouble() - 1, 2 * (float)random.NextDouble() - 1)); } if (traversalFlags.HasFlag(TraversalFlags.Single)) { yield return(new Tuple <String, Action, Func <Double, String> >("incoherent_occlusion1", () => IncoherentOcclusion1(scene, w * h, rays), timer)); } if (traversalFlags.HasFlag(TraversalFlags.Packet4)) { yield return(new Tuple <String, Action, Func <Double, String> >("incoherent_occlusion4", () => IncoherentOcclusion4(scene, w * h, rays), timer)); } if (traversalFlags.HasFlag(TraversalFlags.Packet8)) { yield return(new Tuple <String, Action, Func <Double, String> >("incoherent_occlusion8", () => IncoherentOcclusion8(scene, w * h, rays), timer)); } if (traversalFlags.HasFlag(TraversalFlags.Packet16)) { yield return(new Tuple <String, Action, Func <Double, String> >("incoherent_occlusion16", () => IncoherentOcclusion16(scene, w * h, rays), timer)); } } }
public static IEnumerable <Tuple <String, Action, Func <Double, String> > > Geometries(Device device, SceneFlags sceneFlags, TraversalFlags traversalFlags) { var items = new Dictionary <String, Tuple <int, int> > { { "120", new Tuple <int, int>(6, 1) }, { "1k", new Tuple <int, int>(17, 1) }, { "10k", new Tuple <int, int>(51, 1) }, { "100k", new Tuple <int, int>(159, 1) }, { "1000k_1", new Tuple <int, int>(501, 1) }, { "100k_10", new Tuple <int, int>(159, 10) }, { "10k_100", new Tuple <int, int>(51, 100) }, { "1k_1000", new Tuple <int, int>(17, 1000) }, //{ "120_10000", new Tuple<int, int>(6, 8334) }, }; foreach (var item in items) { var sphere = (TriangleMesh)Sphere.GenerateSphere(device, item.Value.Item1); yield return(new Tuple <String, Action, Func <Double, String> >("create_static_geometry_" + item.Key, () => CreateGeometry(device, sceneFlags, traversalFlags, MeshFlags.Static, sphere, item.Value.Item2), (t) => String.Format("{0:N3} Mtris/s", 1e-6 * item.Value.Item2 * sphere.Indices.Count / 3))); } foreach (var item in items) { var sphere = (TriangleMesh)Sphere.GenerateSphere(device, item.Value.Item1); yield return(new Tuple <String, Action, Func <Double, String> >("create_dynamic_geometry_" + item.Key, () => CreateGeometry(device, sceneFlags, traversalFlags, MeshFlags.Dynamic, sphere, item.Value.Item2), (t) => String.Format("{0:N3} Mtris/s", 1e-6 * item.Value.Item2 * sphere.Indices.Count / 3))); } }
/// <summary> /// Renders the scene into a pixel buffer. /// </summary> public void Render(PixelBuffer pixbuf, TraversalFlags mode = TraversalFlags.Single) { float dx = 1.0f / pixbuf.Width, dy = 1.0f / pixbuf.Height; camera.AspectRatio = (float)pixbuf.Width / pixbuf.Height; // Free parallelism, why not! Note a Parallel.For loop // over each row is slightly faster but less readable. Parallel.ForEach(pixbuf, (pixel) => { var color = Vector.Zero; float u = pixel.X * dx; float v = pixel.Y * dy; Ray[] rays = null; Intersection <Model>[] hits = null; if (mode == TraversalFlags.Single) { rays = new[] { camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1) }; var packet = scene.Intersects(rays[0]); hits = new Intersection <Model>[] { packet.ToIntersection <Model>(scene) }; } else if (mode == TraversalFlags.Packet4) { rays = new[] { camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1), camera.Trace(2 * (u + 0.25f * dx) - 1, 2 * (v - 0.25f * dy) - 1), camera.Trace(2 * (u - 0.25f * dx) - 1, 2 * (v + 0.25f * dy) - 1), camera.Trace(2 * (u + 0.25f * dx) - 1, 2 * (v + 0.25f * dy) - 1) }; // Trace a packet of coherent AA rays var packet = scene.Intersects4(rays); // Convert the packet to a set of usable ray-geometry intersections hits = packet.ToIntersection <Model>(scene); } else if (mode == TraversalFlags.Packet8) { // Sampling pattern Rotated grid // https://en.wikipedia.org/wiki/Supersampling#Supersampling_patterns // ------------ // | X X | // | X X | // | X X | // | X X | // ------------ //https://www.desmos.com/calculator/l2ynkbsahy rays = new[] { camera.Trace(2 * (u - 0.333f * dx) - 1, 2 * (v - 0.166f * dy) - 1), camera.Trace(2 * (u - 0.166f * dx) - 1, 2 * (v - 0.333f * dy) - 1), camera.Trace(2 * (u - 0.300f * dx) - 1, 2 * (v + 0.300f * dy) - 1), camera.Trace(2 * (u - 0.100f * dx) - 1, 2 * (v + 0.100f * dy) - 1), camera.Trace(2 * (u + 0.100f * dx) - 1, 2 * (v - 0.100f * dy) - 1), camera.Trace(2 * (u + 0.300f * dx) - 1, 2 * (v - 0.300f * dy) - 1), camera.Trace(2 * (u + 0.166f * dx) - 1, 2 * (v + 0.333f * dy) - 1), camera.Trace(2 * (u + 0.333f * dx) - 1, 2 * (v + 0.166f * dy) - 1) }; // Trace a packet of coherent AA rays var packet = scene.Intersects8(rays); // Convert the packet to a set of usable ray-geometry intersections hits = packet.ToIntersection <Model>(scene); } else { throw new Exception("Invalid mode"); } for (int t = 0; t < hits.Length; ++t) { if (hits[t].HasHit) { color += new Vector(0.1f, 0.1f, 0.1f); var ray = rays[t]; var model = hits[t].Instance; // Parse the surface normal returned and then process it manually var rawNormal = new Vector(hits[t].NX, hits[t].NY, hits[t].NZ); var normal = model.CorrectNormal(rawNormal); // Important! // Calculate the new ray towards the light source var hitPoint = ray.PointAt(hits[t].Distance); var toLight = lightPosition - hitPoint; // from A to B = B - A var lightRay = new Ray(hitPoint + normal * Constants.Epsilon, toLight); // Is the light source occluded? If so, no point calculating any lighting if (!scene.Occludes(lightRay, 0, toLight.Length())) { // Compute the Lambertian cosine term (rendering equation) float cosLight = Vector.Dot(normal, toLight.Normalize()); // Calculate the total light attenuation (inverse square law + cosine law) var attenuation = lightIntensity * cosLight / Vector.Dot(toLight, toLight); color += model.Material(hits[t].Mesh).BRDF(toLight.Normalize(), ray.Direction, normal) * attenuation; } } } // Average the per-pixel samples pixbuf.SetColor(pixel, color / rays.Length); }); }