add phong interpolation (lighting)
authorCharles McGarvey <chazmcgarvey@brokenzipper.com>
Tue, 14 Feb 2012 21:20:46 +0000 (14:20 -0700)
committerCharles McGarvey <chazmcgarvey@brokenzipper.com>
Tue, 14 Feb 2012 21:20:46 +0000 (14:20 -0700)
Makefile
animate.lua
config.h
mat.h
raster.c
scene.c
tri.h
vec.h

index 7d119e4061dbf22bde738697f72d7b1a1f010e76..aaac3cdb00cbc2abae65126413b024b3f0840108 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,5 +36,5 @@ debug: $(PROJECT)
 -include $(DEPS)
 $(OBJS): Makefile
 
-.PHONY: all clean distclean run debug
+.PHONY: all clean distclean dist run debug
 
index 476051ff8fb08accdd01018703df710b99e010f2..9917cb148f9f2187a920917b45abc4d321b5e653 100755 (executable)
@@ -15,7 +15,7 @@
 local size = {w = 640, h = 480}
 
 -- Set the number of frames to be rendered for the animation.
-local frames = 512
+local frames = 360
 
 -- Define the code to calculate where the camera is, in world coordinates.
 local eye = function(frame)
@@ -47,6 +47,7 @@ c 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1
 t 2 0 -2
 s 1 1 1
 g dragon.raw
+M 0.3 0.3 0.3 5
 c 0.7 0.3 0.2 0.8 0.2 0.1 0.9 0.2 0.2
 t -2 -1 -2
 s 2 2 2
@@ -55,10 +56,12 @@ c 0.1 0.2 0.7 0.1 0.3 0.9 0.2 0.1 0.8
 t 2 -1.5 2
 s 10 10 10
 g bunny.raw
+M 0.2 0.2 0.2 1
 c 0.9 0.8 0.9 0.8 0.7 0.9 0.9 0.8 0.7
 t -2 -1 2
 s 10 10 10
 g teapot2.raw
+M 1 1 1 128
 c 0 1 0 0 1 0 0 1 0
 t 0 -1 0
 s 0.6 0.6 0.6
index 9637deae9233ea9d0e21a67dcc53ca4cfc786c99..a1d7fb9636dfb899bfcd0b90e5cf45f5a0e75ae3 100644 (file)
--- a/config.h
+++ b/config.h
 #define IF_DEPTH_TEST(X)
 #endif
 
+/*
+ * DOUBLE_FLOAT
+ * If enabled, scalars will be of type double.  This provides and insane level
+ * of precision at a performance cost.  The default behavior just uses floats.
+ */
+#if DOUBLE_FLOAT
+#define IF_DOUBLE_FLOAT(X) X
+#else
+#define IF_DOUBLE_FLOAT(X)
+#endif
+
 /*
  * EXPORT_BMP
  * If enabled, each scene rasterization will be saved as a BMP image file.
  * LIGHTING
  * If enabled, local lighting will be used to increase realism of the scene.
  * This option has a performance cost, but it can produce interesting visuals.
- * The behavior of this option also depends on the SMOOTH_COLOR option and
- * whether or not the model has unique vertex normals; if SMOOTH_COLOR is
- * disabled, each triangle will be shaded a flat color.  If it is enabled,
- * Gouraud interpolation is used to smooth the lighting across the face of
- * each triangle.  See the PRE_NORMALS and SMOOTH_COLOR options.
+ * The behavior of this option is effected by its precise value:
+ *   1 Phong lighting model with flat (per-face) interpolation.
+ *   2 Phong lighting model with Gouraud (per-vertex) interpolation.
+ *   3 Phong lighting model with Phong (per-pixel) interpolation.
  */
 #if LIGHTING
 #define IF_LIGHTING(X) X
