/// <summary> /// Render the scene /// </summary> /// <param name="scene">The scene to render</param> public void Render(Scene scene) { for (int y = 0; y < scene.Camera.Screen.Height; y++) { for (int x = 0; x < scene.Camera.Screen.Width; x++) { var color = this.TraceRay(new Ray() { Start = scene.Camera.Position, Direction = scene.Camera.GetRayDirection(x, y) }, scene, 0); this.withResult(x, y, color.ToDrawingColor()); } } }
/// <summary> /// /// </summary> /// <param name="element"></param> /// <param name="position"></param> /// <param name="norm"></param> /// <param name="rayDirection"></param> /// <param name="scene"></param> /// <returns></returns> private Color GetNaturalColor(SceneObject element, Vector position, Vector norm, Vector rayDirection, Scene scene) { var ret = new Color(0, 0, 0); foreach (Light light in scene.Lights) { Vector lightDirection = light.Position - position; Vector lightUnitVector = lightDirection.Normalise; double intersectionDistance = scene.TestRay(new Ray() { Start = position, Direction = lightUnitVector }); bool isInShadow = !((intersectionDistance > lightDirection.Magnitude) || (intersectionDistance == 0)); if (!isInShadow) { double angleOfIllumination = Vector.Dot(lightUnitVector, norm); Color lcolor = angleOfIllumination > 0 ? angleOfIllumination * light.Color : new Color(0, 0, 0); double specular = Vector.Dot(lightUnitVector, rayDirection.Normalise); Color scolor = specular > 0 ? Color.Times(Math.Pow(specular, element.Surface.Roughness), light.Color) : new Color(0, 0, 0); ret = ret + (element.Surface.Diffuse(position) * lcolor) + (element.Surface.Specular(position) * scolor); } } return ret; }
/// <summary> /// Get the color for the pixel /// </summary> /// <param name="intersection">The last point of intersection</param> /// <param name="scene">The scene description</param> /// <param name="depth">The current depth of recursion</param> /// <returns>The color of the pixel</returns> private Color Shade(Intersection intersection, Scene scene, int depth) { var direction = intersection.Ray.Direction; var position = (intersection.Distance * intersection.Ray.Direction) + intersection.Ray.Start; var normal = intersection.Element.Normal(position); var reflectDir = direction - (2 * normal.Dot(direction) * normal); var ret = Color.DefaultColor; ret = ret + this.GetNaturalColor(intersection.Element, position, normal, reflectDir, scene); if (depth >= MaxDepth) { return ret + new Color(.5, .5, .5); } return ret + this.GetReflectionColor(intersection.Element, position + 0.001 * reflectDir, normal, reflectDir, scene, depth); }
/// <summary> /// Trace a ray through the scene /// </summary> /// <param name="ray">The ray to test</param> /// <param name="scene">The scene description</param> /// <param name="depth">The current depth of recursion</param> /// <returns>The color of the pixel</returns> private Color TraceRay(Ray ray, Scene scene, int depth) { var intersection = scene.ClosestIntersection(ray); if (intersection == null) { return Color.Background; } return this.Shade(intersection, scene, depth); }
/// <summary> /// /// </summary> /// <param name="element"></param> /// <param name="position"></param> /// <param name="norm"></param> /// <param name="rayDirection"></param> /// <param name="scene"></param> /// <param name="depth"></param> /// <returns></returns> private Color GetReflectionColor(SceneObject element, Vector position, Vector norm, Vector rayDirection, Scene scene, int depth) { return element.Surface.Reflectiveness(position) * this.TraceRay(new Ray() { Start = position, Direction = rayDirection }, scene, depth + 1); }
/// <summary> /// Application main method. /// </summary> /// <param name="args">Command line arguments</param> static void Main(string[] args) { CommandLineArguments cArgs = new CommandLineArguments(args); Configuration config = new Configuration(); var something = new Driven.Metrics.DrivenMetrics.Factory().Create( cArgs.Assemblies.ToArray(), config.Container.ResolveAll<IMetricCalculator>() , "TestReport", config.Container.Resolve<IReport>()); something.RunAllMetricsAndGenerateReport(); CodeStadt.Core.DrivenMetrics.Reporting.ResultOutput results = something.Report.As<Core.DrivenMetrics.Reporting.ResultOutput>(); if (results != null) { results.Results.ForEach(x => { Console.WriteLine("Metric: {0}".Formatted(x.Name)); Console.WriteLine(""); x.ClassResults.ForEach(y => { Console.WriteLine(" Class: {0}".Formatted(y.Name)); Console.WriteLine(""); y.MethodResults.ForEach(z => { Console.WriteLine(" Method: {0} \n\r Result: {1}".Formatted(z.Name, z.Result)); Console.WriteLine(""); }); }); }); } // Console.ReadLine(); Console.WriteLine("Going to try and draw an image :-)"); // Lets ray trace something string raytraceFileName = "raytrace.jpg"; if (File.Exists(raytraceFileName)) File.Delete(raytraceFileName); int width = 600; int height = 600; var bitmap = new System.Drawing.Bitmap(width, height); RayTracer rayTracer = new RayTracer((int x, int y, System.Drawing.Color color) => { bitmap.SetPixel(x, y, color); }); var screen = new Screen(width, height); var MyScene = new Scene() { Elements = new List<SceneObject>() { new Plane() { Norm = new Vector(0, 1, 0), Point = new Vector(0, -0.5, 0), Surface = Surfaces.CheckerBoard } //,new Polygon(new List<Vector>(){ new Vector(0,0,0), new Vector(0,1,0), new Vector(1,1,0), new Vector(1,0,0)}, new Vector(0,0,1)) //{ // Surface = Surfaces.White //} //,new Polygon(new List<Vector>(){ new Vector(0,0,0), new Vector(0,1,0), new Vector(0,1,1), new Vector(0,0,1)}, new Vector(1,0,0)) //{ // Surface = Surfaces.White //} //,new Polygon(new List<Vector>(){ new Vector(0,0,0), new Vector(0,0,1), new Vector(1,0,1), new Vector(1,0,0)}, new Vector(0,1,0)) //{ // Surface = Surfaces.White //} //,new Sphere() { // Center = new Vector(0,1,0), // Radius = 1, // Surface = Surfaces.Shiny //}, //new Sphere() { // Center = new Vector(-1,.5,1.5), // Radius = .5, // Surface = Surfaces.Shiny //} // FOR TESTING //,new Line(){ // Point = new Vector(0,0,0), // Direction = new Vector(1,0,0), // Surface = Surfaces.Green //} //,new Line(){ // Point = new Vector(0,0,0), // Direction = new Vector(0,1,0), // Surface = Surfaces.Green //} //,new Line(){ // Point = new Vector(0,0,0), // Direction = new Vector(0,0,1), // Surface = Surfaces.Green //} //,new Line(){ // Point = new Vector(1,0,0), // Direction = new Vector(0,0,1), // Surface = Surfaces.Green //} }, Lights = new List<Light>() { //new Light() { // Position = new Vector(-2,2.5,0), // Color = new Color(.49,.07,.07) //}, //new Light() { // Position = new Vector(1.5,2.5,1.5), // Color = new Color(.07,.07,.49) //}, //new Light() { // Position = new Vector(1.5,2.5,-1.5), // Color = new Color(.07,.49,.071) //}, //new Light() { // Position = new Vector(8,5,-6), // Color = new Color(1,0,0) //}, new Light() { Position = new Vector(8,4,8), Color = new Color(1,1,1) }}, Camera = new Camera(new Vector(6, 3, 6), new Vector(0, 0, 0), screen) //Camera = new Camera(new Vector(-3, 2, -4), new Vector(-1,0.5,0)) }; MyScene.AddModel(new Cube(1, new Vector(0, 0, 0))); rayTracer.Render(MyScene); bitmap.Save(raytraceFileName); }
/// <summary> /// Get the color of an object at a point of intersection by tracing back to the light sources. /// This creates shadows and adds color if the lights are off-white. /// </summary> /// <param name="element">The object being intersected</param> /// <param name="position">The point of intersection on the object</param> /// <param name="norm">The normal at the point of intersection</param> /// <param name="reflectDirection">The direction of the light reflection off of the surface</param> /// <param name="scene">The scene description</param> /// <returns>The color of the object due to the scenes lighting</returns> private Color GetNaturalColor(SceneObject element, Vector position, Vector norm, Vector reflectDirection, Scene scene) { var ret = new Color(0, 0, 0); foreach (Light light in scene.Lights) { // Direction from the point of intersction to the light source Vector lightDirection = light.Position - position; Vector lightUnitVector = lightDirection.Normalise; // Perform an intersection test in the direction of the light source to determine if we are in a shadow double intersectionDistance = scene.TestRay(new Ray() { Start = position, Direction = lightUnitVector }); bool isInShadow = !((intersectionDistance > lightDirection.Magnitude) || (intersectionDistance == 0)); if (!isInShadow) { // Check the light is shining on the front of the object. Use the angle to determine // the brightness of the light. double angleOfIllumination = Vector.Dot(lightUnitVector, norm); Color lightColor = angleOfIllumination > 0 ? angleOfIllumination * light.Color : new Color(0, 0, 0); // Determine of the light is in the direction of a reflection, leading to a specular effect double specular = Vector.Dot(lightUnitVector, reflectDirection.Normalise); // Calculate color of object based on surface qualities Color specularColor = specular > 0 ? Math.Pow(specular, element.Surface.Roughness) * light.Color : new Color(0, 0, 0); ret = ret + (element.Surface.Diffuse(position) * lightColor) + (element.Surface.Specular(position) * specularColor); } } return ret; }
/// <summary> /// Get the color of an object at a point of intersection /// </summary> /// <param name="intersection">The last point of intersection</param> /// <param name="scene">The scene description</param> /// <param name="depth">The current depth of recursion</param> /// <returns>The color of the pixel</returns> private Color Shade(Intersection intersection, Scene scene, int depth) { // Use Fresnel's law to calculate the direction of the reflected light ray // R = 2(N.L)*N - L // R = reflection direction // N = Normal at point of intersection // L = -I // I = direction of ray var direction = -1 * intersection.Ray.Direction; var position = (intersection.Distance * intersection.Ray.Direction) + intersection.Ray.Start; var normal = intersection.Element.Normal(position); var reflectDir = (2 * normal.Dot(direction) * normal) - direction; var ret = Color.DefaultColor; ret = ret + this.GetNaturalColor(intersection.Element, position, normal, reflectDir, scene); if (depth >= MaxDepth) { return ret + new Color(.5, .5, .5); } // The color at this point is equal to the color of the object + any color reflecting on to it return ret + this.GetReflectionColor(intersection.Element, position + 0.001 * reflectDir, normal, reflectDir, scene, depth); }
/// <summary> /// Calculate the color being reflected at a point of intersection /// </summary> /// <param name="element">The object being intersected</param> /// <param name="position">The position on the objects surface</param> /// <param name="norm">The normal at the point of intersection</param> /// <param name="reflectDirection">The direction of the reflected ray</param> /// <param name="scene">The scene description</param> /// <param name="depth">The current depth of recursion</param> /// <returns>The color being reflected</returns> private Color GetReflectionColor(SceneObject element, Vector position, Vector norm, Vector reflectDirection, Scene scene, int depth) { // Only calculate reflected color if the surface is reflective var reflectiveness = element.Surface.Reflectiveness(position); if (reflectiveness > 0) { return reflectiveness * this.TraceRay(new Ray() { Start = position, Direction = reflectDirection }, scene, depth + 1); } return new Color(0, 0, 0); }