From a432d0ec1a03d7821e40f2499bea08f65ee71e6f Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 9 Nov 2009 16:17:19 -0500 Subject: Use finishes. --- libdimension/dimension.h | 1 + libdimension/dimension/scene.h | 1 + libdimension/kD_splay_tree.c | 11 +-- libdimension/raytrace.c | 153 +++++++++++++++++++++++++---------------- tests/libdimension/tests.c | 3 + 5 files changed, 104 insertions(+), 65 deletions(-) diff --git a/libdimension/dimension.h b/libdimension/dimension.h index 7fc25c5..d6affc2 100644 --- a/libdimension/dimension.h +++ b/libdimension/dimension.h @@ -70,6 +70,7 @@ typedef void dmnsn_free_fn(void *ptr); #include #include #include +#include #include #include #include diff --git a/libdimension/dimension/scene.h b/libdimension/dimension/scene.h index e3f9662..8108b2b 100644 --- a/libdimension/dimension/scene.h +++ b/libdimension/dimension/scene.h @@ -30,6 +30,7 @@ typedef enum { DMNSN_RENDER_OBJECTS, DMNSN_RENDER_PIGMENT, DMNSN_RENDER_LIGHTS, + DMNSN_RENDER_FINISH, DMNSN_RENDER_FULL } dmnsn_quality; diff --git a/libdimension/kD_splay_tree.c b/libdimension/kD_splay_tree.c index 77e57dd..924d3a9 100644 --- a/libdimension/kD_splay_tree.c +++ b/libdimension/kD_splay_tree.c @@ -356,10 +356,13 @@ dmnsn_kD_splay_search_recursive(dmnsn_kD_splay_node *node, dmnsn_line ray, result.intersection = result_temp.intersection; t = result.intersection->t; - /* Transform the normal vector back to the observer's view */ - result.intersection->normal = dmnsn_matrix_vector_mul( - node->object->trans, - result.intersection->normal + /* Transform the intersection back to the observer's view */ + result.intersection->ray = ray; + result.intersection->normal = dmnsn_vector_normalize( + dmnsn_matrix_vector_mul( + node->object->trans, + result.intersection->normal + ) ); } else { dmnsn_delete_intersection(result_temp.intersection); diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c index 262929f..63385a7 100644 --- a/libdimension/raytrace.c +++ b/libdimension/raytrace.c @@ -254,6 +254,95 @@ dmnsn_raytrace_scene_impl(dmnsn_progress *progress, dmnsn_scene *scene, return 0; } +static dmnsn_color +dmnsn_raytrace_pigment(dmnsn_intersection *intersection, dmnsn_scene *scene) +{ + /* Default to black if there's no texture/pigment */ + dmnsn_color color = dmnsn_black; + + /* Use the default texture if given a NULL texture */ + const dmnsn_texture *texture = intersection->texture ? intersection->texture + : scene->default_texture; + + if (texture) { + /* Use the default pigment if given a NULL pigment */ + const dmnsn_pigment *pigment + = texture->pigment ? texture->pigment + : scene->default_texture->pigment; + + if (pigment) { + color = (*pigment->pigment_fn)( + pigment, + dmnsn_line_point(intersection->ray, intersection->t) + ); + } + } + + return color; +} + +static dmnsn_color +dmnsn_raytrace_shadow(dmnsn_intersection *intersection, dmnsn_scene *scene, + dmnsn_kD_splay_tree *kD_splay_tree, dmnsn_color color) +{ + /* Use the default texture if given a NULL texture */ + const dmnsn_texture *texture = intersection->texture ? intersection->texture + : scene->default_texture; + + const dmnsn_finish *finish = NULL; + if (texture) { + /* Use the default finish if given a NULL finish */ + finish = texture->finish ? texture->finish : scene->default_texture->finish; + } + + 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(intersection->ray, intersection->t); + dmnsn_line shadow_ray = dmnsn_line_construct( + /* Add epsilon*(light->x0 - x0) to avoid hitting ourself with the shadow + ray */ + dmnsn_vector_add( + x0, + dmnsn_vector_mul(1.0e-9, 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 normal = intersection->normal; + dmnsn_vector reflected = dmnsn_vector_normalize( + dmnsn_vector_add( + dmnsn_vector_normalize(dmnsn_vector_sub(intersection->ray.x0, x0)), + dmnsn_vector_normalize(dmnsn_vector_sub(light->x0, x0)) + ) + ); + + dmnsn_color effective + = dmnsn_color_illuminate((*light->light_fn)(light, x0), color); + + if (scene->quality >= DMNSN_RENDER_FINISH && finish) { + illum = dmnsn_color_add((*finish->finish_fn)(finish, effective, x0, + normal, reflected), + illum); + } else { + illum = effective; + } + } + + dmnsn_delete_intersection(shadow_caster); + } + + return illum; +} + /* Shoot a ray, and calculate the color, using `color' as the background */ static dmnsn_color dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene, @@ -262,75 +351,17 @@ dmnsn_raytrace_shoot(dmnsn_line ray, dmnsn_scene *scene, dmnsn_intersection *intersection = dmnsn_kD_splay_search(kD_splay_tree, ray); if (intersection) { - /* Default to black if we have no texture/pigment */ + /* Default to black if we aren't rendering pigments */ color = dmnsn_black; if (scene->quality >= DMNSN_RENDER_PIGMENT) { - /* Use the default texture if given a NULL texture */ - const dmnsn_texture *texture - = intersection->texture ? intersection->texture - : scene->default_texture; - - if (texture) { - /* Use the default pigment if given a NULL pigment */ - const dmnsn_pigment *pigment - = texture->pigment ? texture->pigment - : scene->default_texture->pigment; - - if (pigment) { - color = (*pigment->pigment_fn)( - pigment, - dmnsn_line_point(intersection->ray, intersection->t) - ); - } - } + color = dmnsn_raytrace_pigment(intersection, 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 = intersection->normal; - 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 - ); - } - - dmnsn_delete_intersection(shadow_caster); - } - - color = illum; + color = dmnsn_raytrace_shadow(intersection, scene, kD_splay_tree, color); } - /* Delete the intersection */ dmnsn_delete_intersection(intersection); } diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c index d79434d..1e8cd5c 100644 --- a/tests/libdimension/tests.c +++ b/tests/libdimension/tests.c @@ -30,6 +30,9 @@ dmnsn_new_default_scene() return NULL; } + /* Default finish */ + scene->default_texture->finish = dmnsn_new_specular_finish(); + /* Background color */ dmnsn_sRGB sRGB = { .R = 0.0, .G = 0.0, .B = 0.1 }; scene->background = dmnsn_color_from_sRGB(sRGB); -- cgit v1.2.3