first commit

This commit is contained in:
zongor 2022-09-03 23:43:39 -04:00
commit 2418b06414
28 changed files with 1456 additions and 0 deletions

BIN
.vs/RaytracerEngine/v14/.suo Executable file

Binary file not shown.

BIN
.vs/RaytracerEngine/v15/.suo Executable file

Binary file not shown.

View File

@ -0,0 +1,30 @@
<Properties StartupConfiguration="{3C95A1AE-389C-4012-BBC7-CC03EF11C767}|Default">
<MonoDevelop.Ide.ItemProperties.RaytracerEngine PreferredExecutionTarget="MonoDevelop.Default" />
<MonoDevelop.Ide.Workbench ActiveDocument="test/Form1.cs">
<Files>
<File FileName="test/vec3.cs" Line="20" Column="10" />
<File FileName="test/hitable.cs" />
<File FileName="test/sphere.cs" />
<File FileName="test/triangle.cs" />
<File FileName="test/camera.cs" />
<File FileName="test/Form1.cs" Line="38" Column="15" />
</Files>
<Pads>
<Pad Id="ProjectPad">
<State name="__root__">
<Node name="RaytracerEngine" expanded="True">
<Node name="RaytracerEngine" expanded="True">
<Node name="Form1.cs" selected="True" />
</Node>
</Node>
</State>
</Pad>
</Pads>
</MonoDevelop.Ide.Workbench>
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MultiItemStartupConfigurations />
</Properties>

View File

@ -0,0 +1 @@
{"Format":1,"ProjectReferences":[],"MetadataReferences":[{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/Microsoft.CSharp.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/mscorlib.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Core.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Data.DataSetExtensions.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Data.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Deployment.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Drawing.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Net.Http.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Windows.Forms.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Xml.dll","Aliases":[]},{"FilePath":"/Library/Frameworks/Mono.framework/Versions/6.0.0/lib/mono/4.6.2-api/System.Xml.Linq.dll","Aliases":[]}],"Files":["/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/camera.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/DirectBitmap.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Form1.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Form1.Designer.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/hitable.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/LockBitmap.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Program.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Properties/AssemblyInfo.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/ray.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/sphere.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/triangle.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/vec3.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Form1.resx","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Properties/Resources.resx","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Properties/Resources.Designer.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Properties/Settings.settings","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/Properties/Settings.Designer.cs","/Users/Zongor/Documents/Raytracers/RaytracerEngine/test/App.config"],"BuildActions":["Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","Compile","EmbeddedResource","EmbeddedResource","Compile","None","Compile","None"],"Analyzers":[]}

View File

Binary file not shown.

6
App.config Executable file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
</configuration>

39
DirectBitmap.cs Executable file
View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
public class DirectBitmap : IDisposable
{
public Bitmap Bitmap { get; private set; }
public Int32[] Bits { get; private set; }
public bool Disposed { get; private set; }
public int Height { get; private set; }
public int Width { get; private set; }
protected GCHandle BitsHandle { get; private set; }
public DirectBitmap(int width, int height)
{
Width = width;
Height = height;
Bits = new Int32[width * height];
BitsHandle = GCHandle.Alloc(Bits, GCHandleType.Pinned);
Bitmap = new Bitmap(width, height, width * 4, PixelFormat.Format32bppPArgb, BitsHandle.AddrOfPinnedObject());
}
public void Dispose()
{
if (Disposed) return;
Disposed = true;
Bitmap.Dispose();
BitsHandle.Free();
}
}
}

72
Form1.Designer.cs generated Executable file
View File

@ -0,0 +1,72 @@
namespace RaytracerEngine
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.colorDialog1 = new System.Windows.Forms.ColorDialog();
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.timer1 = new System.Windows.Forms.Timer(this.components);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(800, 720);
this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// timer1
//
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 720);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ColorDialog colorDialog1;
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.Timer timer1;
}
}

251
Form1.cs Executable file
View File

@ -0,0 +1,251 @@
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);
}
}
}

126
Form1.resx Executable file
View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="colorDialog1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>138, 17</value>
</metadata>
</root>

