From 324de43f622ace14a51384cdf8bb7bb190b58699 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 17 Nov 2009 19:08:00 -0500 Subject: Implement phong shading. --- libdimension/dimension/finishes.h | 5 ++-- libdimension/finishes.c | 51 +++++++++++++++++++++++++++++++-------- libdimension/scene.c | 4 +++ tests/libdimension/tests.c | 10 ++++++-- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/libdimension/dimension/finishes.h b/libdimension/dimension/finishes.h index 5f00d43..e3d0597 100644 --- a/libdimension/dimension/finishes.h +++ b/libdimension/dimension/finishes.h @@ -25,7 +25,8 @@ #ifndef DIMENSION_FINISHES_H #define DIMENSION_FINISHES_H -/* A diffuse finish */ -dmnsn_finish *dmnsn_new_diffuse_finish(); +/* A phong finish */ +dmnsn_finish *dmnsn_new_phong_finish(double diffuse, double specular, + double exp); #endif /* DIMENSION_FINISHES_H */ diff --git a/libdimension/finishes.c b/libdimension/finishes.c index d70cfb7..a7cfaea 100644 --- a/libdimension/finishes.c +++ b/libdimension/finishes.c @@ -20,25 +20,56 @@ #include "dimension.h" #include /* For malloc */ +#include dmnsn_color -dmnsn_diffuse_finish_fn(const dmnsn_finish *finish, - dmnsn_color light, dmnsn_color color, - dmnsn_vector ray, dmnsn_vector normal, - dmnsn_vector viewer) +dmnsn_phong_finish_fn(const dmnsn_finish *finish, + dmnsn_color light, dmnsn_color color, + dmnsn_vector ray, dmnsn_vector normal, + dmnsn_vector viewer) { - double diffuse = dmnsn_vector_dot(ray, normal); - dmnsn_color illum = dmnsn_color_illuminate(light, color); - return dmnsn_color_mul(diffuse, illum); + double *params = finish->ptr; + + double diffuse = params[0]; + double specular = params[1]; + double exp = params[2]; + + /* Diffuse component */ + double diffuse_factor = diffuse*dmnsn_vector_dot(ray, normal); + dmnsn_color diffuse_color + = dmnsn_color_mul(diffuse_factor, dmnsn_color_illuminate(light, color)); + + /* Specular component */ + + dmnsn_vector proj = dmnsn_vector_mul(2*dmnsn_vector_dot(ray, normal), normal); + dmnsn_vector reflected = dmnsn_vector_sub(proj, ray); + + double specular_factor + = specular*pow(dmnsn_vector_dot(reflected, viewer), exp); + dmnsn_color specular_color = dmnsn_color_mul(specular_factor, light); + + return dmnsn_color_add(diffuse_color, specular_color); } -/* A diffuse finish */ +/* A phong finish */ dmnsn_finish * -dmnsn_new_diffuse_finish() +dmnsn_new_phong_finish(double diffuse, double specular, double exp) { dmnsn_finish *finish = dmnsn_new_finish(); if (finish) { - finish->finish_fn = &dmnsn_diffuse_finish_fn; + double *params = malloc(3*sizeof(double)); + if (!params) { + dmnsn_delete_finish(finish); + return NULL; + } + + params[0] = diffuse; + params[1] = specular; + params[2] = exp; + + finish->ptr = params; + finish->finish_fn = &dmnsn_phong_finish_fn; + finish->free_fn = &free; } return finish; } diff --git a/libdimension/scene.c b/libdimension/scene.c index 38b1d19..7a39679 100644 --- a/libdimension/scene.c +++ b/libdimension/scene.c @@ -28,6 +28,10 @@ dmnsn_new_scene() dmnsn_scene *scene = malloc(sizeof(dmnsn_scene)); if (scene) { scene->default_texture = dmnsn_new_texture(); + if (!scene->default_texture) { + dmnsn_delete_scene(scene); + return NULL; + } scene->camera = NULL; scene->canvas = NULL; diff --git a/tests/libdimension/tests.c b/tests/libdimension/tests.c index fe914f4..e5d4a06 100644 --- a/tests/libdimension/tests.c +++ b/tests/libdimension/tests.c @@ -31,7 +31,13 @@ dmnsn_new_default_scene() } /* Default finish */ - scene->default_texture->finish = dmnsn_new_diffuse_finish(); + + scene->default_texture->finish = dmnsn_new_phong_finish(1.0, 0.5, 50.0); + if (!scene->default_texture->finish) { + dmnsn_delete_scene(scene); + return NULL; + } + scene->default_texture->finish->ambient = 0.1; /* Background color */ @@ -116,7 +122,7 @@ dmnsn_new_default_scene() /* Now make a light */ dmnsn_light *light = dmnsn_new_point_light( - dmnsn_vector_construct(-5.0, 20.0, -5.0), + dmnsn_vector_construct(-15.0, 20.0, -5.0), dmnsn_white ); if (!light) { -- cgit v1.2.3