Add materials

This commit is contained in:
Jean-Michel Gorius 2022-11-11 12:06:18 +01:00
parent 062f51c7e6
commit 21b3d0e713
9 changed files with 156 additions and 15 deletions

View File

@ -8,8 +8,8 @@ Color color_add(Color c1, Color c2) {
return (Color){c1.r + c2.r, c1.g + c2.g, c1.b + c2.b}; return (Color){c1.r + c2.r, c1.g + c2.g, c1.b + c2.b};
} }
Color color_mul(double t, Color c) { Color color_mul(Color c1, Color c2) {
return (Color){t * c.r, t * c.g, t * c.b}; return (Color){c1.r * c2.r, c1.g * c2.g, c1.b * c2.b};
} }
Color color_lerp(Color c1, Color c2, double t) { Color color_lerp(Color c1, Color c2, double t) {

View File

@ -8,7 +8,7 @@ typedef struct Color {
} Color; } Color;
Color color_add(Color c1, Color c2); Color color_add(Color c1, Color c2);
Color color_mul(double t, Color c); Color color_mul(Color c1, Color c2);
Color color_lerp(Color c1, Color c2, double t); Color color_lerp(Color c1, Color c2, double t);

View File

@ -87,5 +87,6 @@ bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max,
Vec3 outward_normal = Vec3 outward_normal =
vec3_div(point3_sub(record->p, sphere->center), sphere->radius); vec3_div(point3_sub(record->p, sphere->center), sphere->radius);
hit_record_set_face_normal(record, r, outward_normal); hit_record_set_face_normal(record, r, outward_normal);
record->material = sphere->material;
return true; return true;
} }

View File

