// Copyright 2006 Herre Kuijpers - <herre@xs4all.nl>
//
// This source file(s) may be redistributed, altered and customized
// by any means PROVIDING the authors name and all copyright
// notices remain intact.
// THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED. USE IT AT YOUR OWN RISK. THE AUTHOR ACCEPTS NO
// LIABILITY FOR ANY DATA DAMAGE/LOSS THAT THIS PRODUCT MAY CAUSE.
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using Drawing=System.Drawing;
using System.Text;
using System.Windows.Forms;
using RayTracer;
namespace RayTracerApp
{
public partial class Form1 : Form
{
private bool IsTracing;
private Scene scene = new Scene();
private AntiAliasing anti_aliasing = AntiAliasing.Medium;
private int sceneId = 0;
Texture marbleTexture;
Texture woodTexture;
Texture wallTexture;
Drawing.Bitmap bitmap;
public Form1()
{
InitializeComponent();
IsTracing = false;
}
#region Setup scene
private void SetupScene2()
{
scene = new Scene();
scene.Background = new Background(new Color(.2, .3, .4), 0.5);
Vector campos = new Vector(0, 0, -5);
scene.Camera = new Camera(campos, campos / -2, new Vector(0, 1, 0).Normalize());
Random rnd = new Random();
for (int i = 0; i < 40; i++)
{
// setup a solid reflecting sphere
scene.Shapes.Add(new SphereShape(new Vector(rnd.Next(-100, 100) / 50.0, rnd.Next(-100, 100) / 50.0, rnd.Next(0, 200) / 50.0), .2,
new SolidMaterial(new Color(rnd.Next(0, 100) / 100.0, rnd.Next(0, 100) / 100.0, rnd.Next(0, 100) / 100.0), 0.4, 0.0, 2.0)));
}
scene.Lights.Add(new Light(new Vector(5, 10, -1), new Color(0.8, 0.8, 0.8)));
scene.Lights.Add(new Light(new Vector(-3, 5, -15), new Color(0.8, 0.8, 0.8)));
}
private void SetupScene1()
{
TextureMaterial woodMaterial = new TextureMaterial(woodTexture, 0.2, 0.0, 2, .5);
TextureMaterial marbleMaterial = new TextureMaterial(marbleTexture, 0.0, 0.0, 2, .5);
TextureMaterial wallMaterial = new TextureMaterial(wallTexture, 0.0, 0.0, 2, .4);
scene = new Scene();
scene.Background = new Background(new Color(.8, .8, .8), 0.8);
Vector campos = new Vector(5, 1.8, -15);
scene.Camera = new Camera(campos, campos / -3, new Vector(0, 1, 0).Normalize());
// marble
scene.Shapes.Add(new SphereShape(new Vector(1, 1, -5), 1,
marbleMaterial));
//floor
scene.Shapes.Add(new PlaneShape(new Vector(0, 1, 0).Normalize(), 0, woodMaterial));
//wall
scene.Shapes.Add(new PlaneShape(new Vector(0, 0, 1).Normalize(), 0, wallMaterial));
scene.Lights.Add(new Light(new Vector(25, 20, -20), new Color(0.5, 0.5, 0.5)));
scene.Lights.Add(new Light(new Vector(-3, 5, -15), new Color(0.5, 0.5, 0.5)));
}
// metallic box with marble on stone floor
private void SetupScene4()
{
TextureMaterial woodMaterial = new TextureMaterial(woodTexture, 0.0, 0.0, 2, .5);
TextureMaterial marbleMaterial = new TextureMaterial(marbleTexture, 0.3, 0.0, 2, .5);
TextureMaterial wallMaterial = new TextureMaterial(wallTexture, 0.0, 0.0, 2, .4);
scene = new Scene();
scene.Background = new Background(new Color(.3, .8, .8), 0.8);
Vector campos = new Vector(14, 2, -6);
scene.Camera = new Camera(campos, campos / -2.5, new Vector(-0, 1, 0.1).Normalize());
// marble
scene.Shapes.Add(new SphereShape(new Vector(-3, 1, 5), 2,
marbleMaterial));
// box
scene.Shapes.Add(new BoxShape(new Vector(0, 1, -1), new Vector(1, 0, 0),
woodMaterial));
//floor
scene.Shapes.Add(new PlaneShape(new Vector(0, 1, 0).Normalize(), 0, wallMaterial));
//wall
//scene.Shapes.Add(new PlaneShape(new Vector(0, 0, 1).Normalize(), 0, wallMaterial));
scene.Lights.Add(new Light(new Vector(25, 20, -20), new Color(0.5, 0.5, 0.5)));
scene.Lights.Add(new Light(new Vector(-23, 25, -15), new Color(0.5, 0.5, 0.5)));
}
// single reflective shere on chessboard scene
private void SetupScene3()
{
scene = new Scene();
scene.Camera = new Camera(new Vector(0, 0, -15), new Vector(-.2, 0, 5), new Vector(0, 1, 0));
scene.Background = new Background(new Color(0.5, .5, .5), 0.4);
// setup a solid reflecting sphere
scene.Shapes.Add(new SphereShape(new Vector(-0.5, 0.5, -2), 1.5,
new SolidMaterial(new Color(0, .5, .5), 0.3, 0.0, 2.0)));
// setup the chessboard floor
scene.Shapes.Add(new PlaneShape(new Vector(0.1, 0.9, -0.5).Normalize(), 1.2,
new ChessboardMaterial(new Color(1, 1, 1), new Color(0, 0, 0), 0.2, 0, 1, 0.7)));
//add two lights for better lighting effects
scene.Lights.Add(new Light(new Vector(5, 10, -1), new Color(0.8, 0.8, 0.8)));
scene.Lights.Add(new Light(new Vector(-3, 5, -15), new Color(0.8, 0.8, 0.8)));
}
// marble balls scene
private void SetupScene0()
{
TextureMaterial texture = new TextureMaterial(marbleTexture, 0.0, 0.0, 2, .5);
scene = new Scene();
scene.Camera = new Camera(new Vector(0, 0, -15), new Vector(-.2, 0, 5), new Vector(0, 1, 0));
// setup a solid reflecting sphere
scene.Shapes.Add(new SphereShape(new Vector(-1.5, 0.5, 0), .5,
new SolidMaterial(new Color(0, .5, .5), 0.2, 0.0, 2.0)));
// setup sphere with a marble texture from an image
scene.Shapes.Add(new SphereShape(new Vector(0, 0, 0), 1, texture));
// setup the chessboard floor
scene.Shapes.Add(new PlaneShape(new Vector(0.1, 0.9, -0.5).Normalize(), 1.2,
new ChessboardMaterial(new Color(1, 1, 1), new Color(0, 0, 0), 0.2, 0, 1, 0.7)));
//add two lights for better lighting effects
scene.Lights.Add(new Light(new Vector(5, 10, -1), new Color(0.8, 0.8, 0.8)));
scene.Lights.Add(new Light(new Vector(-3, 5, -15), new Color(0.8, 0.8, 0.8)));
}
#endregion Setup scene
private void button1_Click(object sender, EventArgs e)
{
}
void tracer_RenderUpdate(int progress, double duration, double ETA, int scanline)
{
//only invalidate part of the picturebox that needs to be redrawn
pbScene.Invalidate(new Drawing.Rectangle(0, scanline - 1, pbScene.Image.Width, 2));
statusETA.Text = "Eta: " + (ETA/1000).ToString("0.0") + "s";
statusDuration.Text = "Duration:" + (duration/1000).ToString("0.0") + "s";
Application.DoEvents(); // some time to redraw the screen
}
private void pbScene_MouseDown(object sender, MouseEventArgs e)
{
if (IsTracing) return;
if (bitmap == null) return;
// this implementation is used for debugging purposes.
// click on the pixel on the image to start the raytracing
// for that particular ray through the clicked pixel.
RayTracer.RayTracer tracer = new RayTracer.RayTracer(anti_aliasing,
true,
showPhongToolStripMenuItem.Checked,
castShadowsToolStripMenuItem.Checked,
showReflectionsToolStripMenuItem.Checked,
showRefractionsToolStripMenuItem.Checked);
Drawing.Rectangle rect = new Drawing.Rectangle(0, 0, 300, 300);
DateTime t = DateTime.Now;
Vector screen = scene.Camera.Position + scene.Camera.LookAt;
//e.Graphics.FillRectangle(Brushes.Black, bitmap);
double yp = (e.Y - rect.Top) * 1.0f / bitmap.Height * 2 - 1;
double xp = (e.X - rect.Left) * 1.0f / bitmap.Width * 2 - 1;
Vector pos = new Vector(screen.x + xp, screen.y - yp, screen.z);
Vector dir = pos - scene.Camera.Position;
Ray ray = new Ray(pos, dir.Normalize());
Color color = tracer.CalculateColor(ray, scene);
pictureBox1.BackColor = color.ToArgb();
}
private void renderNowToolStripMenuItem_Click(object sender, EventArgs e)
{
label1.Visible = false;
if (IsTracing) return;
IsTracing = true;
switch (sceneId)
{
case 0:
SetupScene0();
break;
case 1:
SetupScene1();
break;
case 2:
SetupScene2();
break;
case 3:
SetupScene3();
break;
default:
SetupScene4();
break;
}
statusETA.Text = "Eta:";
statusDuration.Text = "Duration:";
RayTracer.RayTracer raytracer = new RayTracer.RayTracer(anti_aliasing,
true,
showPhongToolStripMenuItem.Checked,
castShadowsToolStripMenuItem.Checked,
showReflectionsToolStripMenuItem.Checked,
showRefractionsToolStripMenuItem.Checked);
raytracer.RenderUpdate += new RenderUpdateDelegate(tracer_RenderUpdate);
Drawing.Rectangle rect = new Drawing.Rectangle(0, 0, 300, 300);
bitmap = new Drawing.Bitmap(rect.Width, rect.Height);
Drawing.Graphics g = Drawing.Graphics.FromImage(bitmap);
DateTime t = DateTime.Now;
pbScene.Image = bitmap;
raytracer.RayTraceScene(g, rect, scene);
IsTracing = false;
TimeSpan s = DateTime.Now.Subtract(t);
Console.WriteLine("total render time: " + s.TotalMilliseconds.ToString("0.00"));
statusETA.Text = "";
}
private void CheckMenuAntiAliasing(object menuitem)
{
noneToolStripMenuItem.Checked = noneToolStripMenuItem.Equals(menuitem);
quickToolStripMenuItem.Checked = quickToolStripMenuItem.Equals(menuitem);
lowToolStripMenuItem.Checked = lowToolStripMenuItem.Equals(menuitem);
mediumToolStripMenuItem.Checked = mediumToolStripMenuItem.Equals(menuitem);
highToolStripMenuItem.Checked = highToolStripMenuItem.Equals(menuitem);
veryHighToolStripMenuItem.Checked = veryHighToolStripMenuItem.Equals(menuitem);
}
private void noneToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuAntiAliasing(sender);
anti_aliasing = AntiAliasing.None;
}
private void quickToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuAntiAliasing(sender);
anti_aliasing = AntiAliasing.Quick;
}
private void lowToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuAntiAliasing(sender);
anti_aliasing = AntiAliasing.Low;
}
private void mediumToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuAntiAliasing(sender);
anti_aliasing = AntiAliasing.Medium;
}
private void highToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuAntiAliasing(sender);
anti_aliasing = AntiAliasing.High;
}
private void veryHighToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuAntiAliasing(sender);
anti_aliasing = AntiAliasing.VeryHigh;
}
private void CheckMenuScene(object sender)
{
marbleSpheresToolStripMenuItem.Checked = marbleSpheresToolStripMenuItem.Equals(sender);
woodenFloorAndStoneWallToolStripMenuItem.Checked = woodenFloorAndStoneWallToolStripMenuItem.Equals(sender);
randomMarblesToolStripMenuItem.Checked = randomMarblesToolStripMenuItem.Equals(sender);
}
private void marbleSpheresToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuScene(sender);
sceneId = 0;
}
private void woodenFloorAndStoneWallToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuScene(sender);
sceneId = 1;
}
private void randomMarblesToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuScene(sender);
sceneId = 2;
}
private void reflectiveShereOnChessboardToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuScene(sender);
sceneId = 3;
}
private void woodenBoxAndMarbleToolStripMenuItem_Click(object sender, EventArgs e)
{
CheckMenuScene(sender);
sceneId = 4;
}
private void copyToolStripMenuItem_Click(object sender, EventArgs e)
{
Clipboard.SetImage(bitmap);
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Text = "Loading textures...";
this.Visible = true;
Application.DoEvents();
string path = Application.StartupPath;
// pre-load the textures here, so it only needs to be done once
woodTexture = Texture.FromFile(path + @"\wood2.png");
marbleTexture = Texture.FromFile(path + @"\marble1.png");
wallTexture = Texture.FromFile(path + @"\wall1.png");
label1.Text = "Press F5 to start the RayTracer!";
}
}
}