diff --git a/mat.h b/mat.h
index 499d09261697a8c02261c7ac94844475ef507f07..c188723346fce7faeec94210a2eca2d9a61fa042 100644 (file)
--- a/mat.h
+++ b/mat.h
@@ -237,22 +237,16 @@ mat_t MAT_ROTATE_Z(scal_t theta)
 INLINE_MAYBE
 mat_t MAT_ROTATE(scal_t theta, scal_t x, scal_t y, scal_t z)
 {
-    /*
-     * This code is an implementation of an algorithm described by Glenn
-     * Murray at http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/
-     */
     vec_t v = vec_normalize(vec_new(x, y, z));
     x = v.x;
     y = v.y;
     z = v.z;
-    scal_t sin_a = scal_sin(theta);
-    scal_t cos_a = scal_cos(theta);
-    scal_t x2 = x * x;
-    scal_t y2 = y * y;
-    scal_t z2 = z * z;
-    return mat_new(x2+(S(1.0)-x2)*cos_a, x*y*(S(1.0)-cos_a)-z*sin_a, x*z*(S(1.0)-cos_a)+y*sin_a, S(0.0),
-                   x*y*(S(1.0)-cos_a)+z*sin_a, y2+(S(1.0)-y2)*cos_a, y*z*(S(1.0)-cos_a)-y*sin_a, S(0.0),
-                   x*z*(S(1.0)-cos_a)-y*sin_a, y*z*(S(1.0)-cos_a)+x*sin_a, z2+(S(1.0)-z2)*cos_a, S(0.0),
+    scal_t c = scal_cos(-theta);
+    scal_t s = scal_sin(-theta);
+    scal_t t = S(1.0) - c;
+    return mat_new(t * x * x + c, t * x * y + s * z, t * x * z - s * y, S(0.0),
+                   t * x * y - s * z, t * y * y + c, t * y * z + s * x, S(0.0),
+                   t * x * z + s * y, t * y * z - s * x, t * z * z + c, S(0.0),
                    S(0.0), S(0.0), S(0.0), S(1.0));
 }
 
index aca2c5a860315c0cc70f44c8cab3069fb1ce0441..766e6ea7ba4ce6cb22ad0b687e5eccd8bc377c0e 100644 (file)
--- a/raster.c
+++ b/raster.c
@@ -61,7 +61,7 @@ raster_t* raster_alloc(int width, int height, color_t fill)
     p->specular = COLOR_WHITE;
     p->shininess = S(1.0);
 #endif
- /*= light_new(COLOR_WHITE, vec_new(S(-2.0), S(4.0), S(0.0)));*/
+
     p->zbuf = (scal_t*)mem_alloc(sizeof(scal_t) * size);
     for (size_t i = 0; i < size; ++i) {
         p->zbuf[i] = S(1.0);
@@ -304,7 +304,7 @@ bool _try_cull_backface(tri_t t)
  * Determine what color is associated with the given vertex.
  */
 INLINE_MAYBE
-color_t _get_vertex_color(raster_t* p, vert_t vert)
+color_t _do_phong_lighting(raster_t* p, vert_t vert)
 {
 #if LIGHTING
     color_t color = COLOR_BLACK;
@@ -315,7 +315,7 @@ color_t _get_vertex_color(raster_t* p, vert_t vert)
         vec_t   vpos = p->eye;
         vec_t   n = vert.n;
         vec_t   l = vec_normalize(vec_sub(lpos, mpos));
-        vec_t   r = vec_sub(vec_scale(n, S(2.0) * vec_dot(n, l)), l);
+        vec_t   r = vec_normalize(vec_sub(vec_scale(n, S(2.0) * vec_dot(n, l)), l));
         vec_t   v = vec_normalize(vec_sub(vpos, mpos));
 
         scal_t  kd = scal_max(vec_dot(l, n), S(0.0));
@@ -364,17 +364,34 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle)
         return;
     }
 
-    tri_t   temp = tri_transform(*triangle, p->model);
-#if LIGHTING && (!PRE_NORMALS || (!SMOOTH_COLOR && PRE_NORMALS >= 2))
-    temp.a.n = temp.b.n = temp.c.n = vec_normalize(tri_normal(temp));
+#if LIGHTING >= 1
+    tri_t tl = tri_transform(*triangle, p->model);
+#if !PRE_NORMALS
+    tl.a.n = tl.b.n = tl.c.n = vec_normalize(tri_normal(tl));
 #endif
-#if !SMOOTH_COLOR
-    temp.a.c = tri_color(temp);
 #endif
-    color_t color1 = _get_vertex_color(p, temp.a);
-#if SMOOTH_COLOR
-    color_t color2 = _get_vertex_color(p, temp.b);
-    color_t color3 = _get_vertex_color(p, temp.c);
+
+#if LIGHTING == 1
+    vert_t tv = vert_new(tri_midpoint(tl));
+    tv.n = vec_normalize(tri_normal(tl));
+    tv.c = tri_color(tl);
+    color_t color = _do_phong_lighting(p, tv);
+#elif LIGHTING == 2 && SMOOTH_COLOR
+    color_t color1 = _do_phong_lighting(p, tl.a);
+    color_t color2 = _do_phong_lighting(p, tl.b);
+    color_t color3 = _do_phong_lighting(p, tl.c);
+#elif LIGHTING == 2 && !SMOOTH_COLOR
+    color_t c = tri_color(t);
+    tl.a.c = tl.b.c = tl.c.c = c;
+    color_t color1 = _do_phong_lighting(p, tl.a);
+    color_t color2 = _do_phong_lighting(p, tl.b);
+    color_t color3 = _do_phong_lighting(p, tl.c);
+#elif !LIGHTING && SMOOTH_COLOR
+    color_t color1 = t.a.c;
+    color_t color2 = t.b.c;
+    color_t color3 = t.c.c;
+#else
+    color_t color = tri_color(t);
 #endif
 
     for (int y = bottom; y < top; ++y) {
@@ -388,11 +405,20 @@ void raster_draw_tri(raster_t* p, const tri_t* triangle)
                 if (S(-1.0) < v.z && v.z < *n) {
 #endif
                     color_t* c = p->pixels + y * p->w + x;
-#if SMOOTH_COLOR
+
+#if LIGHTING == 2 || (!LIGHTING && SMOOTH_COLOR)
                     *c = color_interp2(color1, color2, color3, b);
+#elif LIGHTING == 3 && SMOOTH_COLOR
+                    *c = _do_phong_lighting(p, tri_interp(tl, b));
+#elif LIGHTING == 3 && !SMOOTH_COLOR
+                    vert_t d = vert_new(tri_point(t, b));
+                    d.c = tri_color(t);
+                    d.n = tri_normal2(t, b);
+                    *c = _do_phong_lighting(p, d);
 #else
-                    *c = color1;
+                    *c = color;
 #endif
+
 #if DEPTH_TEST
                     *n = v.z;
                 }
diff --git a/scene.c b/scene.c
index be185113988fc11ecc7e840763d22f9aa46c14f8..326091fea49b0b50e5a42f3d167c0af666f91d3b 100644 (file)
--- a/scene.c
+++ b/scene.c
@@ -100,13 +100,13 @@ typedef struct _group _group_t;
  */
 static int _group_try_read_cache(const char* filename, list_t** l)
 {
+    int     count = 0;
     char*   cachename  = mem_strcat(".", filename);
     FILE*   file = fopen(cachename, "rb");
     if (file == NULL) {
         goto fail;
     }
 
-    int count = 0;
     _CHECK_IO(fread(&count, sizeof(count), 1, file));
 
     float x1, y1, z1, x2, y2, z2, x3, y3, z3;
diff --git a/tri.h b/tri.h
index de36ae66a8988a3ddd78492e1093e9b6f3d2445e..ce0977b5c7382d7d61867b4f463c99d641effda1 100644 (file)
--- a/tri.h
+++ b/tri.h
@@ -71,6 +71,10 @@ tri_t tri_transform(tri_t t, mat_t m)
     t.a.v = mat_apply(m, t.a.v);
     t.b.v = mat_apply(m, t.b.v);
     t.c.v = mat_apply(m, t.c.v);
+    t.a.n.w = t.b.n.w = t.c.n.w = S(0.0);
+    t.a.n = vec_normalize(mat_apply(m, t.a.n));
+    t.b.n = vec_normalize(mat_apply(m, t.b.n));
+    t.c.n = vec_normalize(mat_apply(m, t.c.n));
     return t;
 }
 
@@ -93,7 +97,8 @@ tri_t tri_homodiv(tri_t t)
 INLINE_MAYBE
 vec_t tri_normal(tri_t t)
 {
-    return vec_cross(vec_sub(t.b.v, t.a.v), vec_sub(t.c.v, t.a.v));
+    vec_t n = vec_cross(vec_sub(t.b.v, t.a.v), vec_sub(t.c.v, t.a.v));
+    return n;
 }
 
 
@@ -137,15 +142,6 @@ bool tri_barycentric(tri_t t, scal_t* b, vec_t v)
 }
 
 
-/*
- * Get an interpolated z-value at the barycentric coordinates.
- */
-INLINE_MAYBE
-scal_t tri_z(tri_t t, scal_t b[3])
-{
-    return t.a.v.z * b[0] + t.b.v.z * b[1] + t.c.v.z * b[2];
-}
-
 /*
  * Find the midpoint of the triangle.
  */
@@ -168,5 +164,46 @@ color_t tri_color(tri_t t)
 }
 
 