168
LockBitmap.cs Executable file
View File

@ -0,0 +1,168 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
class LockBitmap
{
Bitmap source = null;
IntPtr Iptr = IntPtr.Zero;
BitmapData bitmapData = null;
public byte[] Pixels { get; set; }
public int Depth { get; private set; }
public int Width { get; private set; }
public int Height { get; private set; }
public LockBitmap(Bitmap source)
{
this.source = source;
}
/// <summary>
/// Lock bitmap data
/// </summary>
public void LockBits()
{
try
{
// Get width and height of bitmap
Width = source.Width;
Height = source.Height;
// get total locked pixels count
int PixelCount = Width * Height;
// Create rectangle to lock
Rectangle rect = new Rectangle(0, 0, Width, Height);
// get source bitmap pixel format size
Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);
// Check if bpp (Bits Per Pixel) is 8, 24, or 32
if (Depth != 8 && Depth != 24 && Depth != 32)
{
throw new ArgumentException("Only 8, 24 and 32 bpp images are supported.");
}
// Lock bitmap and return bitmap data
bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite,
source.PixelFormat);
// create byte array to copy pixel values
int step = Depth / 8;
Pixels = new byte[PixelCount * step];
Iptr = bitmapData.Scan0;
// Copy data from pointer to array
Marshal.Copy(Iptr, Pixels, 0, Pixels.Length);
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Unlock bitmap data
/// </summary>
public void UnlockBits()
{
try
{
// Copy data from byte array to pointer
Marshal.Copy(Pixels, 0, Iptr, Pixels.Length);
// Unlock bitmap data
source.UnlockBits(bitmapData);
}
catch (Exception ex)
{
throw ex;
}
}
/// <summary>
/// Get the color of the specified pixel
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public Color GetPixel(int x, int y)
{
Color clr = Color.Empty;
// Get color components count
int cCount = Depth / 8;
// Get start index of the specified pixel
int i = ((y * Width) + x) * cCount;
if (i > Pixels.Length - cCount)
throw new IndexOutOfRangeException();
if (Depth == 32) // For 32 bpp get Red, Green, Blue and Alpha
{
byte b = Pixels[i];
byte g = Pixels[i + 1];
byte r = Pixels[i + 2];
byte a = Pixels[i + 3]; // a
clr = Color.FromArgb(a, r, g, b);
}
if (Depth == 24) // For 24 bpp get Red, Green and Blue
{
byte b = Pixels[i];
byte g = Pixels[i + 1];
byte r = Pixels[i + 2];
clr = Color.FromArgb(r, g, b);
}
if (Depth == 8)
// For 8 bpp get color value (Red, Green and Blue values are the same)
{
byte c = Pixels[i];
clr = Color.FromArgb(c, c, c);
}
return clr;
}
/// <summary>
/// Set the color of the specified pixel
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <param name="color"></param>
public void SetPixel(int x, int y, Color color)
{
// Get color components count
int cCount = Depth / 8;
// Get start index of the specified pixel
int i = ((y * Width) + x) * cCount;
if (Depth == 32) // For 32 bpp set Red, Green, Blue and Alpha
{
Pixels[i] = color.B;
Pixels[i + 1] = color.G;
Pixels[i + 2] = color.R;
Pixels[i + 3] = color.A;
}
if (Depth == 24) // For 24 bpp set Red, Green and Blue
{
Pixels[i] = color.B;
Pixels[i + 1] = color.G;
Pixels[i + 2] = color.R;
}
if (Depth == 8)
// For 8 bpp set color value (Red, Green and Blue values are the same)
{
Pixels[i] = color.B;
}
}
}
}

22
Program.cs Executable file
View File

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RaytracerEngine
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

36
Properties/AssemblyInfo.cs Executable file
View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("test")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("test")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3c95a1ae-389c-4012-bbc7-cc03ef11c767")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

