public static Color Trace(Scene scene, Ray r, int max) { IntersectionResult tr = NearestIntersection(scene, r); if (tr.triangle != null) { //v1: //return scene.Materials[tr.MaterialIndex].Color; // v2: Color c = new Color(0, 0, 0, 1); // contribuição luz ambiente: foreach (var light in scene.Lights) { c += light.Color * scene.Materials[tr.triangle.MaterialIndex].Color * scene.Materials[tr.triangle.MaterialIndex].Ambient; } // contribuição luz difusa foreach (var light in scene.Lights) { Vector3 l = light.Position - tr.point; float dist = Vector3.Length(l); l = Vector3.Normalize(l); float cost = tr.triangle.Normal.Dot(l); Ray s = new Ray() { origin = tr.point, direction = l }; if (IsExposedToLight(scene, s, dist) && cost > 0) c = c + light.Color * scene.Materials[tr.triangle.MaterialIndex].Color * scene.Materials[tr.triangle.MaterialIndex].Diffuse * cost; } // reflection, material reflective? if (scene.Materials[tr.triangle.MaterialIndex].Reflection > 0.0f) { float c1 = -tr.triangle.Normal.Dot(r.direction); Vector3 rl = Vector3.Normalize(r.direction + (tr.triangle.Normal * 2.0f * c1)); Ray refl = new Ray() { origin = tr.point, direction = rl }; c += (max > 0 ? Ray.Trace(scene, refl, --max) : new Color(0, 0, 0)) * scene.Materials[tr.triangle.MaterialIndex].Reflection * scene.Materials[tr.triangle.MaterialIndex].Color; } else if (scene.Materials[tr.triangle.MaterialIndex].RefractionCoef > 0.0f) { Vector3 n1 = new Vector3(); double m1, m2; if (RayEnters(r.direction, tr.triangle.Normal)) { n1 = tr.triangle.Normal; m1 = 1.0f; // air m2 = scene.Materials[tr.triangle.MaterialIndex].RefractionIndex; } else { n1 = tr.triangle.Normal * -1; m1 = scene.Materials[tr.triangle.MaterialIndex].RefractionIndex; m2 = 1.0f; } double c1 = -(n1).Dot(r.direction); double m = m1 / m2; double c2 = Math.Sqrt(1 - m * m * (1 - c1 * c1)); Vector3 rr = Vector3.Normalize((r.direction * (float)m) + n1 * (float)(m * c1 - c2)); Ray refr = new Ray() { origin = tr.point, direction = rr }; c += (max > 0 ? Ray.Trace(scene, refr, --max) : new Color(0, 0, 0)) * scene.Materials[tr.triangle.MaterialIndex].RefractionCoef * scene.Materials[tr.triangle.MaterialIndex].Color; } return c; } return scene.Image.Color; }
private static IntersectionResult NearestIntersection(Scene scene, Ray r) { Vector3 intersectionPoint = new Vector3(0, 0, 0); double tmin = double.MaxValue; Triangle nearestTriangle = null; foreach (Solid s in scene.Solids) { foreach (Triangle tr in s.Triangles) { float t = (float)Intersection(r, tr); if (t > 0 && t < tmin) { tmin = t; nearestTriangle = tr; intersectionPoint = r.origin + (r.direction * t); // p(t) } } } return new IntersectionResult() { triangle = nearestTriangle, point = intersectionPoint }; }
private static double Intersection(Ray r, Triangle tr) { double[,] a = new double[3, 3] { {tr.Points[0].X - tr.Points[1].X, tr.Points[0].X - tr.Points[2].X, r.direction.X}, {tr.Points[0].Y - tr.Points[1].Y, tr.Points[0].Y - tr.Points[2].Y, r.direction.Y}, {tr.Points[0].Z - tr.Points[1].Z, tr.Points[0].Z - tr.Points[2].Z, r.direction.Z}}; double detA = Determinant(a); double[,] b = new double[3, 3] { {tr.Points[0].X - r.origin.X, tr.Points[0].X - tr.Points[2].X, r.direction.X}, {tr.Points[0].Y - r.origin.Y, tr.Points[0].Y - tr.Points[2].Y, r.direction.Y}, {tr.Points[0].Z - r.origin.Z, tr.Points[0].Z - tr.Points[2].Z, r.direction.Z}}; double detB = Determinant(b) / detA; if (detB < 0) return -1; double[,] y = new double[3, 3] { {tr.Points[0].X - tr.Points[1].X, tr.Points[0].X - r.origin.X, r.direction.X}, {tr.Points[0].Y - tr.Points[1].Y, tr.Points[0].Y - r.origin.Y, r.direction.Y}, {tr.Points[0].Z - tr.Points[1].Z, tr.Points[0].Z - r.origin.Z, r.direction.Z}}; double detY = Determinant(y) / detA; if (detY < 0) return -1; if (detB + detY >= 1) return -1; double[,] t = new double[3, 3] { {tr.Points[0].X - tr.Points[1].X, tr.Points[0].X - tr.Points[2].X, tr.Points[0].X - r.origin.X}, {tr.Points[0].Y - tr.Points[1].Y, tr.Points[0].Y - tr.Points[2].Y, tr.Points[0].Y - r.origin.Y}, {tr.Points[0].Z - tr.Points[1].Z, tr.Points[0].Z - tr.Points[2].Z, tr.Points[0].Z - r.origin.Z}}; double detT = Determinant(t) / detA; if (detT < EPSILON) return -1; return detT; }
private static bool IsExposedToLight(Scene scene, Ray r, float dist) { // if (intersection => light : triangles) return true; // basta encontrar 1 (mas dentro da largura entre a luz e o ponto) foreach (Solid s in scene.Solids) { foreach (Triangle tr in s.Triangles) { float t = (float)Intersection(r, tr); if (t > 0 && t < dist) return false; } } return true; }
void bgWorker_DoWork(object sender, DoWorkEventArgs e) { if (myScene != null) { stopwatch.Reset(); stopwatch.Start(); try { Bitmap bmp = new Bitmap(myScene.Image.Horizontal, myScene.Image.Vertical); System.Drawing.Color[,] bmData = new System.Drawing.Color[myScene.Image.Horizontal, myScene.Image.Vertical]; //byte[] colorArray = new byte[myScene.Images[0].Horizontal * myScene.Images[0].Vertical]; float height = 2 * myScene.Camera.Distance * (float)Math.Tan((myScene.Camera.FieldOfView * (Math.PI / 180.0f)) / 2); float width = myScene.Image.Horizontal / myScene.Image.Vertical * height; float pixelSize = width / myScene.Image.Horizontal; Vector3 origin = new Vector3(myScene.Camera.Position.X, myScene.Camera.Position.Y, myScene.Camera.Distance); int c = 0; Parallel.ForEach(Partitioner.Create(0, myScene.Image.Horizontal), range => { //Console.WriteLine("BLOCK PARALLEL"); for (int i = range.Item1; i < range.Item2; i++) { for (int y = 0; y < myScene.Image.Vertical; y++) //Parallel.For(0, myScene.Images[0].Vertical, y => { float px = pixelSize * (i + 0.5f) - (width / 2); float py = pixelSize * (y + 0.5f) - (height / 2); Vector3 df = new Vector3(px, py, 0) - origin; Vector3 direction = Vector3.Normalize(df); Ray r = new Ray() { Direction = direction, Origin = origin }; Enox.Framework.Color color = Ray.Trace(myScene, r, myScene.RecursionDepth); float red = (color.R > 1 ? 1 : color.R); float green = (color.G > 1 ? 1 : color.G); float blue = (color.B > 1 ? 1 : color.B); //lock (mutex) //{ // bmp.SetPixel(i, y, // System.Drawing.Color.FromArgb((int)(255), (int)(red * 255), // (int)(green * 255), (int)(blue * 255))); //} bmData[i, y] = System.Drawing.Color.FromArgb((int)(255), (int)(red * 255), (int)(green * 255), (int)(blue * 255)); c++; bgWorker.ReportProgress(c * 100 / (myScene.Image.Horizontal * myScene.Image.Vertical)); } } // }); }); // store pixel data on bitmap: for (int i = 0; i < myScene.Image.Horizontal; i++) { for (int y = 0; y < myScene.Image.Vertical; y++) { bmp.SetPixel(i, y, bmData[i, y]); } } // old way (without parallelism) //for (int i = 0; i < myScene.Images[0].Horizontal; i++) //{ // for (int y = 0; y < myScene.Images[0].Vertical; y++) // { // float px = pixelSize * (i + 0.5f) - (width / 2); // float py = pixelSize * (y + 0.5f) - (height / 2); // Vector3 df = new Vector3(px, py, 0) - origin; // Vector3 direction = Vector3.Normalize(df); // Ray r = new Ray() // { // Direction = direction, // Origin = origin // }; // Enox.Framework.Color color = Ray.Trace(myScene, r, 2); // float red = (color.R > 1 ? 1 : color.R); // float green = (color.G > 1 ? 1 : color.G); // float blue = (color.B > 1 ? 1 : color.B); // bmp.SetPixel(i, y, // System.Drawing.Color.FromArgb((int)(255), (int)(red * 255), // (int)(green * 255), (int)(blue * 255))); // } //} //for (int i = 0; i < 3; i++) //{ // for (int y = 0; y < 3; y++) // { // Task t = new Task(() => // { // int myi = i; // int myy = y; // Console.WriteLine(myi + "**" + myy); // float rangeX = divx * myi + divx; // for (int l = divx * myi; l < rangeX; l++) // { // float rangeY = divy * myy + divy; // for (int c = divy * myy; c < rangeY; c++) // { // float px = pixelSize * (myi + 0.5f) - (width / 2); // float py = pixelSize * (myy + 0.5f) - (height / 2); // Vector3 df = new Vector3(px, py, 0) - origin; // Vector3 direction = Vector3.Normalize(df); // Ray r = new Ray() // { // Direction = direction, // Origin = origin // }; // Enox.Framework.Color color = Ray.Trace(myScene, r, 2); // float red = (color.R > 1 ? 1 : color.R); // float green = (color.G > 1 ? 1 : color.G); // float blue = (color.B > 1 ? 1 : color.B); // lock (mutex) // { // //try // //{ // bmp.SetPixel(l, c, // System.Drawing.Color.FromArgb((int)(255), (int)(red * 255), // (int)(green * 255), (int)(blue * 255))); // //} // //catch (Exception ex) // //{ // // Console.WriteLine(ex.ToString()); // //} // } // } // } // }); // t.Start(); // tasks.Add(t); // } //} //for (int i = 0; i < myScene.Images[0].Horizontal; i++) //{ // for (int y = 0; y < myScene.Images[0].Vertical; y++) // { // construir raio(i, j) // Color c = RayTrace(r); // pixel[i, j] = c; // origin camera = (0, 0, d); d = 3 // direçao = normalize((px, py, pz) - (origin)) // px = pixelSize * (i + 0.5f) - (width/2) // py = pixelSize * (y + 0.5f) - (height/2) // pz = 0 //#if DEBUG // if (i == 0 && y == 100) // { // //Console.WriteLine(direction); // Console.WriteLine("color: " + c); // } //#endif // } //} //Task.WaitAll(tasks.ToArray()); bmp.RotateFlip(RotateFlipType.Rotate180FlipX); pictureBox1.Image = bmp; } catch (Exception ex) { MessageBox.Show(ex.Message, "Error!"); } } }