//test public static Bitmap newImage(int width, int height, List<Sphere> l_sphere) { Bitmap image = new Bitmap(width, height); l_sphere.Sort(); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { Ray r = new Ray(new Point(x, y, -2000), new Point(0f, 0f, 1), 1); Color c = Color.White; float dis = -r.Position.z; Sphere currentSphere = r.Intersection(l_sphere, ref dis); image.SetPixel(x, y, Color.Black); Point inter = r.Position + dis * r.Direction; Point normal = inter - new Point(currentSphere.x, currentSphere.y, currentSphere.z); float temp = normal * normal; if (temp != 0 && dis != -r.Position.z) { temp = 1.0f / (float)Math.Sqrt(temp); normal = temp * normal; if(normal.z == -r.Direction.z) Console.WriteLine("normal"); image.SetPixel(x, y, Color.FromArgb(((int)(currentSphere.color.R * (currentSphere.z - inter.z)) / currentSphere.rayon), (int)((currentSphere.color.G * (currentSphere.z - inter.z)) / currentSphere.rayon), (int)((currentSphere.color.B * (currentSphere.z - inter.z)) / currentSphere.rayon))); } } } return image; }
public double? Intersect(Ray ray) { var dist = ray.Start - Position; var a = Vector3D.DotProduct(ray.Direction, ray.Direction); var b = 2*Vector3D.DotProduct(dist, ray.Direction); var c = Vector3D.DotProduct(dist, dist) - (Radius * Radius); var discriminant = b*b - 4*a*c; if(discriminant < 0) return null; var t1 = (-b + Math.Sqrt(discriminant))/2*a; var t2 = (-b - Math.Sqrt(discriminant))/2*a; if (t1 < 0.5 && t2 < 0.5) return null; if (t1 < 0.5) t1 = Double.MaxValue; if (t2 < 0.5) t2 = Double.MaxValue; return Math.Min(t1, t2); }
public Bitmap Render() { Bitmap bitmap = new Bitmap(Camera.Width, Camera.Height); if (Objects3D.Count < 1) return bitmap; for (int x = 0; x < Camera.Width; x++) for (int y = 0; y < Camera.Height; y++) { Ray ray = new Ray(new Vector3D(x, y, 0), new Vector3D(x - Camera.D.X, y - Camera.D.Y, -Camera.D.Z), 1); Vector3D intersection = null; Object3D selectedObject = null; foreach (var object3D in Objects3D) { Vector3D objectIntersection = SelectIntersection(object3D.GetIntersections(ray)); if (objectIntersection == null) continue; if (selectedObject == null || objectIntersection.Z < intersection.Z) { selectedObject = object3D; intersection = objectIntersection; } } if (intersection != null) { double cosAngle = Math.Abs(ReflectedRayAngleCos(ray, selectedObject.GetNormal(intersection))); cosAngle = Math.Pow(cosAngle, LightIntensity + 1); int r = (int) (selectedObject.Color.R*cosAngle*ray.Intensity); int g = (int) (selectedObject.Color.G*cosAngle*ray.Intensity); int b = (int) (selectedObject.Color.B*cosAngle*ray.Intensity); if (Grain && x%2 == 0 && y%2 == 0) { r += 20; g += 20; b += 20; } r = r < 0 ? 0 : r > 255 ? 255 : r; g = g < 0 ? 0 : g > 255 ? 255 : g; b = b < 0 ? 0 : b > 255 ? 255 : b; bitmap.SetPixel(x, y, Color.FromArgb(r, g, b)); } } return bitmap; }
public Colour CalculateLighting(Intersection intersection, Ray ray, int recursionDepth) { const int maxRecursionDepth = 10; //todo if (recursionDepth > maxRecursionDepth || !ray.IsColourSignificant) { return new Colour(0,0,0); } throw new NotImplementedException(); }
public override double find_intersection(Ray ray) { double a = ray.direction.dot(normal); if (a == 0) { return -1; } double b = normal.dot((ray.origin - (normal * distance))); double n = -1 * b / a; return n; }
public override Intersection Intersect(Ray ray) { float denom = Norm.X * ray.Dir.X + Norm.Y * ray.Dir.Y + Norm.Z * ray.Dir.Z; if (denom > 0) return null; return new Intersection() { Thing = this, Ray = ray, Dist = (Norm.X * ray.Start.X + Norm.Y * ray.Start.Y + Norm.Z * ray.Start.Z + Offset) / (-denom) }; }
private RealColor? GetColorForRay(Ray viewRay, int iteration = 1) { var materialColor = new RealColor(); var intersection = Scene.Objects .Select(o => new {Obj = o, Dist = o.Intersect(viewRay)}) .Where(o => o.Dist != null) .OrderBy(f => f.Dist) .FirstOrDefault(); if (intersection != null) { var start = viewRay.Start + (intersection.Dist.Value*viewRay.Direction); var normal = start - intersection.Obj.Position; normal.Normalize(); foreach (var light in Scene.Lights) { var lightRay = Ray.FromStartAndEndPoints(start, light.Position); if (Scene.Objects.Any(o => o.Intersect(lightRay) != null)) continue; if (Vector3D.DotProduct(normal, lightRay.Direction) < 0) continue; var lambert = Vector3D.DotProduct(lightRay.Direction, normal); materialColor += lambert * light.Color * intersection.Obj.Material.Diffuse; } if (iteration > 10 || intersection.Obj.Material.ReflectionCoefficient <= 0) return materialColor; var reflectionAngle = 2.0f * (Vector3D.DotProduct(viewRay.Direction, normal)); var reflectionRay = new Ray(start, viewRay.Direction - reflectionAngle * normal); var reflectedColor = GetColorForRay(reflectionRay, iteration + 1); if (reflectedColor == null) return materialColor; return materialColor + reflectedColor*intersection.Obj.Material.ReflectionCoefficient; } //return null; return new RealColor(Background); }
public override float IntersectDistance(Ray ray) { float denom = Norm.X * ray.Dir.X + Norm.Y * ray.Dir.Y + Norm.Z * ray.Dir.Z; if (denom > 0) return float.MaxValue; // TODO: is correct? this is never called. return (Norm.X * ray.Start.X + Norm.Y * ray.Start.Y + Norm.Z * ray.Start.Z + Offset); /*return new Intersection() { Thing = this, Ray = ray, Dist = (Norm.X * ray.Start.X + Norm.Y * ray.Start.Y + Norm.Z * ray.Start.Z + Offset) / (-denom) };*/ }
/* Taken from: https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm Haven't taken the time to understand it. Hope it works. */ public override bool Intersects(Ray ray, ref Vector3D intPoint) { Vector3D e1, e2; //Edge1, Edge2 Vector3D P, Q, T; double det, inv_det, u, v; double t; //Find vectors for two edges sharing V1 e1 = Vector3D.Subtract(_p2, _p1); e2 = Vector3D.Subtract(_p3, _p1); //Begin calculating determinant - also used to calculate u parameter P = Vector3D.CrossProduct(ray.Direction, e2); //if determinant is near zero, ray lies in plane of triangle det = Vector3D.DotProduct(e1, P); //NOT CULLING if (det == 0) return false; inv_det = 1.0d / det; //calculate distance from V1 to ray origin T = Vector3D.Subtract(ray.Source, _p1); //Calculate u parameter and test bound u = Vector3D.DotProduct(T, P) * inv_det; //The intersection lies outside of the triangle if (u < 0.0d || u > 1.0d) return false; //Prepare to test v parameter Q = Vector3D.CrossProduct(T, e1); //Calculate V parameter and test bound v = Vector3D.DotProduct(ray.Direction, Q) * inv_det; //The intersection lies outside of the triangle if (v < 0.0d || u + v > 1.0d) return false; t = Vector3D.DotProduct(e2, Q) * inv_det; if (t > 0) { //ray intersection intPoint = ray.Source + ray.Direction * t; return true; } // No hit, no win return false; }
override public bool Intersects(Ray ray, ref Vector3D intPoint) { // Intersection formula from http://www.cl.cam.ac.uk/teaching/1999/AGraphHCI/SMAG/node2.html // t = (N * ( Q - E )) / (E - D) Vector3D E = ray.Source; Vector3D D = ray.Direction; Vector3D NegN = -m_Normal; if (Vector3D.DotProduct(m_Normal, D) != 0) { double t = (Vector3D.DotProduct(m_Normal, (Vector3D.Subtract(m_Point, E)))) / (Vector3D.DotProduct(m_Normal, D)); if (t >= 0) { intPoint = E + (D * t); return true; } } return false; }
public override double find_intersection(Ray ray) { double b = (2 * (ray.origin.x - center.x) * ray.direction.x) + (2 * (ray.origin.y - center.y) * ray.direction.y) + (2 * (ray.origin.z - center.z) * ray.direction.z); double c = Math.Pow((ray.origin.x - center.x), 2) + Math.Pow((ray.origin.y - center.y), 2) + Math.Pow((ray.origin.z - center.z), 2) - Math.Pow(radius, 2); double discriminant = Math.Pow(b, 2) - 4 * c; if (discriminant > 0) { double root = ((-1 * b - Math.Sqrt(discriminant)) / 2); if (root > 0) { return root; } else { return ((-b + Math.Sqrt(discriminant)) / 2); } } else { return -1; } }
private void GetColor(HitInfo info, Light lt, ColorAccumulator ca, int count) { Vector3D lightNormal = info.hitPoint - lt.Location; lightNormal.Normalize(); if (InShadow(info, lt, lightNormal)) { return; } double lambert = Vector3D.DotProduct(lightNormal, info.normal); if (lambert <= 0) { int r, g, b; r = b = g = 0; int r2 = 0; int g2 = 0; int b2 = 0; info.hitObj.GetColor(info.hitPoint, ref r, ref g, ref b); if (info.hitObj.Material != null && info.hitObj.Material is SolidColor) { double phongTerm = Math.Pow(lambert, 20) * (info.hitObj.Material as SolidColor).Phong * 2; r2 = (int)(lt.Color.R * phongTerm); g2 = (int)(lt.Color.G * phongTerm); b2 = (int)(lt.Color.B * phongTerm); double reflet = 2.0f * (Vector3D.DotProduct(info.normal, info.ray.Direction)); Vector3D dir = info.ray.Direction - info.normal * reflet; Ray reflect = new Ray(info.hitPoint + dir, dir); ColorAccumulator rca = CastRay(reflect, ++count); if (rca != null) { ca.accumR = ca.accumR + rca.accumR; ca.accumG = ca.accumG + rca.accumG; ca.accumB = ca.accumB + rca.accumB; } } ca.accumR += (int)((lt.Color.R * r * -lambert) / 255) + r2; ca.accumG += (int)((lt.Color.G * g * -lambert) / 255) + g2; ca.accumB += (int)((lt.Color.B * b * -lambert) / 255) + b2; } }
/// <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 IEnumerable<Intersection> Intersect(Ray r) { return from thing in Things select thing.Intersect(r); }
public override float IntersectDistance(Ray ray) { float eox = Center.X - ray.Start.X; float eoy = Center.Y - ray.Start.Y; float eoz = Center.Z - ray.Start.Z; float v = eox * ray.Dir.X + eoy * ray.Dir.Y + eoz * ray.Dir.Z; if (v < 0) { return float.MaxValue; } float disc = Radius2 - ((eox * eox + eoy * eoy + eoz * eoz) - v * v); if (disc < 0) { return float.MaxValue; } return v - disc; }
/// <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> /// Distance squared or float.MaxValue if no hit. /// </summary> /// <param name="ray"></param> /// <returns></returns> public abstract float IntersectDistance(Ray ray);
public override Intersection Intersect(Ray ray) { float eox = Center.X - ray.Start.X; float eoy = Center.Y - ray.Start.Y; float eoz = Center.Z - ray.Start.Z; float v = eox * ray.Dir.X + eoy * ray.Dir.Y + eoz * ray.Dir.Z; if (v < 0) { return null; } float disc = Radius2 - ((eox * eox + eoy * eoy + eoz * eoz) - v * v); if (disc < 0) { return null; } float dist = (v - Sqrt(disc)); return new Intersection() { Thing = this, Ray = ray, Dist = dist }; }
public static Bitmap run_raytracer(LinkedList<Object> objects, LinkedList<LightSource> lights, Camera c, Size size) { Console.WriteLine("Daniel Bolink's Ray Tracer"); //image size int width = size.Width; int height = size.Height; // Create Camera //Camera c = new Camera(new Position(0, 0, -10), new Position(0,0,0)); //create colors Color BGColor = new Color(0, 0, 0); //Color BLACK = new Color(0, 0, 0); //Color WHITE = new Color(255, 255, 255); //Color GREEN = new Color(0, 255, 0); //Color YELLOW = new Color(255, 255, 0); //Color ORANGE = new Color(255, 0, 255); //Color RED = new Color(200, 0, 0); //Color BLUE = new Color(0, 0, 255); //create Objects in frame //red plane at below 10 units //Object p1 = new Plane(new Vector(0, 1, 0), -1, RED); //blue sphere 10 units ahead radis 0.5 //Object s1 = new Sphere(1, new Position(0, 0, 0), BLACK); //Object s2 = new Sphere(1, new Position(2, 0, 0), ORANGE); //add Objects to list //objects.AddLast(s1); //objects.AddLast(p1); //objects.AddLast(s2); //add Light Sources //LightSource l1 = new LightSource(new Position(20, 5, 10), WHITE); //LightSource l2 = new LightSource(new Position(-20, 5, 10), BLUE); //add lightsources to linked list //lights.AddLast(l1); //lights.AddLast(l2); // Create Pixels Color[,] pixels = new Color[width, height]; //ray tracing algorithm for(int x = 0; x < width; x++) { for (int y = 0; y<height; y++) { double xamnt = (x + 0.5) / width; double yamnt = ((height - y) + 0.5) / height; Vector ray_direction = (c.direction + (c.right * (xamnt-0.5) + (c.down * (yamnt - 0.5)))).normalize(); Ray ray = new Ray(c.position, ray_direction); LinkedList<ObjectPair> intersection_objects = new LinkedList<ObjectPair>(); foreach(Object o in objects) { double val = o.find_intersection(ray); if (val > 0) { intersection_objects.AddLast(new ObjectPair(o, val)); } //Console.WriteLine(val); } //Console.WriteLine(intersection_objects.Count); if(intersection_objects.Count == 0) { pixels[x, y] = BGColor; } else { ObjectPair winner = new ObjectPair(null, -1); foreach (ObjectPair o in intersection_objects) { if (winner.val == -1) { winner = o; } else if(winner.val > o.val && o.val >= 0) { winner = o; } } if(winner.val > 0) { Color final_color = winner.obj.color; Position intersection_point = ray.origin + (ray.direction * (winner.val * 0.999)); foreach (LightSource l in lights) { Boolean shadowed = false; Vector light_direction = new Vector(l.origin, intersection_point).normalize(); //Vector light_direction = new Vector(intersection_point, l.origin).normalize(); Ray shadow_ray = new Ray(intersection_point, light_direction); foreach(Object o in objects) { double obj_intersection = o.find_intersection(shadow_ray); if(obj_intersection > 0) { shadowed = true; break; } } if (!shadowed) { Vector Winner_obj_normal = winner.obj.getNormalAt(intersection_point); double diffuse_coeffient = (shadow_ray.direction.normalize().dot(Winner_obj_normal)); Vector reflection_direction = shadow_ray.direction - (2 * (shadow_ray.direction.dot(Winner_obj_normal)/Winner_obj_normal.magnitude()*Winner_obj_normal)); Ray reflection = new Ray(intersection_point, reflection_direction); double specular_coefficient = reflection.direction.dot(ray.direction); final_color += l.color * 0.15; if(diffuse_coeffient > 0) { final_color += l.color * diffuse_coeffient * 0.15; } if(specular_coefficient > 0) { final_color += l.color * Math.Pow(specular_coefficient, 1000); } } } pixels[x, y] = final_color.clip(); } else { pixels[x, y] = BGColor; } } } } //create image Bitmap bmp = CreateImg(pixels); //Process photoViewer = Process.Start("RayTracer.png"); //prompt for exit //Console.WriteLine("Press any key to exit."); //Console.ReadKey(); return bmp; }
public abstract Intersection Intersect(Ray ray);
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); }
public static double ReflectedRayAngleCos(Ray ray, Vector3D intersectionNormale) { double cos = Vector3D.Scalar(ray.Direction, intersectionNormale)/(ray.Direction.Norm()*intersectionNormale.Norm()); return Math.Pow(-Math.Log(cos + 1), 2); }
/// <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 ColorAccumulator CastRay(Ray ray, int count) { if (count > RayDepth) { return null; } ColorAccumulator ca = null; HitInfo info = FindHitObject(ray); if (info.hitObj != null) { ca = CalculateLighting(info, count); ca.Clamp(); } else { ca = new ColorAccumulator(BackColor.R, BackColor.G, BackColor.B); } return ca; }
public virtual double find_intersection(Ray ray) { Console.WriteLine("This shouldnt be here"); return 0; }
private HitInfo FindHitObject(Ray ray, Geometry originator, HitMode mode) { Vector3D intPoint = new Vector3D(double.MaxValue, double.MaxValue, double.MaxValue); HitInfo info = new HitInfo(null, intPoint, ray); double dist = double.MaxValue; foreach (Geometry geom in Scene.Geoms) { if (geom != originator && geom.Intersects(ray, ref intPoint)) { double distToObj = Vector3D.Subtract(ray.Source, intPoint).Length; if (distToObj < dist) { info.hitPoint = intPoint; dist = distToObj; info.hitObj = geom; if (mode == HitMode.Any) { break; } } } } return info; }
private HitInfo FindHitObject(Ray ray) => FindHitObject(ray, null, HitMode.Closest);
public virtual List<Vector3D> GetIntersections(Ray ray) { return null; }
private bool InShadow(HitInfo info, Light lt, Vector3D lightNormal) { Ray shadowRay = new Ray(lt.Location, lightNormal); HitInfo shadinfo = FindHitObject(shadowRay, info.hitObj, HitMode.Closest); if (shadinfo.hitObj != null && Vector3D.Subtract(lt.Location, info.hitPoint).Length > Vector3D.Subtract(lt.Location, shadinfo.hitPoint).Length) { return true; } return false; }
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; } }
public HitInfo(Geometry hitObj, Vector3D hitPoint, Ray ray) { this.hitObj = hitObj; this.hitPoint = hitPoint; this.ray = ray; }
/// <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; } }
public Color CaculateColour(Ray ray, Scene scene) { throw new NotImplementedException(); }