63
Properties/Resources.Designer.cs generated Executable file
View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RaytracerEngine.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("RaytracerEngine.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

117
Properties/Resources.resx Executable file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

26
Properties/Settings.Designer.cs generated Executable file
View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace RaytracerEngine.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.0.1.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

7
Properties/Settings.settings Executable file
View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

3
README.md Executable file
View File

@ -0,0 +1,3 @@
This is a semi-real time raytracer implemented from the book [Ray Tracing In One Weekend](https://raytracing.github.io/books/RayTracingInOneWeekend.html)
It also allows you to move around the scene using the WASD for horizontal and Q/E for vertical movement

120
RaytracerEngine.csproj Executable file
View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{3C95A1AE-389C-4012-BBC7-CC03EF11C767}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>RaytracerEngine</RootNamespace>
<AssemblyName>RaytracerEngine</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="camera.cs" />
<Compile Include="DirectBitmap.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="hitable.cs" />
<Compile Include="LockBitmap.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ray.cs" />
<Compile Include="sphere.cs" />
<Compile Include="triangle.cs" />
<Compile Include="vec3.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

23
RaytracerEngine.sln Executable file
View File

@ -0,0 +1,23 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RaytracerEngine", "RaytracerEngine.csproj", "{3C95A1AE-389C-4012-BBC7-CC03EF11C767}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Release|Any CPU.Build.0 = Release|Any CPU
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Debug|x64.ActiveCfg = Debug|x64
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Debug|x64.Build.0 = Debug|x64
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Release|x64.ActiveCfg = Release|x64
{3C95A1AE-389C-4012-BBC7-CC03EF11C767}.Release|x64.Build.0 = Release|x64
EndGlobalSection
EndGlobal

9
RaytracerEngine.userprefs Executable file
View File

@ -0,0 +1,9 @@
<Properties StartupConfiguration="{3C95A1AE-389C-4012-BBC7-CC03EF11C767}|Default">
<MonoDevelop.Ide.Workbench />
<MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
<MonoDevelop.Ide.DebuggingService.Breakpoints>
<BreakpointStore />
</MonoDevelop.Ide.DebuggingService.Breakpoints>
<MonoDevelop.Ide.DebuggingService.PinnedWatches />
<MultiItemStartupConfigurations />
</Properties>

75
camera.cs Executable file
View File

@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
class camera
{
vec3 origin;
vec3 lower_left_corner;
vec3 horizontal;
vec3 vertical;
private const float scale = 0.1f;
public camera()
{
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);
}
public ray get_ray(float u, float v) { return new ray(origin, lower_left_corner + u*horizontal + v*vertical - origin); }
public void turn_left()
{
//rotational matrix on camera left 25*
lower_left_corner = vec3.turn_y(lower_left_corner, 25);
horizontal = vec3.turn_y(horizontal, 25);
vertical = vec3.turn_y(vertical, 25);
}
public void turn_right()
{
//rotational matrix on camera right 25*
lower_left_corner = vec3.turn_y(lower_left_corner, -25);
horizontal = vec3.turn_y(horizontal, -25);
vertical = vec3.turn_y(vertical, -25);
}
public void strafe_left()
{
vec3 forwards_back = vec3.cross(horizontal, vertical);
forwards_back.normalize();
vec3 left_right = vec3.cross(vertical, forwards_back);
left_right.normalize();
origin = origin - left_right * scale;
}
public void strafe_right()
{
vec3 forwards_back = vec3.cross(horizontal, vertical);
forwards_back.normalize();
vec3 left_right = vec3.cross(vertical, forwards_back);
left_right.normalize();
origin = origin + left_right * scale;
}
public void fore()
{
vec3 forwards_back = vec3.cross(horizontal, vertical);
forwards_back.normalize();
origin = origin - forwards_back * scale;
}
public void back()
{
vec3 forwards_back = vec3.cross(horizontal, vertical);
forwards_back.normalize();
origin = origin + forwards_back * scale;
}
}
}

19
hitable.cs Executable file
View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
public abstract class hitable
{
public struct hit_record
{
public float t;
public vec3 p;
public vec3 normal;
}
public virtual bool hit(ray r, float t_min, float t_max, out hit_record rec) { rec = new hit_record(); return false; }
}
}

