using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using static RaytracerEngine.hitable; namespace RaytracerEngine { public partial class Form1 : Form { vec3 origin; vec3 lower_left_corner; vec3 horizontal; vec3 vertical; List objects; Bitmap bmp; LockBitmap dbm; int nx = 200; int ny = 100; int ns = 3; bool left; bool right; bool fore; bool back; bool look_left; bool look_right; Random rnd; float rand { get{ return (float)rnd.NextDouble();}} public Form1() { InitializeComponent(); //DoubleBuffered = true; left = false; right = false; fore = false; back = false; look_left = false; look_right = false; origin = new vec3(0, 0, 0); lower_left_corner = new vec3(-2.0f, -1.0f, -1.0f); horizontal = new vec3(4.0f, 0.0f, 0.0f); vertical = new vec3(0.0f, 2.0f, 0.0f); objects = new List(); //OLD VERSION //lower_left_corner = new vec3(-2.0f, -1.0f, -1.0f); //horizontal = new vec3(4.0f, 0.0f, 0.0f); //vertical = new vec3(0.0f, 2.0f, 0.0f); lower_left_corner = new vec3(2.0f, 1.0f, -1.0f); horizontal = new vec3(-4.0f, 0.0f, 0.0f); vertical = new vec3(0.0f, -2.0f, 0.0f); objects = new List(); //objects.Add(new sphere(new vec3(0, 0, -1.0f), 0.5f)); //objects.Add(new sphere(new vec3(0, -100.5f, -1f), 100f)); objects.Add(new sphere(new vec3(0, 0, -16), 2)); objects.Add(new sphere(new vec3(3, -1, -14), 1)); objects.Add(new sphere(new vec3(-3, -1, -14), 1)); objects.Add(new triangle(new vec3(-8, -2, -20), new vec3(8, -2, -20), new vec3(8, 10, -20), 0)); objects.Add(new triangle(new vec3(-8, -2, -20), new vec3(8, 10, -20), new vec3(-8, 10, -20), 0)); objects.Add(new triangle(new vec3(-8, -2, -20), new vec3(8, -2, -10), new vec3(8, -2, -20), 0)); objects.Add(new triangle(new vec3(-8, -2, -20), new vec3(-8, -2, -10), new vec3(8, -2, -10), 0)); objects.Add(new triangle(new vec3(8, -2, -20), new vec3(8, -2, -10), new vec3(8, 10, -20), 0)); bmp = new Bitmap(nx, ny); dbm = new LockBitmap(bmp); rnd = new Random(); timer1.Interval = 10; } protected override void OnLoad(EventArgs e) { timer1.Start(); base.OnLoad(e); } protected override void OnClosed(EventArgs e) { bmp.Dispose(); timer1.Stop(); base.OnClosed(e); } vec3 color(ray r, int reflect) { bool hit_any = false; hit_record temp_rec = new hit_record(); hit_record rec = new hit_record(); float closest = float.MaxValue; foreach(var o in objects) { if (o.hit(r, 0.001f, closest, out temp_rec)) { hit_any = true; closest = temp_rec.t; rec = temp_rec; } } if (hit_any && reflect>0) { vec3 target = rec.p + rec.normal; //+ random_unit_in_sphere(); return 0.5f * color(new ray(rec.p, target - rec.p), --reflect); } vec3 unit_dir = vec3.unit_vector(r.direction); float t = 0.5f * (unit_dir.y + 1.0f); return (1.0f - t) * new vec3(1.0f, 1.0f, 1.0f) + t * new vec3(0.5f, 0.7f, 1.0f); } private vec3 random_unit_in_sphere() { vec3 p; float o = 0f; do { p = 2.0f * new vec3(rand, rand, rand) - new vec3(1,1,1); o = p.square_length(); } while (o >= 1f); return p; } private void draw_scene() { dbm.LockBits(); for (int j = ny - 1; j >= 0; j--) { for (int i = 0; i < nx; i++) { vec3 col = new vec3(0, 0, 0); float u = (float)i / (float)nx; float v = (float)j / (float)ny; //for (int s = 0; s < ns; s++) //{ // float u = (float)(i + rand) / (float)nx; // float v = (float)(j + rand) / (float)ny; ray r = new ray(origin, lower_left_corner + u * horizontal + v * vertical); col = color(r, 4); //} //col /= (float)ns; int ir = (int)(255.99 * col.r); int ig = (int)(255.99 * col.g); int ib = (int)(255.99 * col.b); dbm.SetPixel(i, j, Color.FromArgb(255, (byte)ir, (byte)ig, (byte)ib)); } } dbm.UnlockBits(); pictureBox1.Image = bmp; } private void timer1_Tick(object sender, EventArgs e) { const float scale = 0.7f;//for 'walking' speed vec3 forwards_back = vec3.cross(horizontal, vertical); forwards_back.normalize(); vec3 left_right = vec3.cross(vertical, forwards_back); left_right.normalize(); if (left) origin = origin - left_right * scale; if (right) origin = origin + left_right * scale; if (fore) origin = origin - forwards_back * scale; if (back) origin = origin + forwards_back * scale; if (look_left) { //rotational matrix on camera left 25* lower_left_corner = vec3.turn_y(lower_left_corner, ((float)Math.PI / 16)); horizontal = vec3.turn_y(horizontal, ((float)Math.PI / 16)); vertical = vec3.turn_y(vertical, ((float)Math.PI / 16)); } if (look_right) { //rotational matrix on camera right 25* lower_left_corner = vec3.turn_y(lower_left_corner, -((float)Math.PI / 16)); horizontal = vec3.turn_y(horizontal, -((float)Math.PI / 16)); vertical = vec3.turn_y(vertical, -((float)Math.PI / 16)); } draw_scene(); pictureBox1.Refresh(); } protected override void OnPaint(PaintEventArgs e) { draw_scene(); base.OnPaint(e); } protected override void OnKeyDown(KeyEventArgs e) { if (e.KeyValue == 'A') left = true; if (e.KeyValue == 'D') right = true; if (e.KeyValue == 'W') fore = true; if (e.KeyValue == 'S') back = true; if (e.KeyValue == 'Q') look_left = true; if (e.KeyValue == 'E') look_right = true; base.OnKeyDown(e); } protected override void OnKeyUp(KeyEventArgs e) { if (e.KeyValue == 'A') left = false; if (e.KeyValue == 'D') right = false; if (e.KeyValue == 'W') fore = false; if (e.KeyValue == 'S') back = false; if (e.KeyValue == 'Q') look_left = false; if (e.KeyValue == 'E') look_right = false; base.OnKeyUp(e); } } }