Commits

Anonymous committed 5247830

add light source and shadow (ish)

Comments (0)

Files changed (1)

 #include <sys/stat.h>
 
 #define SWAP(a, b, t) do{ (t) = (a); (a) = (b); (b) = (t); }while(0)
+#define BLACK      (Color){ .val = 0x00000000 }
 #define FAR_PLANE  100.
 #define NEAR_PLANE   1.1
 #define M_PI         3.14159265358979323846
 
+// TODO: fix for endianness
 typedef union {
     uint32_t val;
     struct {
-        uint8_t b, g, r, t; // watch out for Endianness...
+        uint8_t b, g, r, t;
     };
 } Color;
 
     double radius;
 } Sphere;
 
+typedef struct {
+    Point  center;
+    Vector normal;
+    double radius;
+} Disk;
+
 typedef union {
     Sphere sphere;
     Plane  plane;
+    Disk   disk;
 } Shape;
 
 typedef struct {
 } Object;
 
 typedef struct {
+    Point position;
+} Light;
+
+typedef struct {
     Color *buf;
     int xres;
     int yres;
     return 1;
 }
 
-Color shade(Ray r, Object o)
+int intersect_disk(Shape d, Ray *r)
 {
-    return o.color;
+    Ray t = *r;
+
+    if (!intersect_plane((Shape){ .plane = { d.disk.center, d.disk.normal } }, &t)) return 0;
+
+    Point  p = add(t.origin, scalar_multiply(t.tmax, t.direction));
+    Vector v = add(p, scalar_multiply(-1, d.disk.center));
+    if (dot(v, v) > d.disk.radius * d.disk.radius) return 0;
+    r->tmax = t.tmax;
+    return 1;
 }
 
-Color trace(Ray r, Object *o, Color bg)
+Color trace(Ray r, Object *o, Light *l, Color bg, int depth)
 {
     Object *p, *hit = NULL;
+    Light  *i;
 
     for (p = o; p->intersect; p++)
         if (p->intersect(p->shape, &r))
             hit = p;
 
-    return hit ? shade(r, *hit) : bg;
+    if (!hit) return bg;
+
+    // TODO: add light intensity (perhaps color)
+    // TODO: fix hitting self problem (moving towards light by 0.000001 * distance is ugly)
+    for (i = l; dot(i->position, i->position); i++) {
+        Point  intersect = add(r.origin, scalar_multiply(r.tmax, r.direction));
+        Vector delta     = add(i->position, scalar_multiply(-1, intersect));
+        Ray    shadow    = { add(intersect, scalar_multiply(0.000001, delta)), normalize(delta), 0, magnitude(delta) };
+
+        for (p = o; p->intersect; p++)
+            if (p->intersect(p->shape, &shadow))
+                break; // no light from this source
+
+        if (p->intersect)
+            continue;
+
+        return hit->color;
+    }
+    return BLACK;
 }
 
-void render(Camera c, Object *o, Color bg)
+void render(Camera c, Object *o, Light *l, Color bg)
 {
     int x, y;
     Object *hit;
 
     for (y = 0; y < c.yres; y++)
         for (x = 0; x < c.xres; x++)
-            *(c.buf + y * c.xres + x) = trace(new_primary_ray(c, x, y), o, bg);
+            *(c.buf + y * c.xres + x) = trace(new_primary_ray(c, x, y), o, l, bg, 5);
 }
 
 int main(void)
 {
-    int fd;
-    uint8_t *fbm;
-    struct fb_var_screeninfo vi;
-    struct fb_fix_screeninfo fi;
-
-    //Sphere s = { { 0, 0, 10 }, 2 };
     Camera c = { NULL, 0, 0, radians(90), { 0 }, { 0, 0, 1 } };
     Object objects[] = {
-        { { .plane  = { {   0,   0, 20 }, {  0,  0, -1 } } }, { .val = 0x0000ffffUL }, intersect_plane  },
-        { { .plane  = { { -10,   0,  0 }, {  1,  0,  0 } } }, { .val = 0x00ff0000UL }, intersect_plane  },
-        { { .plane  = { {  10,   0,  0 }, { -1,  0,  0 } } }, { .val = 0x00ffff00UL }, intersect_plane  },
-        { { .plane  = { {   0,  10,  0 }, {  0, -1,  0 } } }, { .val = 0x00ffffffUL }, intersect_plane  },
-        { { .plane  = { {   0, -10,  0 }, {  0,  1,  0 } } }, { .val = 0x00000000UL }, intersect_plane  },
-        { { .sphere = { {   0,   0, 10 }, 2              } }, { .val = 0x000000ffUL }, intersect_sphere },
-        { { .sphere = { {   1,   1,  9 }, 1.5            } }, { .val = 0x0000ff00UL }, intersect_sphere },
+        { { .sphere = { {   0,   0, 10 },                   2                   } }, { .val = 0x000000ffUL }, intersect_sphere },
+        { { .sphere = { {   1,   1,  9 },                   1.5                 } }, { .val = 0x0000ff00UL }, intersect_sphere },
+        { { .plane  = { {   0,   0, 20 },                   {  0,  0, -1 }      } }, { .val = 0x0000ffffUL }, intersect_plane  },
+        { { .plane  = { { -10,   0,  0 },                   {  1,  0,  0 }      } }, { .val = 0x00ff0000UL }, intersect_plane  },
+        { { .plane  = { {  10,   0,  0 },                   { -1,  0,  0 }      } }, { .val = 0x00ffff00UL }, intersect_plane  },
+        { { .plane  = { {   0,  10,  0 },                   {  0, -1,  0 }      } }, { .val = 0x00ffffffUL }, intersect_plane  },
+        { { .plane  = { {   0, -10,  0 },                   {  0,  1,  0 }      } }, { .val = 0x00ffffffUL }, intersect_plane  },
+        { { .disk   = { {  -5,  -7, 10 }, normalize((Vector){ .5, .5,  1 }),  1 } }, { .val = 0x00ff00ffUL }, intersect_disk   },
+        { { .disk   = { {  -1,  -1,  8 }, normalize((Vector){ -1,  0, .5 }), .4 } }, { .val = 0x00ff00ffUL }, intersect_disk   },
         { 0 }
     };
+    Light lights[] = {
+        { { -5, 0, 7 } },
+        //{ {  0, 0, 15} },
+        { 0 }
+    };
+
+    int fd;
+    uint8_t *fbm;
+    struct fb_var_screeninfo vi;
+    struct fb_fix_screeninfo fi;
 
     if ((fd = open("/dev/fb0", O_RDWR))     < 0) return 1;
     if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) return 2;
     c.xres = vi.xres;
     c.yres = vi.yres;
 
-    render(c, objects, (Color){ .val = 0x00ffffff });
+    render(c, objects, lights, (Color){ .val = 0x00ffffff });
 
     munmap(c.buf, c.xres * c.yres * sizeof(Color));
     close(fd);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.