chapter 8
This commit is contained in:
parent
617adaf2a1
commit
e312755e3d
2
camera.h
2
camera.h
@ -68,7 +68,7 @@ void camera_render(struct camera * camera, struct world * world, struct canvas *
|
|||||||
for (int y = 0; y < camera->vsize; y++) {
|
for (int y = 0; y < camera->vsize; y++) {
|
||||||
for (int x = 0; x < camera->hsize; x++) {
|
for (int x = 0; x < camera->hsize; x++) {
|
||||||
struct ray ray = camera_ray_for_pixel(camera, x, y);
|
struct ray ray = camera_ray_for_pixel(camera, x, y);
|
||||||
struct tuple color = color_at(world, ray);
|
struct tuple color = world_color_at(world, ray);
|
||||||
canvas_write_pixel(canvas, x, y, color);
|
canvas_write_pixel(canvas, x, y, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
float.h
3
float.h
@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
|
static const float epsilon = 0.00001;
|
||||||
|
|
||||||
inline static bool float_equal(float a, float b)
|
inline static bool float_equal(float a, float b)
|
||||||
{
|
{
|
||||||
const float epsilon = 0.00001;
|
|
||||||
return fabsf(a - b) < epsilon;
|
return fabsf(a - b) < epsilon;
|
||||||
}
|
}
|
||||||
|
@ -118,6 +118,7 @@ struct computations {
|
|||||||
struct tuple eyev;
|
struct tuple eyev;
|
||||||
struct tuple normalv;
|
struct tuple normalv;
|
||||||
bool inside;
|
bool inside;
|
||||||
|
struct tuple over_point;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline static struct computations prepare_computations(struct intersection intersection, struct ray ray)
|
inline static struct computations prepare_computations(struct intersection intersection, struct ray ray)
|
||||||
@ -132,12 +133,15 @@ inline static struct computations prepare_computations(struct intersection inter
|
|||||||
normalv = tuple_neg(normalv);
|
normalv = tuple_neg(normalv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tuple over_point = tuple_add(point, tuple_mul(normalv, epsilon * 100));
|
||||||
|
|
||||||
return (struct computations){
|
return (struct computations){
|
||||||
intersection.t,
|
intersection.t,
|
||||||
intersection.object,
|
intersection.object,
|
||||||
point,
|
point,
|
||||||
eyev,
|
eyev,
|
||||||
normalv,
|
normalv,
|
||||||
inside
|
inside,
|
||||||
|
over_point
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
23
materials.h
23
materials.h
@ -37,7 +37,8 @@ inline static struct tuple lighting(struct material material,
|
|||||||
struct light light,
|
struct light light,
|
||||||
struct tuple point,
|
struct tuple point,
|
||||||
struct tuple eyev,
|
struct tuple eyev,
|
||||||
struct tuple normalv)
|
struct tuple normalv,
|
||||||
|
bool in_shadow)
|
||||||
{
|
{
|
||||||
struct tuple effective_color = hadmard_product(material.color, light.intensity);
|
struct tuple effective_color = hadmard_product(material.color, light.intensity);
|
||||||
|
|
||||||
@ -45,24 +46,24 @@ inline static struct tuple lighting(struct material material,
|
|||||||
|
|
||||||
struct tuple ambient = tuple_mul(effective_color, material.ambient);
|
struct tuple ambient = tuple_mul(effective_color, material.ambient);
|
||||||
|
|
||||||
|
if (in_shadow) {
|
||||||
|
return ambient;
|
||||||
|
}
|
||||||
|
|
||||||
float light_dot_normal = tuple_dot(lightv, normalv);
|
float light_dot_normal = tuple_dot(lightv, normalv);
|
||||||
struct tuple diffuse;
|
|
||||||
struct tuple specular;
|
|
||||||
if (light_dot_normal < 0.0f) {
|
if (light_dot_normal < 0.0f) {
|
||||||
diffuse = color(0.0f, 0.0f, 0.0f); // black
|
return ambient;
|
||||||
specular = color(0.0f, 0.0f, 0.0f); // black
|
|
||||||
} else {
|
} else {
|
||||||
diffuse = tuple_mul(effective_color, material.diffuse * light_dot_normal);
|
struct tuple diffuse = tuple_mul(effective_color, material.diffuse * light_dot_normal);
|
||||||
|
|
||||||
struct tuple reflectv = tuple_reflect(tuple_neg(lightv), normalv);
|
struct tuple reflectv = tuple_reflect(tuple_neg(lightv), normalv);
|
||||||
float reflect_dot_eye = tuple_dot(reflectv, eyev);
|
float reflect_dot_eye = tuple_dot(reflectv, eyev);
|
||||||
if (reflect_dot_eye <= 0.0f) {
|
if (reflect_dot_eye <= 0.0f) {
|
||||||
specular = color(0.0f, 0.0f, 0.0f); // black
|
return tuple_add(ambient, diffuse);
|
||||||
} else {
|
} else {
|
||||||
float factor = powf(reflect_dot_eye, material.shininess);
|
float factor = powf(reflect_dot_eye, material.shininess);
|
||||||
specular = tuple_mul(light.intensity, material.specular * factor);
|
struct tuple specular = tuple_mul(light.intensity, material.specular * factor);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tuple_add(tuple_add(ambient, diffuse), specular);
|
return tuple_add(tuple_add(ambient, diffuse), specular);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,9 +102,9 @@ int main()
|
|||||||
|
|
||||||
for (int i = 0; i < 360; i++) {
|
for (int i = 0; i < 360; i++) {
|
||||||
|
|
||||||
_camera.transform = view_transform(point(5.0f * cosf(pi / 360 * (float)i),
|
_camera.transform = view_transform(point(5.0f * cosf(pi / 360 * (float)i / 10),
|
||||||
1.5f,
|
1.5f,
|
||||||
-5.0f * sinf(pi / 360 * (float)i)),
|
-5.0f * sinf(pi / 360 * (float)i / 10)),
|
||||||
point(0.0f, 1.0f, 0.0f),
|
point(0.0f, 1.0f, 0.0f),
|
||||||
vector(0.0f, 1.0f, 0.0f));
|
vector(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ static bool camera_test_6(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "Rendering a world with a camera";
|
*scenario = "Rendering a world with a camera";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
struct camera c = camera(11.0f, 11.0f, pi / 2.0f);
|
struct camera c = camera(11.0f, 11.0f, pi / 2.0f);
|
||||||
struct tuple from = point(0.0f, 0.0f, -5.0f);
|
struct tuple from = point(0.0f, 0.0f, -5.0f);
|
||||||
struct tuple to = point(0.0f, 0.0f, 0.0f);
|
struct tuple to = point(0.0f, 0.0f, 0.0f);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "intersections.h"
|
#include "intersections.h"
|
||||||
|
#include "transformations.h"
|
||||||
#include "runner.h"
|
#include "runner.h"
|
||||||
|
|
||||||
static bool intersections_test_0(const char ** scenario)
|
static bool intersections_test_0(const char ** scenario)
|
||||||
@ -181,6 +182,20 @@ static bool intersections_test_9(const char ** scenario)
|
|||||||
tuple_equal(comps.normalv, vector(0.0f, 0.0f, -1.0f));
|
tuple_equal(comps.normalv, vector(0.0f, 0.0f, -1.0f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool intersections_test_10(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "The hit should offset the point";
|
||||||
|
|
||||||
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
|
struct sphere shape = sphere();
|
||||||
|
shape.transform = translation(0.0f, 0.0f, 1.0f);
|
||||||
|
struct intersection i = intersection(5.0f, &shape);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
return
|
||||||
|
comps.over_point.z < -epsilon / 2.0f &&
|
||||||
|
comps.point.z > comps.over_point.z;
|
||||||
|
}
|
||||||
|
|
||||||
test_t intersections_tests[] = {
|
test_t intersections_tests[] = {
|
||||||
intersections_test_0,
|
intersections_test_0,
|
||||||
intersections_test_1,
|
intersections_test_1,
|
||||||
@ -192,6 +207,7 @@ test_t intersections_tests[] = {
|
|||||||
intersections_test_7,
|
intersections_test_7,
|
||||||
intersections_test_8,
|
intersections_test_8,
|
||||||
intersections_test_9,
|
intersections_test_9,
|
||||||
|
intersections_test_10,
|
||||||
};
|
};
|
||||||
|
|
||||||
RUNNER(intersections_tests);
|
RUNNER(intersections_tests);
|
||||||
|
@ -28,7 +28,7 @@ static bool materials_test_1(const char ** scenario)
|
|||||||
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct light light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
struct light light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
struct tuple result = lighting(m, light, position, eyev, normalv);
|
struct tuple result = lighting(m, light, position, eyev, normalv, false);
|
||||||
|
|
||||||
return tuple_equal(result, color(1.9f, 1.9f, 1.9f));
|
return tuple_equal(result, color(1.9f, 1.9f, 1.9f));
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ static bool materials_test_2(const char ** scenario)
|
|||||||
struct tuple eyev = vector(0.0f, 0.7071067811865476, -0.7071067811865476);
|
struct tuple eyev = vector(0.0f, 0.7071067811865476, -0.7071067811865476);
|
||||||
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct light light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
struct light light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
struct tuple result = lighting(m, light, position, eyev, normalv);
|
struct tuple result = lighting(m, light, position, eyev, normalv, false);
|
||||||
|
|
||||||
return tuple_equal(result, color(1.0f, 1.0f, 1.0f));
|
return tuple_equal(result, color(1.0f, 1.0f, 1.0f));
|
||||||
}
|
}
|
||||||
@ -58,7 +58,7 @@ static bool materials_test_3(const char ** scenario)
|
|||||||
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct light light = point_light(point(0.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
struct light light = point_light(point(0.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
struct tuple result = lighting(m, light, position, eyev, normalv);
|
struct tuple result = lighting(m, light, position, eyev, normalv, false);
|
||||||
|
|
||||||
return tuple_equal(result, color(0.7364f, 0.7364f, 0.7364f));
|
return tuple_equal(result, color(0.7364f, 0.7364f, 0.7364f));
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ static bool materials_test_4(const char ** scenario)
|
|||||||
struct tuple eyev = vector(0.0f, -0.7071067811865476, -0.7071067811865476);
|
struct tuple eyev = vector(0.0f, -0.7071067811865476, -0.7071067811865476);
|
||||||
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct light light = point_light(point(0.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
struct light light = point_light(point(0.0f, 10.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
struct tuple result = lighting(m, light, position, eyev, normalv);
|
struct tuple result = lighting(m, light, position, eyev, normalv, false);
|
||||||
|
|
||||||
return tuple_equal(result, color(1.63639, 1.63639, 1.63639));
|
return tuple_equal(result, color(1.63639, 1.63639, 1.63639));
|
||||||
}
|
}
|
||||||
@ -88,7 +88,24 @@ static bool materials_test_5(const char ** scenario)
|
|||||||
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
||||||
struct light light = point_light(point(0.0f, 0.0f, 10.0f), color(1.0f, 1.0f, 1.0f));
|
struct light light = point_light(point(0.0f, 0.0f, 10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
struct tuple result = lighting(m, light, position, eyev, normalv);
|
struct tuple result = lighting(m, light, position, eyev, normalv, false);
|
||||||
|
|
||||||
|
return tuple_equal(result, color(0.1f, 0.1f, 0.1f));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool materials_test_6(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "Lighting with the surface in shadow";
|
||||||
|
|
||||||
|
struct material m = material();
|
||||||
|
struct tuple position = point(0.0f, 0.0f, 0.0f);
|
||||||
|
|
||||||
|
struct tuple eyev = vector(0.0f, 0.0f, -1.0f);
|
||||||
|
struct tuple normalv = vector(0.0f, 0.0f, -1.0f);
|
||||||
|
struct light light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
|
bool in_shadow = true;
|
||||||
|
|
||||||
|
struct tuple result = lighting(m, light, position, eyev, normalv, in_shadow);
|
||||||
|
|
||||||
return tuple_equal(result, color(0.1f, 0.1f, 0.1f));
|
return tuple_equal(result, color(0.1f, 0.1f, 0.1f));
|
||||||
}
|
}
|
||||||
@ -100,6 +117,7 @@ test_t materials_tests[] = {
|
|||||||
materials_test_3,
|
materials_test_3,
|
||||||
materials_test_4,
|
materials_test_4,
|
||||||
materials_test_5,
|
materials_test_5,
|
||||||
|
materials_test_6,
|
||||||
};
|
};
|
||||||
|
|
||||||
RUNNER(materials_tests)
|
RUNNER(materials_tests)
|
||||||
|
@ -26,7 +26,7 @@ static bool world_test_1(const char ** scenario)
|
|||||||
s1.material.specular = 0.2f;
|
s1.material.specular = 0.2f;
|
||||||
struct sphere s2 = sphere();
|
struct sphere s2 = sphere();
|
||||||
s2.transform = scaling(0.5f, 0.5f, 0.5f);
|
s2.transform = scaling(0.5f, 0.5f, 0.5f);
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
return
|
return
|
||||||
tuple_equal(w.light.position, light.position) &&
|
tuple_equal(w.light.position, light.position) &&
|
||||||
tuple_equal(w.light.intensity, light.intensity) &&
|
tuple_equal(w.light.intensity, light.intensity) &&
|
||||||
@ -41,11 +41,11 @@ static bool world_test_2(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "Intersect a world with a ray";
|
*scenario = "Intersect a world with a ray";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
|
|
||||||
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
struct intersections xs;
|
struct intersections xs;
|
||||||
intersect_world(&w, r, &xs);
|
world_intersect(&w, r, &xs);
|
||||||
|
|
||||||
return
|
return
|
||||||
xs.count == 4 &&
|
xs.count == 4 &&
|
||||||
@ -59,12 +59,12 @@ static bool world_test_3(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "Shading an intersection";
|
*scenario = "Shading an intersection";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
struct sphere * shape = &w.objects[0];
|
struct sphere * shape = &w.objects[0];
|
||||||
struct intersection i = intersection(4.0f, shape);
|
struct intersection i = intersection(4.0f, shape);
|
||||||
struct computations comps = prepare_computations(i, r);
|
struct computations comps = prepare_computations(i, r);
|
||||||
struct tuple c = shade_hit(&w, &comps);
|
struct tuple c = world_shade_hit(&w, &comps);
|
||||||
|
|
||||||
return tuple_equal(c, color(0.38066, 0.47583, 0.2855));
|
return tuple_equal(c, color(0.38066, 0.47583, 0.2855));
|
||||||
}
|
}
|
||||||
@ -73,13 +73,13 @@ static bool world_test_4(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "Shading an intersection from the inside";
|
*scenario = "Shading an intersection from the inside";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
w.light = point_light(point(0.0f, 0.25f, 0.0f), color(1.0f, 1.0f, 1.0f));
|
w.light = point_light(point(0.0f, 0.25f, 0.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
|
struct ray r = ray(point(0.0f, 0.0f, 0.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
struct sphere * shape = &w.objects[1];
|
struct sphere * shape = &w.objects[1];
|
||||||
struct intersection i = intersection(0.5f, shape);
|
struct intersection i = intersection(0.5f, shape);
|
||||||
struct computations comps = prepare_computations(i, r);
|
struct computations comps = prepare_computations(i, r);
|
||||||
struct tuple c = shade_hit(&w, &comps);
|
struct tuple c = world_shade_hit(&w, &comps);
|
||||||
|
|
||||||
return tuple_equal(c, color(0.90498, 0.90498, 0.90498));
|
return tuple_equal(c, color(0.90498, 0.90498, 0.90498));
|
||||||
}
|
}
|
||||||
@ -88,9 +88,9 @@ static bool world_test_5(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "The color when a ray misses";
|
*scenario = "The color when a ray misses";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 1.0f, 0.0f));
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 1.0f, 0.0f));
|
||||||
struct tuple c = color_at(&w, r);
|
struct tuple c = world_color_at(&w, r);
|
||||||
|
|
||||||
return tuple_equal(c, color(0.0f, 0.0f, 0.0f));
|
return tuple_equal(c, color(0.0f, 0.0f, 0.0f));
|
||||||
}
|
}
|
||||||
@ -99,9 +99,9 @@ static bool world_test_6(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "The color when a ray hits";
|
*scenario = "The color when a ray hits";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
struct ray r = ray(point(0.0f, 0.0f, -5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
struct tuple c = color_at(&w, r);
|
struct tuple c = world_color_at(&w, r);
|
||||||
|
|
||||||
return tuple_equal(c, color(0.38066f, 0.47583f, 0.2855f));
|
return tuple_equal(c, color(0.38066f, 0.47583f, 0.2855f));
|
||||||
}
|
}
|
||||||
@ -110,17 +110,77 @@ static bool world_test_7(const char ** scenario)
|
|||||||
{
|
{
|
||||||
*scenario = "The color with an intersection behind the ray";
|
*scenario = "The color with an intersection behind the ray";
|
||||||
|
|
||||||
struct world w = default_world();
|
struct world w = world_default();
|
||||||
struct sphere * outer = &w.objects[0];
|
struct sphere * outer = &w.objects[0];
|
||||||
outer->material.ambient = 1.0f;
|
outer->material.ambient = 1.0f;
|
||||||
struct sphere * inner = &w.objects[1];
|
struct sphere * inner = &w.objects[1];
|
||||||
inner->material.ambient = 1.0f;
|
inner->material.ambient = 1.0f;
|
||||||
struct ray r = ray(point(0.0f, 0.0f, 0.75f), vector(0.0f, 0.0f, -1.0f));
|
struct ray r = ray(point(0.0f, 0.0f, 0.75f), vector(0.0f, 0.0f, -1.0f));
|
||||||
struct tuple c = color_at(&w, r);
|
struct tuple c = world_color_at(&w, r);
|
||||||
|
|
||||||
return tuple_equal(c, inner->material.color);
|
return tuple_equal(c, inner->material.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool world_test_8(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "There is no shadow when nothing is collinear with point and light";
|
||||||
|
|
||||||
|
struct world w = world_default();
|
||||||
|
struct tuple p = point(0.0f, 10.0f, 0.0f);
|
||||||
|
|
||||||
|
return world_is_shadowed(&w, p) == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_9(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "The shadow when an object is between the point and the light";
|
||||||
|
|
||||||
|
struct world w = world_default();
|
||||||
|
struct tuple p = point(10.0f, -10.0f, 10.0f);
|
||||||
|
|
||||||
|
return world_is_shadowed(&w, p) == true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_10(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "There is no shadow when an object is behind the light";
|
||||||
|
|
||||||
|
struct world w = world_default();
|
||||||
|
struct tuple p = point(-20.0f, 20.0f, -20.0f);
|
||||||
|
|
||||||
|
return world_is_shadowed(&w, p) == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_11(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "There is not shadow when an object is behind the point";
|
||||||
|
|
||||||
|
struct world w = world_default();
|
||||||
|
struct tuple p = point(-2.0f, 2.0f, -2.0f);
|
||||||
|
|
||||||
|
return world_is_shadowed(&w, p) == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool world_test_12(const char ** scenario)
|
||||||
|
{
|
||||||
|
*scenario = "shade_hit() is given an intersection in shadow";
|
||||||
|
|
||||||
|
struct world w = world();
|
||||||
|
w.light = point_light(point(0.0f, 0.0f, -10.0f), color(1.0f, 1.0f, 1.0f));
|
||||||
|
struct sphere s1 = sphere();
|
||||||
|
w.objects[0] = s1;
|
||||||
|
struct sphere s2 = sphere();
|
||||||
|
s2.transform = translation(0.0f, 0.0f, 10.0f);
|
||||||
|
w.objects[1] = s2;
|
||||||
|
w.object_count = 2;
|
||||||
|
struct ray r = ray(point(0.0f, 0.0f, 5.0f), vector(0.0f, 0.0f, 1.0f));
|
||||||
|
struct intersection i = intersection(4.0f, &s2);
|
||||||
|
struct computations comps = prepare_computations(i, r);
|
||||||
|
struct tuple c = world_shade_hit(&w, &comps);
|
||||||
|
|
||||||
|
return tuple_equal(c, color(0.1f, 0.1f, 0.1f));
|
||||||
|
}
|
||||||
|
|
||||||
test_t world_tests[] = {
|
test_t world_tests[] = {
|
||||||
world_test_0,
|
world_test_0,
|
||||||
world_test_1,
|
world_test_1,
|
||||||
@ -130,6 +190,11 @@ test_t world_tests[] = {
|
|||||||
world_test_5,
|
world_test_5,
|
||||||
world_test_6,
|
world_test_6,
|
||||||
world_test_7,
|
world_test_7,
|
||||||
|
world_test_8,
|
||||||
|
world_test_9,
|
||||||
|
world_test_10,
|
||||||
|
world_test_11,
|
||||||
|
world_test_12,
|
||||||
};
|
};
|
||||||
|
|
||||||
RUNNER(world_tests)
|
RUNNER(world_tests)
|
||||||
|
36
world.h
36
world.h
@ -23,7 +23,7 @@ inline static struct world world()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static struct world default_world()
|
inline static struct world world_default()
|
||||||
{
|
{
|
||||||
struct sphere s1 = sphere();
|
struct sphere s1 = sphere();
|
||||||
s1.material.color = color(0.8f, 1.0f, 0.6f);
|
s1.material.color = color(0.8f, 1.0f, 0.6f);
|
||||||
@ -39,7 +39,7 @@ inline static struct world default_world()
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void intersect_world(struct world * world, struct ray ray, struct intersections * intersections)
|
inline static void world_intersect(struct world * world, struct ray ray, struct intersections * intersections)
|
||||||
{
|
{
|
||||||
intersections->count = 0;
|
intersections->count = 0;
|
||||||
for (int i = 0; i < world->object_count; i++) {
|
for (int i = 0; i < world->object_count; i++) {
|
||||||
@ -48,24 +48,46 @@ inline static void intersect_world(struct world * world, struct ray ray, struct
|
|||||||
intersections_sort(intersections);
|
intersections_sort(intersections);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static struct tuple shade_hit(struct world * world, struct computations * computations)
|
inline static bool world_is_shadowed(struct world * world, struct tuple point)
|
||||||
{
|
{
|
||||||
|
struct tuple v = tuple_sub(world->light.position, point);
|
||||||
|
|
||||||
|
float distance = tuple_magnitude(v);
|
||||||
|
struct tuple direction = tuple_normalize(v);
|
||||||
|
|
||||||
|
struct ray r = ray(point, direction);
|
||||||
|
struct intersections xs;
|
||||||
|
world_intersect(world, r, &xs);
|
||||||
|
|
||||||
|
struct intersection * h = hit(&xs);
|
||||||
|
if (h != NULL && h->t < distance) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static struct tuple world_shade_hit(struct world * world, struct computations * computations)
|
||||||
|
{
|
||||||
|
bool is_shadowed = world_is_shadowed(world, computations->over_point);
|
||||||
|
|
||||||
struct tuple color = lighting(computations->object->material,
|
struct tuple color = lighting(computations->object->material,
|
||||||
world->light,
|
world->light,
|
||||||
computations->point,
|
computations->point,
|
||||||
computations->eyev,
|
computations->eyev,
|
||||||
computations->normalv);
|
computations->normalv,
|
||||||
|
is_shadowed);
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static struct tuple color_at(struct world * world, struct ray ray)
|
inline static struct tuple world_color_at(struct world * world, struct ray ray)
|
||||||
{
|
{
|
||||||
struct intersections xs;
|
struct intersections xs;
|
||||||
intersect_world(world, ray, &xs);
|
world_intersect(world, ray, &xs);
|
||||||
struct intersection * i = hit(&xs);
|
struct intersection * i = hit(&xs);
|
||||||
if (i != NULL) {
|
if (i != NULL) {
|
||||||
struct computations computations = prepare_computations(*i, ray);
|
struct computations computations = prepare_computations(*i, ray);
|
||||||
struct tuple color = shade_hit(world, &computations);
|
struct tuple color = world_shade_hit(world, &computations);
|
||||||
return color;
|
return color;
|
||||||
} else {
|
} else {
|
||||||
return color(0.0f, 0.0f, 0.0f);
|
return color(0.0f, 0.0f, 0.0f);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user