commit 2418b06414978784c60b4fe1dac25ea7c29dc01c Author: zongor Date: Sat Sep 3 23:43:39 2022 -0400 first commit diff --git a/.vs/RaytracerEngine/v14/.suo b/.vs/RaytracerEngine/v14/.suo new file mode 100755 index 0000000..e3bfbe4 Binary files /dev/null and b/.vs/RaytracerEngine/v14/.suo differ diff --git a/.vs/RaytracerEngine/v15/.suo b/.vs/RaytracerEngine/v15/.suo new file mode 100755 index 0000000..5aef136 Binary files /dev/null and b/.vs/RaytracerEngine/v15/.suo differ diff --git a/.vs/RaytracerEngine/xs/UserPrefs.xml b/.vs/RaytracerEngine/xs/UserPrefs.xml new file mode 100755 index 0000000..51da035 --- /dev/null +++ b/.vs/RaytracerEngine/xs/UserPrefs.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.vs/RaytracerEngine/xs/project-cache/RaytracerEngine-Debug.json b/.vs/RaytracerEngine/xs/project-cache/RaytracerEngine-Debug.json new file mode 100755 index 0000000..71d5cac --- /dev/null +++ b/.vs/RaytracerEngine/xs/project-cache/RaytracerEngine-Debug.json @@ -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":[]} \ No newline at end of file diff --git a/.vs/RaytracerEngine/xs/sqlite3/db.lock b/.vs/RaytracerEngine/xs/sqlite3/db.lock new file mode 100755 index 0000000..e69de29 diff --git a/.vs/RaytracerEngine/xs/sqlite3/storage.ide b/.vs/RaytracerEngine/xs/sqlite3/storage.ide new file mode 100755 index 0000000..182fc40 Binary files /dev/null and b/.vs/RaytracerEngine/xs/sqlite3/storage.ide differ diff --git a/App.config b/App.config new file mode 100755 index 0000000..e89424b --- /dev/null +++ b/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/DirectBitmap.cs b/DirectBitmap.cs new file mode 100755 index 0000000..3fd10eb --- /dev/null +++ b/DirectBitmap.cs @@ -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(); + } + } +} diff --git a/Form1.Designer.cs b/Form1.Designer.cs new file mode 100755 index 0000000..52ab34b --- /dev/null +++ b/Form1.Designer.cs @@ -0,0 +1,72 @@ +namespace RaytracerEngine +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} + diff --git a/Form1.cs b/Form1.cs new file mode 100755 index 0000000..8915243 --- /dev/null +++ b/Form1.cs @@ -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 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); + } + } +} diff --git a/Form1.resx b/Form1.resx new file mode 100755 index 0000000..ea568f7 --- /dev/null +++ b/Form1.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 138, 17 + + \ No newline at end of file diff --git a/LockBitmap.cs b/LockBitmap.cs new file mode 100755 index 0000000..4b6ba9e --- /dev/null +++ b/LockBitmap.cs @@ -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; + } + + /// + /// Lock bitmap data + /// + 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; + } + } + + /// + /// Unlock bitmap data + /// + 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; + } + } + + /// + /// Get the color of the specified pixel + /// + /// + /// + /// + 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; + } + + /// + /// Set the color of the specified pixel + /// + /// + /// + /// + 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; + } + } + } +} diff --git a/Program.cs b/Program.cs new file mode 100755 index 0000000..ecffa75 --- /dev/null +++ b/Program.cs @@ -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 + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100755 index 0000000..6fba7f0 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -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")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100755 index 0000000..021f9e0 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace RaytracerEngine.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // 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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100755 index 0000000..ffecec8 --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100755 index 0000000..f4080c2 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +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; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100755 index 0000000..abf36c5 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/README.md b/README.md new file mode 100755 index 0000000..f223c6e --- /dev/null +++ b/README.md @@ -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 diff --git a/RaytracerEngine.csproj b/RaytracerEngine.csproj new file mode 100755 index 0000000..b80c1ae --- /dev/null +++ b/RaytracerEngine.csproj @@ -0,0 +1,120 @@ + + + + + Debug + AnyCPU + {3C95A1AE-389C-4012-BBC7-CC03EF11C767} + WinExe + Properties + RaytracerEngine + RaytracerEngine + v4.6.2 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + bin\x64\Debug\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + bin\x64\Release\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + \ No newline at end of file diff --git a/RaytracerEngine.sln b/RaytracerEngine.sln new file mode 100755 index 0000000..0d4ea0c --- /dev/null +++ b/RaytracerEngine.sln @@ -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 diff --git a/RaytracerEngine.userprefs b/RaytracerEngine.userprefs new file mode 100755 index 0000000..aa4752c --- /dev/null +++ b/RaytracerEngine.userprefs @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/camera.cs b/camera.cs new file mode 100755 index 0000000..e1a6ab4 --- /dev/null +++ b/camera.cs @@ -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; + } + } +} diff --git a/hitable.cs b/hitable.cs new file mode 100755 index 0000000..8b45711 --- /dev/null +++ b/hitable.cs @@ -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; } + } +} diff --git a/ray.cs b/ray.cs new file mode 100755 index 0000000..52b5692 --- /dev/null +++ b/ray.cs @@ -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; } + } +} diff --git a/sphere.cs b/sphere.cs new file mode 100755 index 0000000..7b79d61 --- /dev/null +++ b/sphere.cs @@ -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; + } + } +} diff --git a/triangle.cs b/triangle.cs new file mode 100755 index 0000000..dfc4be1 --- /dev/null +++ b/triangle.cs @@ -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; + } + } +} diff --git a/vec3.cs b/vec3.cs new file mode 100755 index 0000000..9e1b5f5 --- /dev/null +++ b/vec3.cs @@ -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); + } + } +}