about summary refs log tree commit diff stats
path: root/apps/raytracing
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2020-10-04 23:12:21 -0700
committerKartik Agaram <vc@akkartik.com>2020-10-04 23:12:21 -0700
commitcdff5d73ceaa269bc1d262d6f7b6fdda794de56b (patch)
treef8c24e29b471fd9e020aa954e94d3d1882051bcc /apps/raytracing
parent00af72ccb0d342feda053191793678e41548ee72 (diff)
downloadmu-cdff5d73ceaa269bc1d262d6f7b6fdda794de56b.tar.gz
6952 - raytracing: much better
The image is now visually indistinguishable from the baseline, though the
file isn't quite bit-for-bit correct.

I found 3 bugs:
a) I forgot to normalize the ray. After creating a helper to "automatically"
do it for me, it turns out said helper requires manually using.
b) I forgot to multiply by t at one place.
c) vec3-length was half-written.

For the umpteenth time, the bugs were all in the last place I looked. I
was worried about spending a lot of time transcribing `main` without any
feedback, but that turned out to be perfect.
Diffstat (limited to 'apps/raytracing')
-rw-r--r--apps/raytracing/3.mu86
-rw-r--r--apps/raytracing/color.h15
-rw-r--r--apps/raytracing/main.cc104
-rw-r--r--apps/raytracing/ray.h25
-rw-r--r--apps/raytracing/vec3.h102
5 files changed, 330 insertions, 2 deletions
diff --git a/apps/raytracing/3.mu b/apps/raytracing/3.mu
index 24d31040..359b5c9b 100644
--- a/apps/raytracing/3.mu
+++ b/apps/raytracing/3.mu
@@ -10,7 +10,16 @@ fn ray-color _in: (addr ray), _out: (addr rgb) {
   var in/esi: (addr ray) <- copy _in
   var out/edi: (addr rgb) <- copy _out
   var dir/eax: (addr vec3) <- get in, dir
-  var y-addr/eax: (addr float) <- get dir, y
+#?   print-string 0, "r.dir: "
+#?   print-vec3 0, dir
+#?   print-string 0, "\n"
+  var unit-storage: vec3
+  var unit/ecx: (addr vec3) <- address unit-storage
+  vec3-unit dir, unit
+#?   print-string 0, "r.dir normalized: "
+#?   print-vec3 0, unit
+#?   print-string 0, "\n"
+  var y-addr/eax: (addr float) <- get unit, y
   # t = (dir.y + 1.0) / 2.0
   var t/xmm0: float <- copy *y-addr
   var one/eax: int <- copy 1
@@ -19,6 +28,9 @@ fn ray-color _in: (addr ray), _out: (addr rgb) {
   var two/eax: int <- copy 2
   var two-f/xmm2: float <- convert two
   t <- divide two-f
+#?   print-string 0, "t: "
+#?   print-float 0, t
+#?   print-string 0, "\n"
   # whitening = (1.0 - t) * white
   var whitening-storage: rgb
   var whitening/ecx: (addr rgb) <- address whitening-storage
@@ -26,6 +38,9 @@ fn ray-color _in: (addr ray), _out: (addr rgb) {
   var one-minus-t/xmm3: float <- copy one-f
   one-minus-t <- subtract t
   rgb-scale-up whitening, one-minus-t
+#?   print-string 0, "whitening: "
+#?   print-rgb-raw 0, whitening
+#?   print-string 0, "\n"
   # out = t * (0.5, 0.7, 1.0)
   var dest/eax: (addr float) <- get out, r
   fill-in-rational dest, 5, 0xa
@@ -33,8 +48,15 @@ fn ray-color _in: (addr ray), _out: (addr rgb) {
   fill-in-rational dest, 7, 0xa
   dest <- get out, b
   copy-to *dest, one-f
+  rgb-scale-up out, t
+#?   print-string 0, "base: "
+#?   print-rgb-raw 0, out
+#?   print-string 0, "\n"
   # blend with whitening
   rgb-add-to out, whitening
+#?   print-string 0, "result: "
+#?   print-rgb-raw 0, out
+#?   print-string 0, "\n"
 }
 
 fn main -> exit-status/ebx: int {
@@ -45,6 +67,14 @@ fn main -> exit-status/ebx: int {
   var aspect: float
   var aspect-addr/eax: (addr float) <- address aspect
   fill-in-rational aspect-addr, 0x10, 9  # 16/9
+#?   print-string 0, "aspect ratio: "
+#?   print-float 0, aspect
+#?   print-string 0, " "
+#?   {
+#?     var foo2/ebx: int <- reinterpret aspect
+#?     print-int32-hex 0, foo2
+#?   }
+#?   print-string 0, "\n"
 
   # camera
 
@@ -52,9 +82,29 @@ fn main -> exit-status/ebx: int {
   var tmp/eax: int <- copy 2
   var two-f/xmm4: float <- convert tmp
   var viewport-height/xmm7: float <- copy two-f
+#?   print-string 0, "viewport height: "
+#?   print-float 0, viewport-height
+#?   print-string 0, " "
+#?   {
+#?     var foo: float
+#?     copy-to foo, viewport-height
+#?     var foo2/ebx: int <- reinterpret foo
+#?     print-int32-hex 0, foo2
+#?   }
+#?   print-string 0, "\n"
   # viewport-width = aspect * viewport-height
   var viewport-width/xmm6: float <- convert tmp
   viewport-width <- multiply aspect
+#?   print-string 0, "viewport width: "
+#?   print-float 0, viewport-width
+#?   print-string 0, " "
+#?   {
+#?     var foo: float
+#?     copy-to foo, viewport-width
+#?     var foo2/ebx: int <- reinterpret foo
+#?     print-int32-hex 0, foo2
+#?   }
+#?   print-string 0, "\n"
   # focal-length = 1.0
   tmp <- copy 1
   var focal-length/xmm5: float <- convert tmp
@@ -119,6 +169,9 @@ fn main -> exit-status/ebx: int {
       # u = i / (image-width - 1)
       var u/xmm0: float <- convert i
       u <- divide image-width-1
+#?       print-string 0, "u: "
+#?       print-float 0, u
+#?       print-string 0, "\n"
       # v = j / (image-height - 1)
       var v/xmm1: float <- convert j
       v <- divide image-height-1
@@ -147,6 +200,9 @@ fn main -> exit-status/ebx: int {
         vec3-add-to dest, tmp
         # . r.dir -= origin
         vec3-subtract-from dest, origin
+#?         print-string 0, "ray direction: "
+#?         print-vec3 0, dest
+#?         print-string 0, "\n"
       }
       # pixel-color = ray-color(r)
       var c-storage: rgb
@@ -226,6 +282,20 @@ fn print-rgb screen: (addr screen), _c: (addr rgb) {
   print-string screen, "\n"
 }
 
+fn print-rgb-raw screen: (addr screen), _v: (addr rgb) {
+  var v/esi: (addr rgb) <- copy _v
+  print-string screen, "("
+  var tmp/eax: (addr float) <- get v, r
+  print-float screen, *tmp
+  print-string screen, ", "
+  tmp <- get v, g
+  print-float screen, *tmp
+  print-string screen, ", "
+  tmp <- get v, b
+  print-float screen, *tmp
+  print-string screen, ")"
+}
+
 fn rgb-white _c: (addr rgb) {
   var c/esi: (addr rgb) <- copy _c
   var one/eax: int <- copy 1
@@ -377,6 +447,9 @@ fn vec3-scale-down _v1: (addr vec3), f: float {
 
 fn vec3-unit in: (addr vec3), out: (addr vec3) {
   var len/xmm0: float <- vec3-length in
+#?   print-string 0, "len: "
+#?   print-float 0, len
+#?   print-string 0, "\n"
   copy-object in, out
   vec3-scale-down out, len
 }
@@ -393,5 +466,14 @@ fn vec3-length-squared _v: (addr vec3) -> result/xmm0: float {
   var tmp/xmm1: float <- copy *src
   tmp <- multiply tmp
   result <- copy tmp
-  # 
+  # result += v.y * v.y
+  src <- get v, y
+  tmp <- copy *src
+  tmp <- multiply tmp
+  result <- add tmp
+  # result += v.z * v.z
+  src <- get v, z
+  tmp <- copy *src
+  tmp <- multiply tmp
+  result <- add tmp
 }
diff --git a/apps/raytracing/color.h b/apps/raytracing/color.h
new file mode 100644
index 00000000..a8a34b26
--- /dev/null
+++ b/apps/raytracing/color.h
@@ -0,0 +1,15 @@
+#ifndef COLOR_H
+#define COLOR_H
+
+#include "vec3.h"
+
+#include <iostream>
+
+void write_color(std::ostream &out, color pixel_color) {
+    // Write the translated [0,255] value of each color component.
+    out << static_cast<int>(255.999 * pixel_color.x()) << ' '
+        << static_cast<int>(255.999 * pixel_color.y()) << ' '
+        << static_cast<int>(255.999 * pixel_color.z()) << '\n';
+}
+
+#endif
diff --git a/apps/raytracing/main.cc b/apps/raytracing/main.cc
new file mode 100644
index 00000000..8ebfc08f
--- /dev/null
+++ b/apps/raytracing/main.cc
@@ -0,0 +1,104 @@
+#include <iostream>
+
+// print float in some sort of intuitive hex that also helps visualize the underlying bits
+void p(std::ostream &out, float f) {
+    int bits = *(int*)&f;
+    // sign
+    if (bits & 0x80000000) {
+      out << '-';
+    }
+    // mantissa
+    int mantissa = bits & 0x007fffff;
+    int exponent = (bits & 0x7f800000) >> 23;
+    out << std::hex << mantissa << "P" << std::dec << (exponent-127);
+}
+
+#include "color.h"
+#include "ray.h"
+#include "vec3.h"
+
+color ray_color(const ray& r) {
+//?     std::cerr << "r.dir: " << r.direction() << '\n';
+//?     std::cerr << "r.dir length: ";
+//?       p(std::cerr, r.direction().length());
+//?       std::cerr << '\n';
+    vec3 unit_direction = unit_vector(r.direction());
+//?     std::cerr << "r.dir normalized: " << unit_direction << '\n';
+    float t = 0.5*(unit_direction.y() + 1.0);
+//?     std::cerr << "t: ";
+//?       p(std::cerr, t);
+//?       std::cerr << '\n';
+    vec3 whitening = (1.0-t)*color(1.0, 1.0, 1.0);
+//?     std::cerr << "whitening: ";
+//?       p(std::cerr, whitening.x());
+//?       std::cerr << " ";
+//?       p(std::cerr, whitening.y());
+//?       std::cerr << " ";
+//?       p(std::cerr, whitening.z());
+//?       std::cerr << "\n";
+    vec3 base = t*color(0.5, 0.7, 1.0);
+//?     std::cerr << "base: ";
+//?       p(std::cerr, base.x());
+//?       std::cerr << " ";
+//?       p(std::cerr, base.y());
+//?       std::cerr << " ";
+//?       p(std::cerr, base.z());
+//?       std::cerr << "\n";
+    vec3 result = base + whitening;
+//?     std::cerr << "result: ";
+//?       p(std::cerr, result.x());
+//?       std::cerr << " ";
+//?       p(std::cerr, result.y());
+//?       std::cerr << " ";
+//?       p(std::cerr, result.z());
+//?       std::cerr << "\n";
+    return result;
+}
+
+int main() {
+
+    // Image
+    const float aspect_ratio = 16.0 / 9.0;
+//?     std::cerr << "aspect ratio: " << aspect_ratio << ' ' << std::hex << *(int*)&aspect_ratio << '\n';
+    const int image_width = 400;
+    const int image_height = static_cast<int>(image_width / aspect_ratio);
+
+    // Camera
+
+    float viewport_height = 2.0;
+//?     std::cerr << "viewport height: " << viewport_height << ' ' << std::hex << *(int*)&viewport_height << '\n';
+    float viewport_width = aspect_ratio * viewport_height;
+//?     std::cerr << "viewport width: " << viewport_width << ' ' << std::hex << *(int*)&viewport_width << '\n';
+    float focal_length = 1.0;
+
+    auto origin = point3(0, 0, 0);
+    auto horizontal = vec3(viewport_width, 0, 0);
+    auto vertical = vec3(0, viewport_height, 0);
+    auto lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length);
+
+    // Render
+
+    std::cout << "P3\n" << image_width << " " << image_height << "\n255\n";
+
+    for (int j = image_height-1; j >= 0; --j) {
+//?         std::cerr << "\rScanlines remaining: " << j << ' ' << std::flush;
+        for (int i = 0; i < image_width; ++i) {
+            auto u = float(i) / (image_width-1);
+//?             std::cerr << "u: " << u << '\n';
+            auto v = float(j) / (image_height-1);
+            ray r(origin, lower_left_corner + u*horizontal + v*vertical - origin);
+//?             std::cerr << "ray origin: " << r.orig.x() << " " << r.orig.y() << " " << r.orig.z() << '\n';
+//?             std::cerr << "ray direction: " << r.dir.x() << " " << r.dir.y() << " " << r.dir.z() << '\n';
+//?             std::cerr << "ray dir.x: " << r.dir.x() << " ";
+//?               p(std::cerr, r.dir.x());
+//?               std::cerr << '\n';
+            color pixel_color = ray_color(r);
+//?             std::cerr << "pixel color: " << pixel_color.x() << " " << pixel_color.y() << " " << pixel_color.z() << '\n';
+            write_color(std::cout, pixel_color);
+//?             break;
+        }
+//?         break;
+    }
+
+//?     std::cerr << "\r";
+}
diff --git a/apps/raytracing/ray.h b/apps/raytracing/ray.h
new file mode 100644
index 00000000..ed65168a
--- /dev/null
+++ b/apps/raytracing/ray.h
@@ -0,0 +1,25 @@
+#ifndef RAY_H
+#define RAY_H
+
+#include "vec3.h"
+
+class ray {
+    public:
+        ray() {}
+        ray(const point3& origin, const vec3& direction)
+            : orig(origin), dir(direction)
+        {}
+
+        point3 origin() const  { return orig; }
+        vec3 direction() const { return dir; }
+
+        point3 at(float t) const {
+            return orig + t*dir;
+        }
+
+    public:
+        point3 orig;
+        vec3 dir;
+};
+
+#endif
diff --git a/apps/raytracing/vec3.h b/apps/raytracing/vec3.h
new file mode 100644
index 00000000..d8341d36
--- /dev/null
+++ b/apps/raytracing/vec3.h
@@ -0,0 +1,102 @@
+#ifndef VEC3_H
+#define VEC3_H
+
+#include <cmath>
+#include <iostream>
+
+using std::sqrt;
+
+class vec3 {
+    public:
+        vec3() : e{0,0,0} {}
+        vec3(float e0, float e1, float e2) : e{e0, e1, e2} {}
+
+        float x() const { return e[0]; }
+        float y() const { return e[1]; }
+        float z() const { return e[2]; }
+
+        vec3 operator-() const { return vec3(-e[0], -e[1], -e[2]); }
+        float operator[](int i) const { return e[i]; }
+        float& operator[](int i) { return e[i]; }
+
+        vec3& operator+=(const vec3 &v) {
+            e[0] += v.e[0];
+            e[1] += v.e[1];
+            e[2] += v.e[2];
+            return *this;
+        }
+
+        vec3& operator*=(const float t) {
+            e[0] *= t;
+            e[1] *= t;
+            e[2] *= t;
+            return *this;
+        }
+
+        vec3& operator/=(const float t) {
+            return *this *= 1/t;
+        }
+
+        float length() const {
+            return sqrt(length_squared());
+        }
+
+        float length_squared() const {
+            return e[0]*e[0] + e[1]*e[1] + e[2]*e[2];
+        }
+
+    public:
+        float e[3];
+};
+
+// Type aliases for vec3
+using point3 = vec3;   // 3D point
+using color = vec3;    // RGB color
+
+// vec3 Utility Functions
+
+inline std::ostream& operator<<(std::ostream &out, const vec3 &v) {
+    return out << v.e[0] << ' ' << v.e[1] << ' ' << v.e[2];
+}
+
+inline vec3 operator+(const vec3 &u, const vec3 &v) {
+    return vec3(u.e[0] + v.e[0], u.e[1] + v.e[1], u.e[2] + v.e[2]);
+}
+
+inline vec3 operator-(const vec3 &u, const vec3 &v) {
+    return vec3(u.e[0] - v.e[0], u.e[1] - v.e[1], u.e[2] - v.e[2]);
+}
+
+inline vec3 operator*(const vec3 &u, const vec3 &v) {
+    return vec3(u.e[0] * v.e[0], u.e[1] * v.e[1], u.e[2] * v.e[2]);
+}
+
+inline vec3 operator*(float t, const vec3 &v) {
+    return vec3(t*v.e[0], t*v.e[1], t*v.e[2]);
+}
+
+inline vec3 operator*(const vec3 &v, float t) {
+    return t * v;
+}
+
+inline vec3 operator/(vec3 v, float t) {
+    return (1/t) * v;
+}
+
+inline float dot(const vec3 &u, const vec3 &v) {
+    return u.e[0] * v.e[0]
+         + u.e[1] * v.e[1]
+         + u.e[2] * v.e[2];
+}
+
+inline vec3 cross(const vec3 &u, const vec3 &v) {
+    return vec3(u.e[1] * v.e[2] - u.e[2] * v.e[1],
+                u.e[2] * v.e[0] - u.e[0] * v.e[2],
+                u.e[0] * v.e[1] - u.e[1] * v.e[0]);
+}
+
+inline vec3 unit_vector(vec3 v) {
+    return v / v.length();
+}
+
+#endif