+/*
+ * Get an interpolated z-value at the barycentric coordinates.
+ */
+INLINE_MAYBE
+scal_t tri_z(tri_t t, scal_t b[3])
+{
+    return t.a.v.z * b[0] + t.b.v.z * b[1] + t.c.v.z * b[2];
+}
+
+/*
+ * Calculate an interpolated point.
+ */
+INLINE_MAYBE
+vec_t tri_point(tri_t t, scal_t b[3])
+{
+    return vec_interp(t.a.v, t.b.v, t.c.v, b);
+}
+
+/*
+ * Calculate an interpolated normal.
+ */
+INLINE_MAYBE
+vec_t tri_normal2(tri_t t, scal_t b[3])
+{
+    return vec_normalize(vec_interp(t.a.n, t.b.n, t.c.n, b));
+}
+
+/*
+ * Calculate an entirely new vertex within the triangle based on barycentric
+ * coordinates.
+ */
+INLINE_MAYBE
+vert_t tri_interp(tri_t t, scal_t b[3])
+{
+    vert_t v = vert_new(tri_point(t, b));
+    v.c = color_interp2(t.a.c, t.b.c, t.c.c, b);
+    v.n = tri_normal2(t, b);
+    return v;
+}
+
+
 #endif // _TRI_H_
 
