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};
|
||||
}
|
||||
|
||||
Color color_mul(double t, Color c) {
|
||||
return (Color){t * c.r, t * c.g, t * c.b};
|
||||
Color color_mul(Color c1, Color c2) {
|
||||
return (Color){c1.r * c2.r, c1.g * c2.g, c1.b * c2.b};
|
||||
}
|
||||
|
||||
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_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);
|
||||
|
||||
|
||||
@ -87,5 +87,6 @@ bool sphere_hit(const Sphere *sphere, Ray r, double t_min, double t_max,
|
||||
Vec3 outward_normal =
|
||||
vec3_div(point3_sub(record->p, sphere->center), sphere->radius);
|
||||
hit_record_set_face_normal(record, r, outward_normal);
|
||||
record->material = sphere->material;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4,11 +4,13 @@
|
||||
#include "point3.h"
|
||||
#include "ray.h"
|
||||
#include "vec3.h"
|
||||
#include "material.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct HitRecord {
|
||||
const Material *material;
|
||||
Point3 p;
|
||||
Vec3 normal;
|
||||
double t;
|
||||
@ -43,6 +45,7 @@ void hittable_list_free(HittableList *list);
|
||||
|
||||
typedef struct Sphere {
|
||||
HittableType type;
|
||||
const Material *material;
|
||||
Point3 center;
|
||||
double radius;
|
||||
} Sphere;
|
||||
|
||||
56
main.c
56
main.c
@ -6,6 +6,7 @@
|
||||
#include "camera.h"
|
||||
#include "color.h"
|
||||
#include "hittable.h"
|
||||
#include "material.h"
|
||||
#include "point3.h"
|
||||
#include "ray.h"
|
||||
#include "utils.h"
|
||||
@ -17,12 +18,13 @@ Color ray_color(Ray r, const Hittable *world, int depth) {
|
||||
|
||||
HitRecord record;
|
||||
if (hittable_hit(world, r, 0.001, DBL_MAX, &record)) {
|
||||
Point3 target = point3_add(
|
||||
record.p, vec3_add(record.normal, vec3_random_unit_vector()));
|
||||
return color_mul(0.5,
|
||||
ray_color((Ray){record.p, point3_sub(target, record.p)},
|
||||
world, depth - 1));
|
||||
Ray scattered;
|
||||
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);
|
||||
double t = 0.5 * (unit_direction.y + 1.0);
|
||||
Color gradient1 = {1.0, 1.0, 1.0};
|
||||
@ -39,19 +41,48 @@ int main(void) {
|
||||
const int max_depth = 50;
|
||||
|
||||
/* World */
|
||||
|
||||
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,
|
||||
.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,
|
||||
.material = (const Material *)&material_center,
|
||||
};
|
||||
Sphere sphere2 = {
|
||||
Sphere sphere_left = {
|
||||
.type = HITTABLE_SPHERE,
|
||||
.center = (Point3){0, -100.5, -1},
|
||||
.radius = 100,
|
||||
.center = (Point3){-1.0, 0.0, -1.0},
|
||||
.radius = 0.5,
|
||||
.material = (const Material *)&material_left,
|
||||
};
|
||||
hittable_list_add(&world, (const Hittable *)&sphere1);
|
||||
hittable_list_add(&world, (const Hittable *)&sphere2);
|
||||
Sphere sphere_right = {
|
||||
.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;
|
||||
@ -84,6 +115,7 @@ int main(void) {
|
||||
#include "camera.c"
|
||||
#include "color.c"
|
||||
#include "hittable.c"
|
||||
#include "material.c"
|
||||
#include "point3.c"
|
||||
#include "ray.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) {
|
||||
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
|
||||
#define INCLUDED_VEC3_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct Vec3 {
|
||||
double x, y, z;
|
||||
} Vec3;
|
||||
@ -24,4 +26,8 @@ Vec3 vec3_random_in_range(double min, double max);
|
||||
Vec3 vec3_random_in_unit_sphere(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 */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user