Add diffuse lights
This commit is contained in:
parent
8db2d5aa2c
commit
007bb10b7b
103
hittable.c
103
hittable.c
@ -1,7 +1,9 @@
|
|||||||
#include "hittable.h"
|
#include "hittable.h"
|
||||||
#include "aabb.h"
|
#include "aabb.h"
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
|
#include "material.h"
|
||||||
#include "point3.h"
|
#include "point3.h"
|
||||||
|
#include "ray.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "vec3.h"
|
#include "vec3.h"
|
||||||
|
|
||||||
@ -32,12 +34,28 @@ Hittable *hittable_create_sphere(Point3 center, double radius,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Point3 moving_sphere_center(const MovingSphere *sphere, double t) {
|
static Point3 moving_sphere_center(const MovingSphere *sphere, double t) {
|
||||||
Vec3 dir = point3_sub(sphere->center_end, sphere->center_start);
|
Vec3 dir = point3_sub(sphere->center_end, sphere->center_start);
|
||||||
double c = (t - sphere->start) / (sphere->end - sphere->start);
|
double c = (t - sphere->start) / (sphere->end - sphere->start);
|
||||||
return point3_add(sphere->center_start, vec3_mul(c, dir));
|
return point3_add(sphere->center_start, vec3_mul(c, dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hittable *hittable_create_moving_sphere(Point3 center_start, Point3 center_end,
|
||||||
|
double start, double end, double radius,
|
||||||
|
const Material *material,
|
||||||
|
Arena *arena) {
|
||||||
|
assert(start <= end);
|
||||||
|
Hittable *result = arena_alloc(arena, sizeof(Hittable));
|
||||||
|
result->type = HITTABLE_MOVING_SPHERE;
|
||||||
|
result->moving_sphere.center_start = center_start;
|
||||||
|
result->moving_sphere.center_end = center_end;
|
||||||
|
result->moving_sphere.start = start;
|
||||||
|
result->moving_sphere.end = end;
|
||||||
|
result->moving_sphere.radius = radius;
|
||||||
|
result->moving_sphere.material = material;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
typedef int BoxCompareFunc(const void *lhs, const void *rhs);
|
typedef int BoxCompareFunc(const void *lhs, const void *rhs);
|
||||||
|
|
||||||
#define BOX_COMPARATOR(axis) \
|
#define BOX_COMPARATOR(axis) \
|
||||||
@ -101,6 +119,20 @@ Hittable *hittable_create_bvh_node(const Hittable **objects, size_t start,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hittable *hittable_create_xy_rectangle(double x0, double x1, double y0,
|
||||||
|
double y1, double k,
|
||||||
|
const Material *material, Arena *arena) {
|
||||||
|
Hittable *result = arena_alloc(arena, sizeof(Hittable));
|
||||||
|
result->type = HITTABLE_XY_RECTANGLE;
|
||||||
|
result->xy_rectangle.x0 = x0;
|
||||||
|
result->xy_rectangle.x1 = x1;
|
||||||
|
result->xy_rectangle.y0 = y0;
|
||||||
|
result->xy_rectangle.y1 = y1;
|
||||||
|
result->xy_rectangle.k = k;
|
||||||
|
result->xy_rectangle.material = material;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
|
static bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
|
||||||
double t_max, HitRecord *record) {
|
double t_max, HitRecord *record) {
|
||||||
bool hit_anything = false;
|
bool hit_anything = false;
|
||||||
@ -194,6 +226,31 @@ static bool bvh_node_hit(const BVHNode *node, Ray r, double t_min, double t_max,
|
|||||||
return hit_left || hit_right;
|
return hit_left || hit_right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool xy_rectangle_hit(const XYRectangle *rectangle, Ray r, double t_min,
|
||||||
|
double t_max, HitRecord *record) {
|
||||||
|
double t = (rectangle->k - r.origin.z) / r.direction.z;
|
||||||
|
if (t < t_min || t > t_max)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
double x = r.origin.x + t * r.direction.x;
|
||||||
|
double y = r.origin.y + t * r.direction.y;
|
||||||
|
|
||||||
|
if (x < rectangle->x0 || x > rectangle->x1 || y < rectangle->y0 ||
|
||||||
|
y > rectangle->y1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
record->u = (x - rectangle->x0) / (rectangle->x1 - rectangle->x0);
|
||||||
|
record->v = (y - rectangle->y0) / (rectangle->y1 - rectangle->y0);
|
||||||
|
record->t = t;
|
||||||
|
|
||||||
|
Vec3 outward_normal = {0.0, 0.0, 1.0};
|
||||||
|
hit_record_set_face_normal(record, r, outward_normal);
|
||||||
|
record->material = rectangle->material;
|
||||||
|
record->p = ray_at(r, t);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
||||||
HitRecord *record) {
|
HitRecord *record) {
|
||||||
switch (hittable->type) {
|
switch (hittable->type) {
|
||||||
@ -205,6 +262,8 @@ bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
|||||||
return moving_sphere_hit(&hittable->moving_sphere, r, t_min, t_max, record);
|
return moving_sphere_hit(&hittable->moving_sphere, r, t_min, t_max, record);
|
||||||
case HITTABLE_BVH_NODE:
|
case HITTABLE_BVH_NODE:
|
||||||
return bvh_node_hit(&hittable->bvh_node, r, t_min, t_max, record);
|
return bvh_node_hit(&hittable->bvh_node, r, t_min, t_max, record);
|
||||||
|
case HITTABLE_XY_RECTANGLE:
|
||||||
|
return xy_rectangle_hit(&hittable->xy_rectangle, r, t_min, t_max, record);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -230,9 +289,7 @@ static bool hittable_list_bounding_box(const HittableList *list,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool sphere_bounding_box(const Sphere *sphere, double time_start,
|
static bool sphere_bounding_box(const Sphere *sphere, AABB *bounding_box) {
|
||||||
double time_end, AABB *bounding_box) {
|
|
||||||
(void)time_start, (void)time_end;
|
|
||||||
*bounding_box = (AABB){
|
*bounding_box = (AABB){
|
||||||
.min = point3_add(sphere->center, (Vec3){-sphere->radius, -sphere->radius,
|
.min = point3_add(sphere->center, (Vec3){-sphere->radius, -sphere->radius,
|
||||||
-sphere->radius}),
|
-sphere->radius}),
|
||||||
@ -263,13 +320,21 @@ static bool moving_sphere_bounding_box(const MovingSphere *sphere,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bvh_node_bounding_box(const BVHNode *node, double time_start,
|
static bool bvh_node_bounding_box(const BVHNode *node, AABB *bounding_box) {
|
||||||
double time_end, AABB *bounding_box) {
|
|
||||||
(void)time_start, (void)time_end;
|
|
||||||
*bounding_box = node->box;
|
*bounding_box = node->box;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool xy_rectangle_bouding_box(const XYRectangle *rectangle,
|
||||||
|
AABB *bounding_box) {
|
||||||
|
/* Pad the bounding box to make sure it is not zero-width */
|
||||||
|
*bounding_box = (AABB){
|
||||||
|
.min = {rectangle->x0, rectangle->y0, rectangle->k - 0.0001},
|
||||||
|
.max = {rectangle->x1, rectangle->y1, rectangle->k + 0.0001},
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool hittable_bounding_box(const Hittable *hittable, double time_start,
|
bool hittable_bounding_box(const Hittable *hittable, double time_start,
|
||||||
double time_end, AABB *bounding_box) {
|
double time_end, AABB *bounding_box) {
|
||||||
switch (hittable->type) {
|
switch (hittable->type) {
|
||||||
@ -277,14 +342,14 @@ bool hittable_bounding_box(const Hittable *hittable, double time_start,
|
|||||||
return hittable_list_bounding_box(&hittable->list, time_start, time_end,
|
return hittable_list_bounding_box(&hittable->list, time_start, time_end,
|
||||||
bounding_box);
|
bounding_box);
|
||||||
case HITTABLE_SPHERE:
|
case HITTABLE_SPHERE:
|
||||||
return sphere_bounding_box(&hittable->sphere, time_start, time_end,
|
return sphere_bounding_box(&hittable->sphere, bounding_box);
|
||||||
bounding_box);
|
|
||||||
case HITTABLE_MOVING_SPHERE:
|
case HITTABLE_MOVING_SPHERE:
|
||||||
return moving_sphere_bounding_box(&hittable->moving_sphere, time_start,
|
return moving_sphere_bounding_box(&hittable->moving_sphere, time_start,
|
||||||
time_end, bounding_box);
|
time_end, bounding_box);
|
||||||
case HITTABLE_BVH_NODE:
|
case HITTABLE_BVH_NODE:
|
||||||
return bvh_node_bounding_box(&hittable->bvh_node, time_start, time_end,
|
return bvh_node_bounding_box(&hittable->bvh_node, bounding_box);
|
||||||
bounding_box);
|
case HITTABLE_XY_RECTANGLE:
|
||||||
|
return xy_rectangle_bouding_box(&hittable->xy_rectangle, bounding_box);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -309,19 +374,3 @@ void hittable_list_add(HittableList *list, const Hittable *hittable,
|
|||||||
hittable_list_grow(list, list->capacity == 0 ? 16 : list->capacity, arena);
|
hittable_list_grow(list, list->capacity == 0 ? 16 : list->capacity, arena);
|
||||||
list->objects[list->size++] = hittable;
|
list->objects[list->size++] = hittable;
|
||||||
}
|
}
|
||||||
|
|
||||||
Hittable *hittable_create_moving_sphere(Point3 center_start, Point3 center_end,
|
|
||||||
double start, double end, double radius,
|
|
||||||
const Material *material,
|
|
||||||
Arena *arena) {
|
|
||||||
assert(start <= end);
|
|
||||||
Hittable *result = arena_alloc(arena, sizeof(Hittable));
|
|
||||||
result->type = HITTABLE_MOVING_SPHERE;
|
|
||||||
result->moving_sphere.center_start = center_start;
|
|
||||||
result->moving_sphere.center_end = center_end;
|
|
||||||
result->moving_sphere.start = start;
|
|
||||||
result->moving_sphere.end = end;
|
|
||||||
result->moving_sphere.radius = radius;
|
|
||||||
result->moving_sphere.material = material;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|||||||
10
hittable.h
10
hittable.h
@ -27,6 +27,7 @@ typedef enum HittableType {
|
|||||||
HITTABLE_SPHERE,
|
HITTABLE_SPHERE,
|
||||||
HITTABLE_MOVING_SPHERE,
|
HITTABLE_MOVING_SPHERE,
|
||||||
HITTABLE_BVH_NODE,
|
HITTABLE_BVH_NODE,
|
||||||
|
HITTABLE_XY_RECTANGLE,
|
||||||
} HittableType;
|
} HittableType;
|
||||||
|
|
||||||
typedef struct Hittable Hittable;
|
typedef struct Hittable Hittable;
|
||||||
@ -56,6 +57,11 @@ typedef struct BVHNode {
|
|||||||
AABB box;
|
AABB box;
|
||||||
} BVHNode;
|
} BVHNode;
|
||||||
|
|
||||||
|
typedef struct XYRectangle {
|
||||||
|
const Material *material;
|
||||||
|
double x0, x1, y0, y1, k;
|
||||||
|
} XYRectangle;
|
||||||
|
|
||||||
struct Hittable {
|
struct Hittable {
|
||||||
HittableType type;
|
HittableType type;
|
||||||
union {
|
union {
|
||||||
@ -63,6 +69,7 @@ struct Hittable {
|
|||||||
Sphere sphere;
|
Sphere sphere;
|
||||||
MovingSphere moving_sphere;
|
MovingSphere moving_sphere;
|
||||||
BVHNode bvh_node;
|
BVHNode bvh_node;
|
||||||
|
XYRectangle xy_rectangle;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,6 +82,9 @@ Hittable *hittable_create_moving_sphere(Point3 center_start, Point3 center_end,
|
|||||||
Hittable *hittable_create_bvh_node(const Hittable **objects, size_t start,
|
Hittable *hittable_create_bvh_node(const Hittable **objects, size_t start,
|
||||||
size_t end, double time_start,
|
size_t end, double time_start,
|
||||||
double time_end, Arena *arena);
|
double time_end, Arena *arena);
|
||||||
|
Hittable *hittable_create_xy_rectangle(double x0, double x1, double y0,
|
||||||
|
double y1, double k,
|
||||||
|
const Material *material, Arena *arena);
|
||||||
|
|
||||||
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
|
||||||
HitRecord *record);
|
HitRecord *record);
|
||||||
|
|||||||
81
main.c
81
main.c
@ -20,27 +20,32 @@
|
|||||||
#define SCENE_TWO_SPHERES 1
|
#define SCENE_TWO_SPHERES 1
|
||||||
#define SCENE_TWO_PERLIN_SPHERES 2
|
#define SCENE_TWO_PERLIN_SPHERES 2
|
||||||
#define SCENE_EARTH 3
|
#define SCENE_EARTH 3
|
||||||
|
#define SCENE_SIMPLE_LIGHT 4
|
||||||
|
|
||||||
#define SCENE_SELECT SCENE_EARTH
|
#ifndef SCENE_SELECT
|
||||||
|
#define SCENE_SELECT SCENE_SIMPLE_LIGHT
|
||||||
|
#endif
|
||||||
|
|
||||||
static Color ray_color(Ray r, const Hittable *world, int depth) {
|
static Color ray_color(Ray r, Color background_color, const Hittable *world,
|
||||||
|
int depth) {
|
||||||
if (depth <= 0)
|
if (depth <= 0)
|
||||||
return (Color){0, 0, 0};
|
return (Color){0, 0, 0};
|
||||||
|
|
||||||
HitRecord record;
|
HitRecord record;
|
||||||
if (hittable_hit(world, r, 0.001, DBL_MAX, &record)) {
|
if (!hittable_hit(world, r, 0.001, DBL_MAX, &record))
|
||||||
Ray scattered;
|
return background_color;
|
||||||
Color attenuation;
|
|
||||||
if (material_scatter(record.material, r, &record, &attenuation, &scattered))
|
|
||||||
return color_mul(attenuation, ray_color(scattered, world, depth - 1));
|
|
||||||
return (Color){0, 0, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 unit_direction = vec3_normalize(r.direction);
|
Ray scattered;
|
||||||
double t = 0.5 * (unit_direction.y + 1.0);
|
Color attenuation;
|
||||||
Color gradient1 = {1.0, 1.0, 1.0};
|
Color emitted =
|
||||||
Color gradient2 = {0.5, 0.7, 1.0};
|
material_emitted(record.material, record.u, record.v, record.p);
|
||||||
return color_lerp(gradient1, gradient2, t);
|
|
||||||
|
if (!material_scatter(record.material, r, &record, &attenuation, &scattered))
|
||||||
|
return emitted;
|
||||||
|
|
||||||
|
return color_add(emitted,
|
||||||
|
color_mul(attenuation, ray_color(scattered, background_color,
|
||||||
|
world, depth - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Hittable *generate_random_scene(Arena *arena) {
|
static const Hittable *generate_random_scene(Arena *arena) {
|
||||||
@ -152,6 +157,34 @@ static Hittable *earth(Arena *arena) {
|
|||||||
return globe;
|
return globe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Hittable *simple_light(Arena *arena) {
|
||||||
|
Hittable *world = hittable_create_hittable_list(arena);
|
||||||
|
|
||||||
|
Texture *perlin_texture =
|
||||||
|
texture_create_perlin_noise(4.0, PERLIN_DEFAULT_POINT_COUNT, arena);
|
||||||
|
hittable_list_add(
|
||||||
|
&world->list,
|
||||||
|
hittable_create_sphere((Point3){0.0, -1000.0, 0.0}, 1000.0,
|
||||||
|
material_create_lambertian(perlin_texture, arena),
|
||||||
|
arena),
|
||||||
|
arena);
|
||||||
|
hittable_list_add(
|
||||||
|
&world->list,
|
||||||
|
hittable_create_sphere((Point3){0.0, 2.0, 0.0}, 2.0,
|
||||||
|
material_create_lambertian(perlin_texture, arena),
|
||||||
|
arena),
|
||||||
|
arena);
|
||||||
|
|
||||||
|
Material *diffuse_light =
|
||||||
|
material_create_diffuse_light_color((Color){4.0, 4.0, 4.0}, arena);
|
||||||
|
hittable_list_add(&world->list,
|
||||||
|
hittable_create_xy_rectangle(3.0, 5.0, 1.0, 3.0, -2.0,
|
||||||
|
diffuse_light, arena),
|
||||||
|
arena);
|
||||||
|
|
||||||
|
return world;
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
srand(42);
|
srand(42);
|
||||||
|
|
||||||
@ -169,40 +202,51 @@ int main(void) {
|
|||||||
const double aspect_ratio = 16.0 / 9.0;
|
const double aspect_ratio = 16.0 / 9.0;
|
||||||
const int image_width = 400;
|
const int image_width = 400;
|
||||||
const int image_height = (int)(image_width / aspect_ratio);
|
const int image_height = (int)(image_width / aspect_ratio);
|
||||||
const int samples_per_pixel = 100;
|
const int samples_per_pixel = 400;
|
||||||
const int max_depth = 50;
|
const int max_depth = 50;
|
||||||
|
|
||||||
/* World */
|
|
||||||
|
|
||||||
Point3 look_from = {0.0, 0.0, 1.0};
|
Point3 look_from = {0.0, 0.0, 1.0};
|
||||||
Point3 look_at = {0.0, 0.0, 0.0};
|
Point3 look_at = {0.0, 0.0, 0.0};
|
||||||
double vfov = 40.0;
|
double vfov = 40.0;
|
||||||
double aperture = 0.0;
|
double aperture = 0.0;
|
||||||
double dist_to_focus = 10.0;
|
double dist_to_focus = 10.0;
|
||||||
|
Color background_color = {0.0, 0.0, 0.0};
|
||||||
|
|
||||||
|
/* World */
|
||||||
|
|
||||||
const Hittable *world = 0;
|
const Hittable *world = 0;
|
||||||
|
|
||||||
#if SCENE_SELECT == SCENE_RANDOM
|
#if SCENE_SELECT == SCENE_RANDOM
|
||||||
world = generate_random_scene(&arena);
|
world = generate_random_scene(&arena);
|
||||||
|
background_color = (Color){0.7, 0.8, 1.0};
|
||||||
look_from = (Point3){13.0, 2.0, 3.0};
|
look_from = (Point3){13.0, 2.0, 3.0};
|
||||||
look_at = (Point3){0.0, 0.0, 0.0};
|
look_at = (Point3){0.0, 0.0, 0.0};
|
||||||
vfov = 20.0;
|
vfov = 20.0;
|
||||||
aperture = 0.1;
|
aperture = 0.1;
|
||||||
#elif SCENE_SELECT == SCENE_TWO_SPHERES
|
#elif SCENE_SELECT == SCENE_TWO_SPHERES
|
||||||
world = two_spheres(&arena);
|
world = two_spheres(&arena);
|
||||||
|
background_color = (Color){0.7, 0.8, 1.0};
|
||||||
look_from = (Point3){13.0, 2.0, 3.0};
|
look_from = (Point3){13.0, 2.0, 3.0};
|
||||||
look_at = (Point3){0.0, 0.0, 0.0};
|
look_at = (Point3){0.0, 0.0, 0.0};
|
||||||
vfov = 20.0;
|
vfov = 20.0;
|
||||||
#elif SCENE_SELECT == SCENE_TWO_PERLIN_SPHERES
|
#elif SCENE_SELECT == SCENE_TWO_PERLIN_SPHERES
|
||||||
world = two_perlin_spheres(&arena);
|
world = two_perlin_spheres(&arena);
|
||||||
|
background_color = (Color){0.7, 0.8, 1.0};
|
||||||
look_from = (Point3){13.0, 2.0, 3.0};
|
look_from = (Point3){13.0, 2.0, 3.0};
|
||||||
look_at = (Point3){0.0, 0.0, 0.0};
|
look_at = (Point3){0.0, 0.0, 0.0};
|
||||||
vfov = 20.0;
|
vfov = 20.0;
|
||||||
#elif SCENE_SELECT == SCENE_EARTH
|
#elif SCENE_SELECT == SCENE_EARTH
|
||||||
world = earth(&arena);
|
world = earth(&arena);
|
||||||
|
background_color = (Color){0.7, 0.8, 1.0};
|
||||||
look_from = (Point3){13.0, 2.0, 3.0};
|
look_from = (Point3){13.0, 2.0, 3.0};
|
||||||
look_at = (Point3){0.0, 0.0, 0.0};
|
look_at = (Point3){0.0, 0.0, 0.0};
|
||||||
vfov = 20.0;
|
vfov = 20.0;
|
||||||
|
#elif SCENE_SELECT == SCENE_SIMPLE_LIGHT
|
||||||
|
world = simple_light(&arena);
|
||||||
|
background_color = (Color){0.0, 0.0, 0.0};
|
||||||
|
look_from = (Point3){26.0, 3.0, 6.0};
|
||||||
|
look_at = (Point3){0.0, 2.0, 0.0};
|
||||||
|
vfov = 20.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Vec3 up = {0.0, 1.0, 0.0};
|
Vec3 up = {0.0, 1.0, 0.0};
|
||||||
@ -221,7 +265,8 @@ int main(void) {
|
|||||||
double u = (i + random_double()) / (image_width - 1);
|
double u = (i + random_double()) / (image_width - 1);
|
||||||
double v = (j + random_double()) / (image_height - 1);
|
double v = (j + random_double()) / (image_height - 1);
|
||||||
Ray r = camera_get_ray(&camera, u, v);
|
Ray r = camera_get_ray(&camera, u, v);
|
||||||
pixel_color = color_add(pixel_color, ray_color(r, world, max_depth));
|
pixel_color = color_add(
|
||||||
|
pixel_color, ray_color(r, background_color, world, max_depth));
|
||||||
}
|
}
|
||||||
color_write(stdout, pixel_color, samples_per_pixel);
|
color_write(stdout, pixel_color, samples_per_pixel);
|
||||||
}
|
}
|
||||||
|
|||||||
32
material.c
32
material.c
@ -1,6 +1,7 @@
|
|||||||
#include "material.h"
|
#include "material.h"
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "hittable.h"
|
#include "hittable.h"
|
||||||
|
#include "texture.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "vec3.h"
|
#include "vec3.h"
|
||||||
|
|
||||||
@ -81,10 +82,27 @@ bool material_scatter(const Material *material, Ray r,
|
|||||||
case MATERIAL_DIELECTRIC:
|
case MATERIAL_DIELECTRIC:
|
||||||
return dielectric_scatter(&material->dielectric, r, record, attenuation,
|
return dielectric_scatter(&material->dielectric, r, record, attenuation,
|
||||||
scattered);
|
scattered);
|
||||||
|
case MATERIAL_DIFFUSE_LIGHT:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Color diffuse_light_emitted(const DiffuseLight *diffuse_light, double u,
|
||||||
|
double v, Point3 p) {
|
||||||
|
return texture_value(diffuse_light->emit, u, v, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color material_emitted(const Material *material, double u, double v, Point3 p) {
|
||||||
|
switch (material->type) {
|
||||||
|
case MATERIAL_DIFFUSE_LIGHT:
|
||||||
|
return diffuse_light_emitted(&material->diffuse_light, u, v, p);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (Color){0.0, 0.0, 0.0};
|
||||||
|
}
|
||||||
|
|
||||||
Material *material_create_lambertian(const Texture *albedo, Arena *arena) {
|
Material *material_create_lambertian(const Texture *albedo, Arena *arena) {
|
||||||
Material *result = arena_alloc(arena, sizeof(Material));
|
Material *result = arena_alloc(arena, sizeof(Material));
|
||||||
result->type = MATERIAL_LAMBERTIAN;
|
result->type = MATERIAL_LAMBERTIAN;
|
||||||
@ -118,3 +136,17 @@ Material *material_create_dielectric(double eta, Arena *arena) {
|
|||||||
result->dielectric.eta = eta;
|
result->dielectric.eta = eta;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material *material_create_diffuse_light(const Texture *emit, Arena *arena) {
|
||||||
|
Material *result = arena_alloc(arena, sizeof(Material));
|
||||||
|
result->type = MATERIAL_DIFFUSE_LIGHT;
|
||||||
|
result->diffuse_light.emit = emit;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material *material_create_diffuse_light_color(Color color, Arena *arena) {
|
||||||
|
Material *result = arena_alloc(arena, sizeof(Material));
|
||||||
|
result->type = MATERIAL_DIFFUSE_LIGHT;
|
||||||
|
result->diffuse_light.emit = texture_create_solid_color(color, arena);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@ -13,6 +13,7 @@ typedef enum MaterialType {
|
|||||||
MATERIAL_LAMBERTIAN,
|
MATERIAL_LAMBERTIAN,
|
||||||
MATERIAL_METAL,
|
MATERIAL_METAL,
|
||||||
MATERIAL_DIELECTRIC,
|
MATERIAL_DIELECTRIC,
|
||||||
|
MATERIAL_DIFFUSE_LIGHT,
|
||||||
} MaterialType;
|
} MaterialType;
|
||||||
|
|
||||||
typedef struct Lambertian {
|
typedef struct Lambertian {
|
||||||
@ -28,18 +29,24 @@ typedef struct Dielectric {
|
|||||||
double eta;
|
double eta;
|
||||||
} Dielectric;
|
} Dielectric;
|
||||||
|
|
||||||
|
typedef struct DiffuseLight {
|
||||||
|
const Texture *emit;
|
||||||
|
} DiffuseLight;
|
||||||
|
|
||||||
typedef struct Material {
|
typedef struct Material {
|
||||||
MaterialType type;
|
MaterialType type;
|
||||||
union {
|
union {
|
||||||
Lambertian lambertian;
|
Lambertian lambertian;
|
||||||
Metal metal;
|
Metal metal;
|
||||||
Dielectric dielectric;
|
Dielectric dielectric;
|
||||||
|
DiffuseLight diffuse_light;
|
||||||
};
|
};
|
||||||
} Material;
|
} Material;
|
||||||
|
|
||||||
bool material_scatter(const Material *material, Ray r,
|
bool material_scatter(const Material *material, Ray r,
|
||||||
const struct HitRecord *record, Color *attenuation,
|
const struct HitRecord *record, Color *attenuation,
|
||||||
Ray *scattered);
|
Ray *scattered);
|
||||||
|
Color material_emitted(const Material *material, double u, double v, Point3 p);
|
||||||
|
|
||||||
Material *material_create_lambertian(const Texture *albedo, Arena *arena);
|
Material *material_create_lambertian(const Texture *albedo, Arena *arena);
|
||||||
Material *material_create_lambertian_color(Color albedo, Arena *arena);
|
Material *material_create_lambertian_color(Color albedo, Arena *arena);
|
||||||
@ -48,5 +55,7 @@ Material *material_create_metal(const Texture *albedo, double fuzziness,
|
|||||||
Material *material_create_metal_color(Color albedo, double fuzziness,
|
Material *material_create_metal_color(Color albedo, double fuzziness,
|
||||||
Arena *arena);
|
Arena *arena);
|
||||||
Material *material_create_dielectric(double eta, Arena *arena);
|
Material *material_create_dielectric(double eta, Arena *arena);
|
||||||
|
Material *material_create_diffuse_light(const Texture *emit, Arena *arena);
|
||||||
|
Material *material_create_diffuse_light_color(Color color, Arena *arena);
|
||||||
|
|
||||||
#endif /* INCLUDED_MATERIAL_H */
|
#endif /* INCLUDED_MATERIAL_H */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user