public Tracer(Scene s) { Width = 640; Height = 480; Background = Color.Black; Scene = s; }
public MainWindow() { scene = Scene.TwoPlanes; this.ReflectionDepth = 5; this.FieldOfView = 120; scene.Camera.FieldOfView = this.FieldOfView; this.MultiThreadedRendering = true; this.DrawLinesAsync = true; InitializeComponent(); InitializeKeyListeners(); InitializeSceneOptions(); this.SizeToContent = System.Windows.SizeToContent.Manual; this.Width = 640; this.Height = 480; Task.Run(() => { Task.Delay(100).Wait(); this.InvokeOnApplicationDispatcher(() => { DrawSceneLinesMultiThreaded(); }); }); }
private RayTracer.Scene CreateScene() { RayTracer.Scene scene = new RayTracer.Scene(); scene.SetLight(this.light); scene.SetCamera(this.camera); scene.allObjects = this.objects.Values.ToList(); return(scene); }
private void MenuItem_Save_Click(object sender, RoutedEventArgs e) { System.Windows.Forms.SaveFileDialog saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); saveFileDialog1.Filter = "|*.xml"; saveFileDialog1.Title = "Save database"; saveFileDialog1.ShowDialog(); // If the file name is not an empty string open it for saving. if (saveFileDialog1.FileName != "") { RayTracer.Scene scene = CreateScene(); RayTracer.Database.DatabaseHandler.Save(scene, saveFileDialog1.FileName); } }
// Camera = new Camera(new Vector3(0, 0, -5), new Vector3(0, 0, 1)); public Image TraceRay(Viewport viewport, Camera camera, Scene scene) { var image = new Image(viewport); Color[,] colours; for (int y = 0; y < viewport.Height; y++) { for (int x = 0; x < viewport.Width; x++) { Ray ray = camera.GetRay(x, y, viewport); } } throw new NotImplementedException(); }
private void renderButton_Click(object sender, RoutedEventArgs e) { Button button = (Button)sender; if ((string)button.Content == "Render") { ts = new CancellationTokenSource(); CancellationToken ct = ts.Token; Task.Factory.StartNew(() => { RayTracer.Scene scene = CreateScene(); if (addFloor) { RayTracer.Floor floor = new RayTracer.Floor(1, new RayTracer.Point(-10, 0, -10), new RayTracer.Point(10, 0, 10)); floor.SetProperties(0.6f, 0.4f, 0); floor.SetColors(new RayTracer.Color(0, 0, 0), new RayTracer.Color(1, 1, 1)); scene.allObjects.Add(floor); } RayTracer.Renderer renderer = new RayTracer.Renderer(scene, scene.allObjects); scene.width = RenderWidth; scene.height = RenderHeight; renderer.ct = ct; Console.WriteLine("Raytracing started."); int time = Environment.TickCount; RayTracer.RenderWindow window = renderer.Render(); if (ct.IsCancellationRequested) { return; } time = -time + Environment.TickCount; Console.WriteLine("Raytracing finished."); window.ShowImage(); Console.WriteLine("Intersection calculating time: \t" + scene.intersectionCalculationCount + "\nRender time: \t\t" + time + "ms"); window.ShowDialog(); }, ct); button.Content = "Cancel"; } else { // Can't wait anymore => cancel this task ts.Cancel(); button.Content = "Render"; } }
private void loadToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "JSON Scene|*.json"; if (ofd.ShowDialog() == DialogResult.OK) { try { sc = Scene.Load(ofd.FileName); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error loading scene", MessageBoxButtons.OK); return; } tsslblScene.Text = Path.GetFileName(ofd.FileName); pnlControls.Enabled = true; } }
private void SetupScene(int width, int height) { //Vector3D bunnyCenter = loadedPlyFile.GetScanAsSpheres().GetAxisAlignedBoundingBox().Center; scene = new RayTracer.Scene(); scene.camera = new RayTracer.Camera(width, height, MathHelper.DegreesToRadians(40)); scene.background = new RayTracer.Background(new RGBA_Floats(0.5, .5, .5), 0.4); //AddBoxAndSheresBooleanTest(); //AddBoxAndBoxBooleanTest(); #if false renderCollection.Add(new BoxShape(new Vector3(), new Vector3(1, 1, 1), new SolidMaterial(new RGBA_Floats(.9, .2, .1), .01, 0.0, 2.0))); renderCollection.Add(new BoxShape(new Vector3(.5, .5, .5), new Vector3(1.5, 1.5, 1.5), new SolidMaterial(new RGBA_Floats(.9, .2, .1), .01, 0.0, 2.0))); #endif //renderCollection.Add(new CylinderShape(.25, 1, new SolidMaterial(RGBA_Floats.Cyan, 0, 0, 0))); //AddSphereAndBox(); //AddAxisMarker(); //AddCubeOfShperes(); renderCollection.Add(MakerGearXCariage()); allObjects = BoundingVolumeHierarchy.CreateNewHierachy(renderCollection); trackBallTransform = new Transform(allObjects); //allObjects = root; scene.shapes.Add(trackBallTransform); //AddAFloor(); //add two lights for better lighting effects scene.lights.Add(new Light(new Vector3(50, -10, 100), new RGBA_Floats(0.8, 0.8, 0.8))); scene.lights.Add(new Light(new Vector3(-30, -150, 50), new RGBA_Floats(0.8, 0.8, 0.8))); OrientCamera(); }
/// <summary> /// Determines whether a given ray intersects with any scene objects (other than excludedObject) /// </summary> /// <param name="ray">The ray to test</param> /// <param name="scene">The scene to test</param> /// <param name="excludedObject">An object that is not tested for intersections</param> /// <param name="intersection">If the intersection test succeeds, contains the closest intersection</param> /// <returns>A value indicating whether or not any scene object intersected with the ray</returns> private bool TryCalculateIntersection(Ray ray, Scene scene, DrawableSceneObject excludedObject, out Intersection intersection) { var closestDistance = float.PositiveInfinity; var closestIntersection = new Intersection(); foreach (var sceneObject in scene.DrawableObjects) { Intersection i; if (sceneObject != excludedObject && sceneObject.TryCalculateIntersection(ray, out i)) { if (i.Distance < closestDistance) { closestDistance = i.Distance; closestIntersection = i; } } } if (closestDistance == float.PositiveInfinity) { intersection = new Intersection(); return false; } else { intersection = closestIntersection; return true; } }
private Color TraceRayAgainstScene(Ray ray, Scene scene) { Intersection intersection; if (TryCalculateIntersection(ray, scene, null, out intersection)) { return CalculateRecursiveColor(intersection, scene, 0); } else { return scene.BackgroundColor; } }
/// <summary> /// Renders the given scene, providing a callback for each individual line rendered. Each line is rendered on a separate thread. /// </summary> /// <param name="width">The width of the rendered image</param> /// <param name="width">The height of the rendered image</param> /// <param name="scene">The scene to render</param> /// <param name="callback">The delegate invoked when a thread completes rendering a line</param> public void RenderSceneLinesThreaded(Scene scene, int width, int height, LineFinishedHandler callback) { if (width == -1 || height == -1) { width = renderSize.Width; height = renderSize.Height; } else { renderSize = new Size(width, height); } var before = DateTime.UtcNow; List<Task> tasks = new List<Task>(); for (int yCounter = height - 1; yCounter >= 0; yCounter--) { var y = yCounter; Color[] colors = new Color[width]; Task.Run(() => { for (int xCounter = 0; xCounter < width; xCounter++) { var x = xCounter; var viewPortX = ((2 * x) / (float)width) - 1; var viewPortY = ((2 * y) / (float)height) - 1; var color = TraceRayAgainstScene(GetRay(viewPortX, viewPortY), scene); colors[x] = color; } callback(y, colors); }); } var after = DateTime.UtcNow; System.Diagnostics.Debug.WriteLine("Total render time: " + (after - before).TotalMilliseconds + " ms"); }
private void Form1_Load(object sender, EventArgs e) { Scene = new Scene(new Camera(pictureBox1.Width, pictureBox1.Height, -10000)); Scene.LightIntensity = trackBar1.Value; }
public Color CaculateColour(Ray ray, Scene scene) { throw new NotImplementedException(); }
private double TestRay(Ray ray, Scene scene) { var isects = Intersections(ray, scene); ISect isect = isects.FirstOrDefault(); if (isect == null) return 0; return isect.Dist; }
private IEnumerable<ISect> Intersections(Ray ray, Scene scene) { return scene.Things .Select(obj => obj.Intersect(ray)) .Where(inter => inter != null) .OrderBy(inter => inter.Dist); }
private Colour GetNaturalColor(Thing thing, Vector3 pos, Vector3 norm, Vector3 rd, Scene scene) { Colour ret = new Colour(0, 0, 0); foreach (LightSource light in scene.Lights) { Vector3 ldis = light.Pos - pos; Vector3 livec = ldis.Normalized(); double neatIsect = TestRay(new Ray(pos, livec), scene); bool isInShadow = !((neatIsect > ldis.Length()) || (neatIsect == 0)); if (!isInShadow) { double illum = livec.DotProduct(norm); Colour lcolor = illum > 0 ? illum * light.Color : new Colour(0, 0, 0); double specular = livec.DotProduct(rd.Normalized()); Colour scolor = specular > 0 ? Math.Pow(specular, thing.Surface.Roughness) * light.Color : new Colour(0, 0, 0); ret = ret + (thing.Surface.Diffuse(pos) * lcolor) + (thing.Surface.Specular(pos) * scolor); } } return(ret); }
/// <summary> /// this is the main entrypoint for rendering a scene. this method is responsible for correctly rendering /// the graphics device (in this case a bitmap). /// Note that apart from the raytracing, painting on a graphics device is rather slow /// </summary> /// <param name="g">the graphics to render on</param> /// <param name="viewport">basically determines the size of the bitmap to render on</param> /// <param name="scene">the scene to render.</param> public void RayTraceScene(Graphics g, Rectangle viewport, Scene scene) { int maxsamples = (int)AntiAliasing; g.FillRectangle(Brushes.Black, viewport); //Color[] scanline1; //Color[] scanline2 = null; //Color[] scanline3 = null; Color[,] buffer = new Color[viewport.Width + 2, viewport.Height + 2]; for (int y = 0; y < viewport.Height + 2; y++) { DateTime timestart = DateTime.Now; //// used for anti-aliasing //scanline1 = scanline2; //scanline2 = scanline3; //scanline3 = new Color[viewport.Width + 2]; for (int x = 0; x < viewport.Width + 2; x++) { double yp = y * 1.0f / viewport.Height * 2 - 1; double xp = x * 1.0f / viewport.Width * 2 - 1; Ray ray = scene.Camera.GetRay(xp, yp); // this will trigger the raytracing algorithm buffer[x, y] = CalculateColor(ray, scene); if ((x > 1) && (y > 1)) { if (AntiAliasing != AntiAliasing.None) { Color avg = (buffer[x - 2, y - 2] + buffer[x - 1, y - 2] + buffer[x, y - 2] + buffer[x - 2, y - 1] + buffer[x - 1, y - 1] + buffer[x, y - 1] + buffer[x - 2, y] + buffer[x - 1, y] + buffer[x, y]) / 9; if (AntiAliasing == AntiAliasing.Quick) { // this basically implements a simple mean filter // it quick but not very accurate buffer[x - 1, y - 1] = avg; } else { // use a more accurate antialasing method (MonteCarlo implementation) // this will fire multiple rays per pixel if (avg.Distance(buffer[x - 1, y - 1]) > 0.18) // 0.18 is a treshold for detailed aliasing { for (int i = 0; i < maxsamples; i++) { // get some 'random' samples double rx = Math.Sign(i % 4 - 1.5) * (IntNoise(x + y * viewport.Width * maxsamples * 2 + i) + 1) / 4; // interval <-0.5, 0.5> double ry = Math.Sign(i % 2 - 0.5) * (IntNoise(x + y * viewport.Width * maxsamples * 2 + 1 + i) + 1) / 4; // interval <-0.5, 0.5> xp = (x - 1 + rx) * 1.0f / viewport.Width * 2 - 1; yp = (y - 1 + ry) * 1.0f / viewport.Height * 2 - 1; ray = scene.Camera.GetRay(xp, yp); // execute even more ray traces, this makes detailed anti-aliasing expensive buffer[x - 1, y - 1] += CalculateColor(ray, scene); } buffer[x - 1, y - 1] /= (maxsamples + 1); } } } // this is the slow part of the painting algorithm, it can be greatly speed up // by directly accessing the bitmap data Brush br = new SolidBrush(buffer[x - 1, y - 1].ToArgb()); g.FillRectangle(br, viewport.Left + x - 2, viewport.Top + y - 2, 1, 1); br.Dispose(); } } // update progress after every scanline if (RenderUpdate != null) { double progress = (y) / (double)(viewport.Height); double duration = DateTime.Now.Subtract(timestart).TotalMilliseconds; double ETA = duration / progress - duration; RenderUpdate.Invoke((int)progress * 100, duration, ETA, y - 1); } } }
/// <summary> /// This is the main RayTrace controller algorithm, the core of the RayTracer /// recursive method setup /// this does the actual tracing of the ray and determines the color of each pixel /// supports: /// - ambient lighting /// - diffuse lighting /// - Gloss lighting /// - shadows /// - reflections /// </summary> /// <param name="info"></param> /// <param name="ray"></param> /// <param name="scene"></param> /// <param name="depth"></param> /// <returns></returns> private Color RayTrace(IntersectInfo info, Ray ray, Scene scene, int depth) { // calculate ambient light Color color = info.Color * scene.Background.Ambience; double shininess = Math.Pow(10, info.Element.Material.Gloss + 1); foreach (Light light in scene.Lights) { // calculate diffuse lighting Vector v = (light.Position - info.Position).Normalize(); if (RenderDiffuse) { double L = v.Dot(info.Normal); if (L > 0.0f) { color += info.Color * light.Color * L; } } // this is the max depth of raytracing. // increasing depth will calculate more accurate color, however it will // also take longer (exponentially) if (depth < 3) { // calculate reflection ray if (RenderReflection && info.Element.Material.Reflection > 0) { Ray reflectionray = GetReflectionRay(info.Position, info.Normal, ray.Direction); IntersectInfo refl = TestIntersection(reflectionray, scene, info.Element); if (refl.IsHit && refl.Distance > 0) { // recursive call, this makes reflections expensive refl.Color = RayTrace(refl, reflectionray, scene, depth + 1); } else // does not reflect an object, then reflect background color { refl.Color = scene.Background.Color; } color = color.Blend(refl.Color, info.Element.Material.Reflection); } //calculate refraction ray if (RenderRefraction && info.Element.Material.Transparency > 0) { Ray refractionray = GetRefractionRay(info.Position, info.Normal, ray.Direction, info.Element.Material.Refraction); IntersectInfo refr = info.Element.Intersect(refractionray); if (refr.IsHit) { //refractionray = new Ray(refr.Position, ray.Direction); refractionray = GetRefractionRay(refr.Position, refr.Normal, refractionray.Direction, refr.Element.Material.Refraction); refr = TestIntersection(refractionray, scene, info.Element); if (refr.IsHit && refr.Distance > 0) { // recursive call, this makes refractions expensive refr.Color = RayTrace(refr, refractionray, scene, depth + 1); } else { refr.Color = scene.Background.Color; } } else { refr.Color = scene.Background.Color; } color = color.Blend(refr.Color, info.Element.Material.Transparency); } } IntersectInfo shadow = new IntersectInfo(); if (RenderShadow) { // calculate shadow, create ray from intersection point to light Ray shadowray = new Ray(info.Position, v); // find any element in between intersection point and light shadow = TestIntersection(shadowray, scene, info.Element); if (shadow.IsHit && shadow.Element != info.Element) { // only cast shadow if the found interesection is another // element than the current element color *= 0.5 + 0.5 * Math.Pow(shadow.Element.Material.Transparency, 0.5); // Math.Pow(.5, shadow.HitCount); } } // only show highlights if it is not in the shadow of another object if (RenderHighlights && !shadow.IsHit && info.Element.Material.Gloss > 0) { // only show Gloss light if it is not in a shadow of another element. // calculate Gloss lighting (Phong) Vector Lv = (info.Element.Position - light.Position).Normalize(); Vector E = (scene.Camera.Position - info.Element.Position).Normalize(); Vector H = (E - Lv).Normalize(); double Glossweight = 0.0; Glossweight = Math.Pow(Math.Max(info.Normal.Dot(H), 0), shininess); color += light.Color * (Glossweight); } } // normalize the color color.Limit(); return(color); }
public Bitmap RayTraceRows(Scene scene, Rectangle viewport, int startRow, int numberOfRowsToTrace) { int maxsamples = (int)AntiAliasing; Color[,] buffer = new Color[viewport.Width + 2, numberOfRowsToTrace + 2]; Bitmap image = new Bitmap(viewport.Width, numberOfRowsToTrace); for (int y = startRow; y < (startRow + numberOfRowsToTrace) + 2; y++) { for (int x = 0; x < viewport.Width + 2; x++) { double yp = y * 1.0f / viewport.Height * 2 - 1; double xp = x * 1.0f / viewport.Width * 2 - 1; Ray ray = scene.Camera.GetRay(xp, yp); // this will trigger the raytracing algorithm buffer[x, y - startRow] = CalculateColor(ray, scene); // if current line is at least 2 lines into the scan if ((x > 1) && (y > startRow + 1)) { if (AntiAliasing != AntiAliasing.None) { Color avg = (buffer[x - 2, y - startRow - 2] + buffer[x - 1, y - startRow - 2] + buffer[x, y - startRow - 2] + buffer[x - 2, y - startRow - 1] + buffer[x - 1, y - startRow - 1] + buffer[x, y - startRow - 1] + buffer[x - 2, y - startRow] + buffer[x - 1, y - startRow] + buffer[x, y - startRow]) / 9; if (AntiAliasing == AntiAliasing.Quick) { // this basically implements a simple mean filter // it quick but not very accurate buffer[x - 1, y - startRow - 1] = avg; } else { // use a more accurate antialasing method (MonteCarlo implementation) // this will fire multiple rays per pixel if (avg.Distance(buffer[x - 1, y - startRow - 1]) > 0.18) // 0.18 is a treshold for detailed aliasing { for (int i = 0; i < maxsamples; i++) { // get some 'random' samples double rx = Math.Sign(i % 4 - 1.5) * (IntNoise(x + y * viewport.Width * maxsamples * 2 + i) + 1) / 4; // interval <-0.5, 0.5> double ry = Math.Sign(i % 2 - 0.5) * (IntNoise(x + y * viewport.Width * maxsamples * 2 + 1 + i) + 1) / 4; // interval <-0.5, 0.5> xp = (x - 1 + rx) * 1.0f / viewport.Width * 2 - 1; yp = (y - 1 + ry) * 1.0f / viewport.Height * 2 - 1; ray = scene.Camera.GetRay(xp, yp); // execute even more ray traces, this makes detailed anti-aliasing expensive buffer[x - 1, y - startRow - 1] += CalculateColor(ray, scene); } buffer[x - 1, y - startRow - 1] /= (maxsamples + 1); } } } image.SetPixel(x - 2, y - startRow - 2, buffer[x - 1, y - startRow - 1].ToArgb()); } } System.Windows.Forms.Application.DoEvents(); } return(image); }
private Colour GetReflectionColor(Thing thing, Vector3 pos, Vector3 norm, Vector3 rd, Scene scene, int depth) { return(thing.Surface.Reflect(pos) * TraceRay(new Ray(pos, rd), scene, depth + 1)); }
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)); }
private Intersection ClosestIntersection(Ray ray, Scene scene) { Intersection closest = new Intersection() { Dist = float.MaxValue, Thing = null, Ray = null }; for (int i = 0; i < scene.Things.Length; i++) { var thing = scene.Things[i]; Intersection intersection = thing.Intersect(ray); if (intersection != null && intersection.Dist < closest.Dist) { closest = intersection; } } return closest.Thing == null ? null : closest; }
private Color TraceRay(Ray ray, Scene scene, int depth) { var isects = Intersections(ray, scene); ISect isect = isects.FirstOrDefault(); if (isect == null) return Color.Background; return Shade(isect, scene, depth); }
private Color GetNaturalColor(SceneObject thing, Vector pos, Vector norm, Vector rd, Scene scene) { Color ret = new Color(Color.DefaultColor.R, Color.DefaultColor.G, Color.DefaultColor.B); Vector rdNormalized = Vector.Norm(rd); for (int i = 0; i < scene.Lights.Length; i++) { Light light = scene.Lights[i]; float vx = light.Pos.X - pos.X; float vy = light.Pos.Y - pos.Y; float vz = light.Pos.Z - pos.Z; float sqrLength, invLength; sqrLength = vx * vx + vy * vy + vz * vz; invLength = SceneObject.InvSqrt(sqrLength); Vector livec = new Vector(vx * invLength, vy * invLength, vz * invLength); float neatIsect = TestRay(new Ray() { Start = pos, Dir = livec }, scene); bool isInShadow = !((neatIsect == 0) || (neatIsect > vx * vx + vy * vy + vz * vz)); if (!isInShadow) { float illum = livec.X * norm.X + livec.Y * norm.Y + livec.Z * norm.Z; float specular = livec.X * rdNormalized.X + livec.Y * rdNormalized.Y + livec.Z * rdNormalized.Z; Color lcolor = illum > 0 ? Color.Times(illum, light.Color) : Color.Background; Color scolor = specular > 0 ? Color.Times((float)Math.Pow(specular, thing.Surface.Roughness), light.Color) : Color.Background; var diffuseSurfaceColor = thing.Surface.Diffuse(pos); var specularSurfaceColor = thing.Surface.Specular(pos); ret.R += diffuseSurfaceColor.R * lcolor.R + specularSurfaceColor.R * scolor.R; ret.G += diffuseSurfaceColor.G * lcolor.G + specularSurfaceColor.G * scolor.G; ret.B += diffuseSurfaceColor.B * lcolor.B + specularSurfaceColor.B * scolor.B; } } return ret; }
private Color Shade(Intersection isect, Scene scene, int depth) { var d = isect.Ray.Dir; var pos = new Vector( isect.Dist * isect.Ray.Dir.X + isect.Ray.Start.X, isect.Dist * isect.Ray.Dir.Y + isect.Ray.Start.Y, isect.Dist * isect.Ray.Dir.Z + isect.Ray.Start.Z ); var normal = isect.Thing.Normal(pos); var reflectDir = Vector.Minus(d, Vector.Times(2 * Vector.Dot(normal, d), normal)); // TODO: whats wrong with this? /*var reflectDir = new Vector( d.X - (2.0f * normal.X * d.X * normal.X), d.Y - (2.0f * normal.Y * d.Y * normal.Y), d.Z - (2.0f * normal.Z * d.Z * normal.Z) );*/ Color natColor = GetNaturalColor(isect.Thing, pos, normal, reflectDir, scene); Color ret = new Color(Color.DefaultColor.R + natColor.R,Color.DefaultColor.R + natColor.G, Color.DefaultColor.R + natColor.B); if (depth >= MaxDepth) { return new Color(ret.R + Color.Grey.R, ret.G + Color.Grey.G, ret.B + Color.Grey.B); } Color refColor = GetReflectionColor(isect.Thing, new Vector(pos.X + .001f * reflectDir.X, pos.Y + .001f * reflectDir.Y, pos.Z + .001f * reflectDir.Z), normal, reflectDir, scene, depth); return new Color(ret.R + refColor.R, ret.G + refColor.G, ret.B + refColor.B); }
private float TestRay(Ray ray, Scene scene) { float d = float.MaxValue; for (int i = 0; i < scene.Things.Length; i++) { var thing = scene.Things[i]; float intersectionDistance = thing.IntersectDistance(ray); if (intersectionDistance < d) { d = intersectionDistance; } } return d == float.MaxValue ? 0 : d; }
private void SetupScene(int width, int height) { //Vector3D bunnyCenter = loadedPlyFile.GetScanAsSpheres().GetAxisAlignedBoundingBox().Center; scene = new RayTracer.Scene(); scene.camera = new RayTracer.Camera(width, height, MathHelper.DegreesToRadians(40)); scene.background = new RayTracer.Background(new RGBA_Floats(0.5, .5, .5), 0.4); //AddBoxAndSheresBooleanTest(); //AddBoxAndBoxBooleanTest(); #if false renderCollection.Add(new BoxShape(new Vector3(), new Vector3(1, 1, 1), new SolidMaterial(new RGBA_Floats(.9, .2, .1), .01, 0.0, 2.0))); renderCollection.Add(new BoxShape(new Vector3(.5,.5,.5), new Vector3(1.5, 1.5, 1.5), new SolidMaterial(new RGBA_Floats(.9, .2, .1), .01, 0.0, 2.0))); #endif //renderCollection.Add(new CylinderShape(.25, 1, new SolidMaterial(RGBA_Floats.Cyan, 0, 0, 0))); //AddSphereAndBox(); //AddAxisMarker(); //AddCubeOfShperes(); renderCollection.Add(MakerGearXCariage()); allObjects = BoundingVolumeHierarchy.CreateNewHierachy(renderCollection); trackBallTransform = new Transform(allObjects); //allObjects = root; scene.shapes.Add(trackBallTransform); //AddAFloor(); //add two lights for better lighting effects scene.lights.Add(new Light(new Vector3(50, -10, 100), new RGBA_Floats(0.8, 0.8, 0.8))); scene.lights.Add(new Light(new Vector3(-30, -150, 50), new RGBA_Floats(0.8, 0.8, 0.8))); OrientCamera(); }
private Color TraceRay(Ray ray, Scene scene, int depth) { var i = ClosestIntersection(ray, scene); if (i == null) { return Color.Background; } return Shade(i, scene, depth); }
/// <summary> /// Renders the given scene to a bitmap, using one thread per line of pixels in the image. /// </summary> /// <param name="scene">The scene to render</param> /// <returns>A bitmap of the rendered scene.</returns> public void RenderSceneToBitmapThreaded(Scene scene, RenderBuffer renderBuffer, int width = -1, int height = -1) { if (width == -1 || height == -1) { width = renderSize.Width; height = renderSize.Height; } else { renderSize = new Size(width, height); } var before = DateTime.UtcNow; List<Task> tasks = new List<Task>(); for (int yCounter = height - 1; yCounter >= 0; yCounter--) { var y = yCounter; var task = Task.Run(() => { for (int xCounter = 0; xCounter < width; xCounter++) { var x = xCounter; var viewPortX = ((2 * x) / (float)width) - 1; var viewPortY = ((2 * y) / (float)height) - 1; var color = TraceRayAgainstScene(GetRay(viewPortX, viewPortY), scene); renderBuffer.SetColor(x, height - y - 1, ref color); } }); tasks.Add(task); } Task.WhenAll(tasks).Wait(); var after = DateTime.UtcNow; System.Diagnostics.Debug.WriteLine("Total render time: " + (after - before).TotalMilliseconds + " ms"); }
internal unsafe void Render(Scene scene) { // TODO: use more here? need to be height % processorCount == 0. //int processorCount = Environment.ProcessorCount; int processorCount = 12; ScanlineTask[] scanLineTasks = new ScanlineTask[processorCount]; int numRowsPerTask = screenHeight / processorCount; CountdownEvent countEvent = new CountdownEvent(processorCount); int pitch = numRowsPerTask * screenWidth * 4; int currentY = 0; int offset = 0; for (int i = 0; i < processorCount; i++) { scanLineTasks[i] = new ScanlineTask(i == processorCount - 1, screenWidth, numRowsPerTask, currentY, scanlines + offset, countEvent, (x, y) => TraceRay(new Ray() { Start = scene.Camera.Pos, Dir = GetPoint(x, y, scene.Camera) }, scene, 0) ); currentY += numRowsPerTask; offset += pitch; } for (int i = 0; i < processorCount; i++) { scanLineTasks[i].Start(); } //Stopwatch t = Stopwatch.StartNew(); countEvent.Wait(); //t.Stop(); //Console.WriteLine("wait " + t.ElapsedMilliseconds); }
/// <summary> /// Renders the given scene in a background thread. Uses a single thread for rendering. /// </summary> /// <param name="scene">The scene to render</param> /// <returns>A bitmap of the rendered scene.</returns> public async Task<Bitmap> RenderSceneToBitmap(Scene scene, int width = -1, int height = -1) { if (width == -1 || height == -1) { width = renderSize.Width; height = renderSize.Height; } else { renderSize = new Size(width, height); } var before = DateTime.UtcNow; Bitmap bitmap = new Bitmap(width, height); var task = Task.Run(() => { for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { var viewPortX = ((2 * x) / (float)width) - 1; var viewPortY = ((2 * y) / (float)height) - 1; var color = TraceRayAgainstScene(GetRay(viewPortX, viewPortY), scene); bitmap.SetPixel(x, height - y - 1, color); } } }); await task; var after = DateTime.UtcNow; System.Diagnostics.Debug.WriteLine("Total render time: " + (after - before).TotalMilliseconds + " ms"); return bitmap; }
internal void Render(Scene scene) { for (int y = 0; y < screenHeight; y++) { for (int x = 0; x < screenWidth; x++) { Color color = TraceRay(new Ray() { Start = scene.Camera.Pos, Dir = GetPoint(x, y, scene.Camera) }, scene, 0); setPixel(x, y, color.ToDrawingColor()); } } }
/// <summary> /// Renders the given scene, providing a callback for each individual line rendered. Uses a single background thread. /// </summary> /// <param name="width">The width of the rendered image</param> /// <param name="height">The height of the rendered image</param> /// <param name="scene">The scene to render</param> /// <param name="callback">The delegate invoked when a thread completes rendering a line</param> public void RenderSceneLines(Scene scene, int width, int height, LineFinishedHandler callback) { if (width == -1 || height == -1) { width = renderSize.Width; height = renderSize.Height; } else { renderSize = new Size(width, height); } var before = DateTime.UtcNow; Task.Run(() => // Even single-threaded method should run in the background to avoid freezing UI. { for (int y = height - 1; y >= 0; y--) { var colors = new Color[width]; for (int x = 0; x < width; x++) { var viewPortX = ((2 * x) / (float)width) - 1; var viewPortY = ((2 * y) / (float)height) - 1; var color = TraceRayAgainstScene(GetRay(viewPortX, viewPortY), scene); colors[x] = color; } callback(y, colors); } }); var after = DateTime.UtcNow; System.Diagnostics.Debug.WriteLine("Total render time: " + (after - before).TotalMilliseconds + " ms"); }
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; }
/// <summary> /// Recursive algorithm base /// </summary> /// <param name="intersection">The intersection the recursive step started from</param> /// <param name="ray">The ray, starting from the intersection</param> /// <param name="scene">The scene to trace</param> private Color CalculateRecursiveColor(Intersection intersection, Scene scene, int depth) { // Ambient light: var color = Color.Lerp(Color.Black, intersection.Color * scene.AmbientLightColor, scene.AmbientLightIntensity); foreach (Light light in scene.Lights) { var lightContribution = new Color(); var towardsLight = (light.Position - intersection.Point).Normalized(); var lightDistance = Util.Distance(intersection.Point, light.Position); // Accumulate diffuse lighting: var lightEffectiveness = Vector3.Dot(towardsLight, intersection.Normal); if (lightEffectiveness > 0.0f) { lightContribution = lightContribution + (intersection.Color * light.GetIntensityAtDistance(lightDistance) * light.Color * lightEffectiveness); } // Render shadow var shadowRay = new Ray(intersection.Point, towardsLight); Intersection shadowIntersection; if (TryCalculateIntersection(shadowRay, scene, intersection.ObjectHit, out shadowIntersection) && shadowIntersection.Distance < lightDistance) { var transparency = shadowIntersection.ObjectHit.Material.Transparency; var lightPassThrough = Util.Lerp(.25f, 1.0f, transparency); lightContribution = Color.Lerp(lightContribution, Color.Zero, 1 - lightPassThrough); } color += lightContribution; } if (depth < ReflectionDepth) { // Reflection ray var objectReflectivity = intersection.ObjectHit.Material.Reflectivity; if (objectReflectivity > 0.0f) { var reflectionRay = GetReflectionRay(intersection.Point, intersection.Normal, intersection.ImpactDirection); Intersection reflectionIntersection; if (TryCalculateIntersection(reflectionRay, scene, intersection.ObjectHit, out reflectionIntersection)) { color = Color.Lerp(color, CalculateRecursiveColor(reflectionIntersection, scene, depth + 1), objectReflectivity); } } // Refraction ray var objectRefractivity = intersection.ObjectHit.Material.Refractivity; if (objectRefractivity > 0.0f) { var refractionRay = GetRefractionRay(intersection.Point, intersection.Normal, intersection.ImpactDirection, objectRefractivity); Intersection refractionIntersection; if (TryCalculateIntersection(refractionRay, scene, intersection.ObjectHit, out refractionIntersection)) { var refractedColor = CalculateRecursiveColor(refractionIntersection, scene, depth + 1); color = Color.Lerp(color, refractedColor, 1 - (intersection.ObjectHit.Material.Opacity)); } } } color = color.Limited; return color; }
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)); }
/// <summary> /// Renders the given scene to a bitmap, using one thread per line of pixels in the image. /// </summary> /// <param name="scene">The scene to render</param> /// <returns>A bitmap of the rendered scene.</returns> public async Task<Bitmap> RenderSceneToBitmapThreaded(Scene scene, int width = -1, int height = -1) { if (width == -1 || height == -1) { width = renderSize.Width; height = renderSize.Height; } else { renderSize = new Size(width, height); } var before = DateTime.UtcNow; Bitmap bitmap = new Bitmap(width, height); List<Task> tasks = new List<Task>(); Color[,] colors = new Color[width, height]; for (int xCounter = 0; xCounter < width; xCounter++) { var x = xCounter; var task = Task.Run(() => { for (int yCounter = 0; yCounter < height; yCounter++) { var y = yCounter; var viewPortX = ((2 * x) / (float)width) - 1; var viewPortY = ((2 * y) / (float)height) - 1; var color = TraceRayAgainstScene(GetRay(viewPortX, viewPortY), scene); colors[x, y] = color; } }); tasks.Add(task); } await Task.WhenAll(tasks); // Copy all pixel data into bitmap. for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { bitmap.SetPixel(x, height - y - 1, colors[x, y]); } } var after = DateTime.UtcNow; System.Diagnostics.Debug.WriteLine("Total render time: " + (after - before).TotalMilliseconds + " ms"); return bitmap; }
private void OnSceneButtonClicked(Scene scene) { this.scene = scene; this.scene.Camera.FieldOfView = this.FieldOfView; this.scene.Camera.ReflectionDepth = this.ReflectionDepth; }