Add materials
This commit is contained in:
parent
062f51c7e6
commit
21b3d0e713
4
color.c
4
color.c
@ -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) {
|
||||||
|
|||||||
2
color.h
2
color.h
@ -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);
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
56
main.c
@ -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
47
material.c
Normal 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
42
material.h
Normal 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
10
vec3.c
@ -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
6
vec3.h
@ -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 */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user