19
ray.cs Executable file
View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
public class ray
{
private vec3 A;
private vec3 B;
public ray() { }
public ray(vec3 a, vec3 b) { A = a; B = b; }
public vec3 origin { get { return A; } }
public vec3 direction { get { return B; } }
public vec3 pap(float t) { return A + t * B; }
}
}

47
sphere.cs Executable file
View File

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
public class sphere : hitable
{
vec3 center;
float radius;
public sphere() { }
public sphere(vec3 cen, float r) { center = cen; radius = r; }
public override bool hit(ray r, float t_min, float t_max, out hit_record rec)
{
vec3 oc = r.origin - center;
float a = vec3.dot(r.direction, r.direction);
float b = vec3.dot(oc, r.direction);
float c = vec3.dot(oc, oc) - radius * radius;
float discriminant = b * b - a * c;
if (discriminant > 0)
{
float temp = (float)((-b - Math.Sqrt(discriminant)) / a);
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.pap(rec.t);
rec.normal = (rec.p - center) / radius;
return true;
}
temp = (float)((-b + Math.Sqrt(discriminant)) / a);
if (temp < t_max && temp > t_min)
{
rec.t = temp;
rec.p = r.pap(rec.t);
rec.normal = (rec.p - center) / radius;
return true;
}
}
rec = new hit_record();
return false;
}
}
}

118
triangle.cs Executable file
View File

@ -0,0 +1,118 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RaytracerEngine
{
public class triangle : hitable
{
vec3 posa;
vec3 posb;
vec3 posc;
int reflect;
public triangle() { }
public triangle(vec3 a, vec3 b, vec3 c, int r) { posa = a; posb = b; posc = c; reflect = r; }
public override bool hit(ray r, float t_min, float t_max, out hit_record rec)
{
// The three triangle vertices.
vec3 verta, vertb, vertc;
vec3 vecray, posray;
vec3 n = new vec3(0,0,0); // Normal vector
float xa, xb, xc, xd, xe, ya, yb, yc, yd, ye, za, zb, zc, zd, ze; // The components to determine t.
float m, beta, gamma, t; // Components to determine the Barycentric coordinates.
float a, b, c, d, e, f, g, h, i, j, k, l;
// Copy the three positions from the triangle class into the x, y, z arrays.
verta = posa;
vertb = posb;
vertc = posc;
vecray = r.direction;
posray = r.origin;
// Set up the a,b, and c components of the 3 vertices.
xa = verta[0];
xb = vertb[0];
xc = vertc[0];
xd = vecray[0];
xe = posray[0];
ya = verta[1];
yb = vertb[1];
yc = vertc[1];
yd = vecray[1];
ye = posray[1];
za = verta[2];
zb = vertb[2];
zc = vertc[2];
zd = vecray[2];
ze = posray[2];
// Set up the components.
a = xa - xb;
b = ya - yb;
c = za - zb;
d = xa - xc;
e = ya - yc;
f = za - zc;
g = xd;
h = yd;
i = zd;
j = xa - xe;
k = ya - ye;
l = za - ze;
// Calculate M, Beta, Gamma, and t.
m = (a * ((e * i) - (h * f))) + (b * ((g * f) - (d * i))) + (c * ((d * h) - (e * g)));
t = (-(((f * ((a * k) - (j * b))) + (e * ((j * c) - (a * l))) + (d * ((b * l) - (k * c))))) / m);
// Return the result of the intersection.
if (t < 0) {
t = 0;
rec = new hit_record();
return false;
}
gamma = (((i * ((a * k) - (j * b))) + (h * ((j * c) - (a * l))) + (g * ((b * l) - (k * c)))) / m);
if ((gamma < 0) || (gamma > 1)) {
t = 0;
rec = new hit_record();
return false;
}
beta = ((j * ((e * i) - (h * f)) + (k * ((g * f) - (d * i))) + (l * ((d * h) - (e * g)))) / m);
if ((beta < 0) || (beta > (1-gamma))) {
t = 0;
rec = new hit_record();
return false;
}
// Calculate the normal of the triangle
vec3 u = new vec3(0, 0, 0);
vec3 v = new vec3(0, 0, 0);
u = vertb - verta;
v = vertc - verta;
n = vec3.cross(v, u);
// Determine the position that the vector hits the object.
vec3 hit_pos = new vec3(0, 0, 0);
vecray = vecray * t;
hit_pos = posray + vecray;
// Set up the normal of the triangle in regards to the hit position.
vec3 normal = new vec3(0, 0, 0);
normal = hit_pos - n;
normal.normalize();
if (t < t_max && t > t_min)
{
rec.t = t;
rec.p = hit_pos;
rec.normal = normal;
return true;
}
rec = new hit_record();
return false;
}
}
}

