]> Dogcows Code - chaz/rasterize/blobdiff - scene.cc
basic ray tracing with hard shadows
[chaz/rasterize] / scene.cc
index f0635d800a6bc10de5a53aa6af8be680ce085443..a415ab084d0354342a420c3cd0a3876ca5d804f5 100644 (file)
--- a/scene.cc
+++ b/scene.cc
@@ -6,9 +6,13 @@
  */
 
 #include <cerrno>
+#include <cmath>
 
+#include "contact.hh"
 #include "light.hh"
-#include "list.hh"
+#include "plane.hh"
+#include "sphere.hh"
+#include "triangle.hh"
 #include "vec.hh"
 
 #include "scene.hh"
 static int _scene_add_light(scene_t* s, FILE* file);
 static int _scene_add_sphere(scene_t* s, FILE* file);
 static int _scene_add_plane(scene_t* s, FILE* file);
+static int _scene_add_triangle(scene_t* s, FILE* file);
 
 
 struct scene
 {
     int     w, h;
     vec_t   eye;
-    vec_t   spot;
-    vec_t   up;
+    vec_t   screenCenter;
+    vec_t   screenU;
+    vec_t   screenV;
     list_t* lights;
-    list_t* spheres;
-    list_t* planes;
+    list_t* objects;
     color_t ambient;
 };
 
@@ -47,16 +52,26 @@ scene_t* scene_alloc(FILE* file)
         return NULL;
     }
 
+    vec_t eye = vec_new(eyeX, eyeY, eyeZ);
+    vec_t spot = vec_new(spotX, spotY, spotZ);
+    vec_t up = vec_new(upX, upY, upZ);
+    scal_t d = S(1.0) / scal_tan((scal_t)fovy * S(0.5));
+
+    vec_t look = vec_normalize(vec_sub(spot, eye));
+    vec_t screenCenter = vec_scale(look, d);
+    vec_t screenU = vec_normalize(vec_cross(look, up));
+    vec_t screenV = vec_cross(screenU, look);
+    screenU = vec_scale(screenU, (scal_t)aspect);
+
     scene_t* s = (scene_t*)mem_alloc(sizeof(scene_t));
     s->w = w;
     s->h = h;
-    s->eye = vec_new(eyeX, eyeY, eyeZ);
-    s->spot = vec_new(spotX, spotY, spotZ);
-    s->up = vec_new(upX, upY, upZ);
-    // what to do with fovy and aspect...
+    s->eye = eye;
+    s->screenCenter = screenCenter;
+    s->screenU = screenU;
+    s->screenV = screenV;
     s->lights = NULL;
-    s->spheres = NULL;
-    s->planes = NULL;
+    s->objects = NULL;
     s->ambient = color_new((scal_t)aR, (scal_t)aG, (scal_t)aB, S(1.0));
 
     char type;
@@ -80,6 +95,12 @@ scene_t* scene_alloc(FILE* file)
                 }
                 break;
 
+            case 't':
+                if (_scene_add_triangle(s, file) != 0) {
+                    goto fail;
+                }
+                break;
+
             case 'X':
                 goto done;
 
@@ -87,11 +108,9 @@ scene_t* scene_alloc(FILE* file)
                 fprintf(stderr, "Unknown identifier: %c\n", type);
         }
     }
-#undef _ASSERT_G
 
 done:
-    if (s->spheres) list_reverse(&s->spheres);
-    if (s->planes) list_reverse(&s->planes);
+    if (s->objects) list_reverse(&s->objects);
     return s;
 
 fail:
@@ -102,8 +121,7 @@ fail:
 void scene_destroy(scene_t* s)
 {
     if (s->lights) list_destroy(&s->lights);
-    if (s->spheres) list_destroy(&s->spheres);
-    if (s->planes) list_destroy(&s->planes);
+    if (s->objects) list_destroy(&s->objects);
     mem_free(s);
 }
 
@@ -121,7 +139,6 @@ static int _scene_add_light(scene_t* s, FILE* file)
     }
     light_t* l = light_alloc(
             vec_new(lx, ly, lz),
-            color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0)),
             color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
     );
     list_push2(&s->lights, l, mem_free);