@ -4,11 +4,13 @@
#include "point3.h" #include "point3.h"
#include "ray.h" #include "ray.h"
#include "vec3.h" #include "vec3.h"
#include "material.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
typedef struct HitRecord { typedef struct HitRecord {
const Material *material;
Point3 p; Point3 p;
Vec3 normal; Vec3 normal;
double t; double t;
@ -43,6 +45,7 @@ void hittable_list_free(HittableList *list);
typedef struct Sphere { typedef struct Sphere {
HittableType type; HittableType type;
const Material *material;
Point3 center; Point3 center;
double radius; double radius;
} Sphere; } Sphere;

56
main.c
View File

@ -6,6 +6,7 @@
#include "camera.h" #include "camera.h"
#include "color.h" #include "color.h"
#include "hittable.h" #include "hittable.h"
#include "material.h"
#include "point3.h" #include "point3.h"
#include "ray.h" #include "ray.h"
#include "utils.h" #include "utils.h"
@ -17,12 +18,13 @@ Color ray_color(Ray r, const Hittable *world, int depth) {
HitRecord record; HitRecord record;
if (hittable_hit(world, r, 0.001, DBL_MAX, &record)) { if (hittable_hit(world, r, 0.001, DBL_MAX, &record)) {
Point3 target = point3_add( Ray scattered;
record.p, vec3_add(record.normal, vec3_random_unit_vector())); Color attenuation;
return color_mul(0.5, if (material_scatter(record.material, r, &record, &attenuation, &scattered))
ray_color((Ray){record.p, point3_sub(target, record.p)}, return color_mul(attenuation, ray_color(scattered, world, depth - 1));
world, depth - 1)); return (Color){0, 0, 0};
} }
Vec3 unit_direction = vec3_normalize(r.direction); Vec3 unit_direction = vec3_normalize(r.direction);
double t = 0.5 * (unit_direction.y + 1.0); double t = 0.5 * (unit_direction.y + 1.0);
Color gradient1 = {1.0, 1.0, 1.0}; Color gradient1 = {1.0, 1.0, 1.0};
@ -39,19 +41,48 @@ int main(void) {
const int max_depth = 50; const int max_depth = 50;
/* World */ /* World */
HittableList world = {.type = HITTABLE_LIST}; HittableList world = {.type = HITTABLE_LIST};
Sphere sphere1 = {
Lambertian material_ground = {.type = MATERIAL_LAMBERTIAN,
.albedo = (Color){0.8, 0.8, 0.0}};
Lambertian material_center = {.type = MATERIAL_LAMBERTIAN,
.albedo = (Color){0.7, 0.3, 0.3}};
Metal material_left = {.type = MATERIAL_METAL,
.albedo = (Color){0.8, 0.8, 0.8},
.fuzziness = 0.3};
Metal material_right = {.type = MATERIAL_METAL,
.albedo = (Color){0.8, 0.6, 0.2},
.fuzziness = 1.0};
Sphere sphere_ground = {
.type = HITTABLE_SPHERE, .type = HITTABLE_SPHERE,
.center = (Point3){0, 0, -1}, .center = (Point3){0.0, -100.5, -1},
.radius = 100.0,
.material = (const Material *)&material_ground,
};
Sphere sphere_center = {
.type = HITTABLE_SPHERE,
.center = (Point3){0.0, 0.0, -1.0},
.radius = 0.5, .radius = 0.5,
.material = (const Material *)&material_center,
}; };
Sphere sphere2 = { Sphere sphere_left = {
.type = HITTABLE_SPHERE, .type = HITTABLE_SPHERE,
.center = (Point3){0, -100.5, -1}, .center = (Point3){-1.0, 0.0, -1.0},
.radius = 100, .radius = 0.5,
.material = (const Material *)&material_left,
}; };
hittable_list_add(&world, (const Hittable *)&sphere1); Sphere sphere_right = {
hittable_list_add(&world, (const Hittable *)&sphere2); .type = HITTABLE_SPHERE,
.center = (Point3){1.0, 0.0, -1.0},
.radius = 0.5,
.material = (const Material *)&material_right,
};
hittable_list_add(&world, (const Hittable *)&sphere_ground);
hittable_list_add(&world, (const Hittable *)&sphere_center);
hittable_list_add(&world, (const Hittable *)&sphere_left);
hittable_list_add(&world, (const Hittable *)&sphere_right);
/* Camera */ /* Camera */
Camera camera; Camera camera;
@ -84,6 +115,7 @@ int main(void) {
#include "camera.c" #include "camera.c"
#include "color.c" #include "color.c"
#include "hittable.c" #include "hittable.c"
#include "material.c"
#include "point3.c" #include "point3.c"
#include "ray.c" #include "ray.c"
#include "utils.c" #include "utils.c"

47
material.c Normal file
View File

@ -0,0 +1,47 @@
#include "material.h"
#include "hittable.h"
#include "vec3.h"
#include <assert.h>
bool material_scatter(const Material *material, Ray r,
const struct HitRecord *record, Color *attenuation,
Ray *scattered) {
switch (material->type) {
case MATERIAL_LAMBERTIAN:
return lambertian_scatter((const Lambertian *)material, r, record,
attenuation, scattered);
case MATERIAL_METAL:
return metal_scatter((const Metal *)material, r, record, attenuation,
scattered);
}
return false;
}
bool lambertian_scatter(const Lambertian *lambertian, Ray r,
const HitRecord *record, Color *attenuation,
Ray *scattered) {
(void)r;
Vec3 scatter_direction = vec3_add(record->normal, vec3_random_unit_vector());
/* Catch degenerate scatter direction */
if (vec3_is_near_zero(scatter_direction))
scatter_direction = record->normal;
*scattered = (Ray){record->p, scatter_direction};
*attenuation = lambertian->albedo;
return true;
}
bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record,
Color *attenuation, Ray *scattered) {
Vec3 reflected = vec3_reflect(vec3_normalize(r.direction), record->normal);
assert(metal->fuzziness <= 1);
*scattered = (Ray){
record->p,
vec3_add(reflected,
vec3_mul(metal->fuzziness, vec3_random_in_unit_sphere())),
};
*attenuation = metal->albedo;
return vec3_dot(scattered->direction, record->normal) > 0;
}

42
material.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef INCLUDED_MATERIAL_H
#define INCLUDED_MATERIAL_H
#include "color.h"
#include "ray.h"
#include <stdbool.h>
struct HitRecord;
typedef enum MaterialType {
MATERIAL_LAMBERTIAN,
MATERIAL_METAL,
} MaterialType;
typedef struct Material {
MaterialType type;
} Material;
bool material_scatter(const Material *material, Ray r,
const struct HitRecord *record, Color *attenuation,
Ray *scattered);
typedef struct Lambertian {
MaterialType type;
Color albedo;
} Lambertian;
bool lambertian_scatter(const Lambertian *lambertian, Ray r,
const struct HitRecord *record, Color *attenuation,
Ray *scattered);
typedef struct Metal {
MaterialType type;
Color albedo;
double fuzziness;
} Metal;
bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record,
Color *attenuation, Ray *scattered);
#endif /* INCLUDED_MATERIAL_H */

10
vec3.c
View File

@ -63,3 +63,13 @@ Vec3 vec3_random_in_unit_sphere(void) {
Vec3 vec3_random_unit_vector(void) { Vec3 vec3_random_unit_vector(void) {
return vec3_normalize(vec3_random_in_unit_sphere()); return vec3_normalize(vec3_random_in_unit_sphere());
} }
bool vec3_is_near_zero(Vec3 v) {
static const double threshold = 1e-8;
return (fabs(v.x) < threshold) && (fabs(v.y) < threshold) &&
(fabs(v.z) < threshold);
}
Vec3 vec3_reflect(Vec3 v, Vec3 n) {
return vec3_sub(v, vec3_mul(2 * vec3_dot(v, n), n));
}

6
vec3.h
View File

@ -1,6 +1,8 @@
#ifndef INCLUDED_VEC3_H #ifndef INCLUDED_VEC3_H
#define INCLUDED_VEC3_H #define INCLUDED_VEC3_H
#include <stdbool.h>
typedef struct Vec3 { typedef struct Vec3 {
double x, y, z; double x, y, z;
} Vec3; } Vec3;
@ -24,4 +26,8 @@ Vec3 vec3_random_in_range(double min, double max);
Vec3 vec3_random_in_unit_sphere(void); Vec3 vec3_random_in_unit_sphere(void);
Vec3 vec3_random_unit_vector(void); Vec3 vec3_random_unit_vector(void);
bool vec3_is_near_zero(Vec3 v);
Vec3 vec3_reflect(Vec3 v, Vec3 n);
#endif /* INCLUDED_VEC3_H */ #endif /* INCLUDED_VEC3_H */