diff options
-rw-r--r-- | libdimension/color.c | 56 | ||||
-rw-r--r-- | libdimension/dimension/color.h | 6 | ||||
-rw-r--r-- | libdimension/dimension/scene.h | 1 | ||||
-rw-r--r-- | libdimension/raytrace.c | 66 | ||||
-rw-r--r-- | tests/libdimension/tests.c | 2 |
5 files changed, 109 insertions, 22 deletions
diff --git a/libdimension/color.c b/libdimension/color.c index 7fb73ed..374a0a0 100644 --- a/libdimension/color.c +++ b/libdimension/color.c @@ -263,17 +263,14 @@ dmnsn_sRGB_from_color(dmnsn_color color) dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) { - dmnsn_CIE_Lab Lab, Lab1, Lab2; - dmnsn_color ret; - - Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint); - Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint); + dmnsn_CIE_Lab Lab1 = dmnsn_Lab_from_color(color1, dmnsn_whitepoint); + dmnsn_CIE_Lab Lab2 = dmnsn_Lab_from_color(color2, dmnsn_whitepoint); - Lab.L = Lab1.L + Lab2.L; - Lab.a = Lab1.a + Lab2.a; - Lab.b = Lab1.b + Lab2.b; + dmnsn_CIE_Lab Lab = { .L = Lab1.L + Lab2.L, + .a = Lab1.a + Lab2.a, + .b = Lab1.b + Lab2.b }; - ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint); + dmnsn_color ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint); /* Weighted average of transparencies by intensity */ ret.filter = (Lab1.L*color1.filter + Lab2.L*color2.filter)/Lab.L; ret.trans = (Lab1.L*color1.trans + Lab2.L*color2.trans)/Lab.L; @@ -281,6 +278,47 @@ dmnsn_color_add(dmnsn_color color1, dmnsn_color color2) return ret; } +/* Multiply a color by a scalar */ +dmnsn_color +dmnsn_color_mul(double n, dmnsn_color color) +{ + dmnsn_CIE_Lab Lab = dmnsn_Lab_from_color(color, dmnsn_whitepoint); + double LabL = Lab.L; + Lab.L *= n; + Lab.a *= n; + Lab.b *= n; + + dmnsn_color ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint); + ret.filter = color.filter; + ret.trans = color.trans; + + return ret; +} + +/* Illuminates `color' with `light' */ +dmnsn_color +dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color) +{ + dmnsn_CIE_Lab Lab1 = dmnsn_Lab_from_color(light, dmnsn_whitepoint); + dmnsn_CIE_Lab Lab2 = dmnsn_Lab_from_color(color, dmnsn_whitepoint); + + double dot = Lab1.L*Lab2.L + Lab1.a*Lab2.a + Lab1.b*Lab2.b; + double norm = sqrt(Lab2.L*Lab2.L + Lab2.a*Lab2.a + Lab2.b*Lab2.b); + + if (norm == 0.0) + return dmnsn_black; + + dmnsn_CIE_Lab Lab = { .L = dot*Lab2.L/norm/100.0, + .a = dot*Lab2.a/norm, + .b = dot*Lab2.b/norm }; + + dmnsn_color ret = dmnsn_color_from_Lab(Lab, dmnsn_whitepoint); + ret.filter = color.filter; + ret.trans = color.trans; + + return ret; +} + /* Find the perceptual difference between two colors, using CIE L*a*b*. */ double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2) diff --git a/libdimension/dimension/color.h b/libdimension/dimension/color.h index ab2ea04..a72de98 100644 --- a/libdimension/dimension/color.h +++ b/libdimension/dimension/color.h @@ -80,10 +80,10 @@ dmnsn_CIE_Lab dmnsn_Lab_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); dmnsn_CIE_Luv dmnsn_Luv_from_color(dmnsn_color color, dmnsn_CIE_XYZ white); dmnsn_sRGB dmnsn_sRGB_from_color(dmnsn_color color); -/* Perceptually correct color combination */ +/* Perceptual color manipulation */ dmnsn_color dmnsn_color_add(dmnsn_color color1, dmnsn_color color2); - -/* Perceptual color difference */ +dmnsn_color dmnsn_color_mul(double n, dmnsn_color color); +dmnsn_color dmnsn_color_illuminate(dmnsn_color light, dmnsn_color color); double dmnsn_color_difference(dmnsn_color color1, dmnsn_color color2); #endif /* DIMENSION_COLOR_H */ diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h index 8c9c705..e3f9662 100644 --- a/libdimension/dimension/scene.h +++ b/libdimension/dimension/scene.h @@ -29,6 +29,7 @@ typedef enum { DMNSN_RENDER_NONE, DMNSN_RENDER_OBJECTS, DMNSN_RENDER_PIGMENT, + DMNSN_RENDER_LIGHTS, DMNSN_RENDER_FULL } dmnsn_quality; diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c index 6cb6d8b..da78411 100644 --- a/libdimension/raytrace.c +++ b/libdimension/raytrace.c @@ -259,11 +259,7 @@ static dmnsn_color dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene, dmnsn_kD_splay_tree *kD_splay_tree, dmnsn_color color) { - dmnsn_intersection *intersection; - const dmnsn_texture *texture; - const dmnsn_pigment *pigment; - - intersection = dmnsn_kD_splay_search(kD_splay_tree, ray); + dmnsn_intersection *intersection = dmnsn_kD_splay_search(kD_splay_tree, ray); if (intersection) { /* Default to black if we have no texture/pigment */ @@ -271,13 +267,15 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene, if (scene->quality >= DMNSN_RENDER_PIGMENT) { /* Use the default texture if given a NULL texture */ - texture = intersection->texture ? intersection->texture - : scene->default_texture; + const dmnsn_texture *texture + = intersection->texture ? intersection->texture + : scene->default_texture; if (texture) { /* Use the default pigment if given a NULL pigment */ - pigment = texture->pigment ? texture->pigment - : scene->default_texture->pigment; + const dmnsn_pigment *pigment + = texture->pigment ? texture->pigment + : scene->default_texture->pigment; if (pigment) { color = (*pigment->pigment_fn)( @@ -288,6 +286,56 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene, } } + if (scene->quality >= DMNSN_RENDER_LIGHTS) { + dmnsn_color illum = dmnsn_color_mul(0.3, color); + + const dmnsn_light *light; + unsigned int i; + + for (i = 0; i < dmnsn_array_size(scene->lights); ++i) { + dmnsn_array_get(scene->lights, i, &light); + dmnsn_vector x0 = dmnsn_line_point(ray, intersection->t); + dmnsn_line shadow_ray = dmnsn_line_construct( + dmnsn_vector_add( + x0, + dmnsn_vector_mul(1.0e-6, dmnsn_vector_sub(light->x0, x0)) + ), + dmnsn_vector_sub(light->x0, x0) + ); + + dmnsn_intersection *shadow_caster + = dmnsn_kD_splay_search(kD_splay_tree, shadow_ray); + + if (!shadow_caster || shadow_caster->t > 1.0) { + dmnsn_vector object_normal = x0; + dmnsn_vector normal = dmnsn_vector_normalize( + dmnsn_vector_add( + dmnsn_vector_normalize(dmnsn_vector_sub(ray.x0, x0)), + dmnsn_vector_normalize(dmnsn_vector_sub(light->x0, x0)) + ) + ); + + illum = dmnsn_color_add( + dmnsn_color_mul( + dmnsn_vector_dot(normal, object_normal), + dmnsn_color_illuminate((*light->light_fn)(light, x0), color) + ), + illum + ); + illum = dmnsn_color_add( + dmnsn_color_mul( + 0.1*dmnsn_vector_dot(normal, object_normal), + dmnsn_color_illuminate((*light->light_fn)(light, x0), dmnsn_white) + ), + illum + ); + } + + dmnsn_delete_intersection(shadow_caster); + color = illum; + } + } + /* Delete the intersection */ dmnsn_delete_intersection(intersection); } diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c index 5a0b4cf..1257219 100644 --- a/tests/libdimension/tests.c +++ b/tests/libdimension/tests.c @@ -116,7 +116,7 @@ dmnsn_new_default_scene() /* Now make a light */ dmnsn_light *light = dmnsn_new_point_light( - dmnsn_vector_construct(0.0, 3.0, 0.0), + dmnsn_vector_construct(-5.0, 20.0, -5.0), dmnsn_white ); if (!light) { |