RaytracerEngine/Form1.cs

252 lines
7.9 KiB
C#
Executable File

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<hitable> 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<hitable>();
//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<hitable>();
//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);
}
}
}