@@ -136,7 +153,12 @@ static int _scene_add_sphere(scene_t* s, FILE* file)
         fprintf(stderr, "Cannot read sphere values from scene.\n");
         return -1;
     }
-    /*list_push2(&s->spheres, s, mem_free);*/
+    rt::element* sphere = new rt::sphere(
+            vec_new((scal_t)x, (scal_t)y, (scal_t)z),
+            (scal_t)radius,
+            color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
+            );
+    list_push2(&s->objects, sphere, DTOR(rt::sphere_destroy));
     return 0;
 }
 
@@ -148,12 +170,51 @@ static int _scene_add_plane(scene_t* s, FILE* file)
         fprintf(stderr, "Cannot read plane values from scene.\n");
         return -1;
     }
-    /*list_push2(&s->planes, s, mem_free);*/
+    rt::element* plane = new rt::plane(
+            vec_new((scal_t)x, (scal_t)y, (scal_t)z),
+            vec_new((scal_t)nx, (scal_t)ny, (scal_t)nz),
+            color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
+            );
+    list_push2(&s->objects, plane, DTOR(rt::plane_destroy));
+    return 0;
+}
+
+static int _scene_add_triangle(scene_t* s, FILE* file)
+{
+    double x1, y1, z1, x2, y2, z2, x3, y3, z3, r, g, b;
+    if (fscanf(file, " %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf %lf",
+               &x1, &y1, &z1, &x2, &y2, &z2, &x3, &y3, &z3, &r, &g, &b) != 12) {
+        fprintf(stderr, "Cannot read triangle values from scene.\n");
+        return -1;
+    }
+    rt::element* triangle = new rt::triangle(
+            vec_new((scal_t)x1, (scal_t)y1, (scal_t)z1),
+            vec_new((scal_t)x2, (scal_t)y2, (scal_t)z2),
+            vec_new((scal_t)x3, (scal_t)y3, (scal_t)z3),
+            color_new((scal_t)r, (scal_t)g, (scal_t)b, S(1.0))
+            );
+    list_push2(&s->objects, triangle, DTOR(rt::triangle_destroy));
     return 0;
 }
 
 
-raster_t* scene_render(scene_t* s)
+list_t* scene_elements(const scene_t* s)
+{
+    return s->objects;
+}
+
+list_t* scene_lights(const scene_t* s)
+{
+    return s->lights;
+}
+
+color_t scene_ambient(const scene_t* s)
+{
+    return s->ambient;
+}
+
+
+raster_t* scene_render(const scene_t* s)
 {
 #if VERBOSITY >= 3
     timer_start();
@@ -169,7 +230,37 @@ raster_t* scene_render(scene_t* s)
     printf("rendering scene...\n");
 #endif
 
-    // RENDER IT
+    scal_t wh = S(2.0) / (scal_t)s->w;
+    scal_t hh = S(2.0) / (scal_t)s->h;
+
+    for (int y = 0; y < s->h; ++y) {
+        for (int x = 0; x < s->w; ++x) {
+            color_t* pixel = raster_color(p, x, y);
+            scal_t u = (scal_t)x * wh - S(1.0);
+            scal_t v = (scal_t)y * hh - S(1.0);
+            vec_t rayDirection = vec_add2(s->screenCenter,
+                    vec_scale(s->screenU, u), vec_scale(s->screenV, v));
+
+            ray_t ray = ray_normalize(ray_new(s->eye, rayDirection));
+
+            rt::element*    nearestObj = 0;
+            contact_t       nearestHit;
+
+            // find the nearest object along the ray
+            for (list_t* i = s->objects; i; i = i->link) {
+                rt::element*    obj = (rt::element*)i->val;
+                contact_t       hit;
+                if (obj->intersect(ray, hit) && (!nearestObj || hit.d < nearestHit.d)) {
+                    nearestObj = obj;
+                    nearestHit = hit;
+                }
+            }
+
+            if (nearestObj) {
+                *pixel = nearestObj->cast(nearestHit, s);
+            }
+        }
+    }
 
 #if VERBOSITY >= 3
     long dt = timer_stop();
This page took 0.024639 seconds and 4 git commands to generate.