diff --git a/vec.h b/vec.h
index 614e31dfec4c0e68bdbcb5b08ae0be7399ef4ef7..48635238202c5de1a437161028112bf1085352c1 100644 (file)
--- a/vec.h
+++ b/vec.h
@@ -57,10 +57,11 @@ vec_t vec_new(scal_t x, scal_t y, scal_t z)
     return vec_new2(x, y, z, S(1.0));
 }
 
-#define VEC_ZERO    vec_new(S(0.0), S(0.0), S(0.0))
-#define VEC_ORTHO_X vec_new(S(1.0), S(0.0), S(0.0))
-#define VEC_ORTHO_Y vec_new(S(0.0), S(1.0), S(0.0))
-#define VEC_ORTHO_Z vec_new(S(0.0), S(0.0), S(1.0))
+#define VEC_ZERO      vec_new(S(0.0), S(0.0), S(0.0))
+#define VEC_ORTHO_X   vec_new(S(1.0), S(0.0), S(0.0))
+#define VEC_ORTHO_Y   vec_new(S(0.0), S(1.0), S(0.0))
+#define VEC_ORTHO_Z   vec_new(S(0.0), S(0.0), S(1.0))
+#define VEC_ZERO_FREE vec_new2(S(0.0), S(0.0), S(0.0), S(0.0))
 
 
 /*
@@ -155,6 +156,15 @@ vec_t vec_add(vec_t a, vec_t b)
     return a;
 }
 
+/*
+ * Add three vectors together.
+ */
+INLINE_MAYBE
+vec_t vec_add2(vec_t a, vec_t b, vec_t c)
+{
+    return vec_add(vec_add(a, b), c);
+}
+
 /*
  * Subtract a vector from another vector.
  */
@@ -239,5 +249,18 @@ vec_t vec_homodiv(vec_t v)
 }
 
 
+/*
+ * Interpolate smoothly between three vectors with barycentric coordinates.
+ */
+INLINE_MAYBE
+vec_t vec_interp(vec_t v1, vec_t v2, vec_t v3, scal_t b[3])
+{
+    return vec_new(v1.x * b[0] + v2.x * b[1] + v3.x * b[2],
+                   v1.y * b[0] + v2.y * b[1] + v3.y * b[2],
+                   v1.z * b[0] + v2.z * b[1] + v3.z * b[2]);
+}
+
+
+
 #endif // _VEC_H_
 
This page took 0.039531 seconds and 4 git commands to generate.