59
vec3.cs Executable file
View File

@ -0,0 +1,59 @@
using System;
namespace RaytracerEngine
{
public class vec3
{
protected float[] e;
public vec3() { e = new float[3]; }
public vec3(float e0, float e1, float e2) { e = new float[3]; e[0] = e0; e[1] = e1; e[2] = e2; }
public float x { get { return e[0]; } set { e[0] = value; } }
public float y { get { return e[1]; } set { e[1] = value; } }
public float z { get { return e[2]; } set { e[2] = value; } }
public float r { get { return e[0]; } set { e[0] = value; } }
public float g { get { return e[1]; } set { e[1] = value; } }
public float b { get { return e[2]; } set { e[2] = value; } }
public float this[int i] { get { return e[i]; } set { e[i] = value; } }
public float square_length() { return (e[0] * e[0] + e[1] * e[1] + e[2] * e[2]); }
public float length() { return (float)Math.Sqrt(e[0]* e[0] + e[1]* e[1] + e[2]* e[2]); }
public void normalize()
{
float k = 1.0f / (float)Math.Sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]);
e[0] *= k; e[1] *= k; e[2] *= k;
}
public static vec3 operator -(vec3 v) { return new vec3(-v.x, -v.y, -v.z); }
public static vec3 operator +(vec3 v, vec3 o) { return new vec3(v.x + o.x, v.y + o.y, v.z + o.z); }
public static vec3 operator -(vec3 v, vec3 o) { return new vec3(v.x - o.x, v.y - o.y, v.z - o.z); }
public static vec3 operator *(vec3 v, vec3 o) { return new vec3(v.x * o.x, v.y * o.y, v.z * o.z); }
public static vec3 operator /(vec3 v, vec3 o) { return new vec3(v.x / o.x, v.y / o.y, v.z / o.z); }
public static vec3 operator *(float t, vec3 v) { return new vec3(t * v.x, t * v.y, t * v.z); }
public static vec3 operator *(vec3 v, float t) { return new vec3(t * v.x, t * v.y, t * v.z); }
public static vec3 operator /(vec3 v, float t) { return new vec3(v.x / t, v.y / t, v.z / t); }
public static float dot(vec3 v, vec3 o) { return v.x * o.x + v.y * o.y + v.z * o.z; }
public static vec3 cross(vec3 v, vec3 o) { return new vec3(v.y * o.z - v.z * o.y, -(v.x * o.z - v.z * o.x), v.x * o.y - v.y * o.x); }
public static vec3 unit_vector(vec3 v) { return v / v.length(); }
public static vec3 turn_x(vec3 v, float d)
{
float y = 0, z = 0;
y = (float)(Math.Cos(d) * v.y + -Math.Sin(d) * v.z);
z = (float)(Math.Sin(d) * v.y + Math.Cos(d) * v.z);
return new vec3(v.x, y, z);
}
public static vec3 turn_y(vec3 v, float d)
{
float x = 0, z = 0;
x = (float)(Math.Cos(d) * v.x + Math.Sin(d) * v.z);
z = (float)(-Math.Sin(d) * v.x + Math.Cos(d) * v.z);
return new vec3(x, v.y, z);
}
public static vec3 turn_z(vec3 v, float d)
{
float x = 0, y = 0;
x = (float)(Math.Cos(d) * v.x + -Math.Sin(d) * v.y);
y = (float)(Math.Sin(d) * v.x + Math.Cos(d) * v.y);
return new vec3(x, y, v.z);
}
}
}