From 7e6ba7d445aca008987dfc6850e572109ad2d4ef Mon Sep 17 00:00:00 2001 From: Jean-Michel Gorius Date: Fri, 11 Nov 2022 12:27:06 +0100 Subject: [PATCH] Add glass material --- main.c | 15 ++++++++++----- material.c | 36 ++++++++++++++++++++++++++++++++++++ material.h | 10 ++++++++++ vec3.c | 9 +++++++++ vec3.h | 1 + 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index 65d5aac..b6f1577 100644 --- a/main.c +++ b/main.c @@ -47,13 +47,11 @@ int main(void) { 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}; + .albedo = (Color){0.1, 0.2, 0.5}}; + Dielectric material_left = {.type = MATERIAL_DIELECTRIC, .eta = 1.5}; Metal material_right = {.type = MATERIAL_METAL, .albedo = (Color){0.8, 0.6, 0.2}, - .fuzziness = 1.0}; + .fuzziness = 0.0}; Sphere sphere_ground = { .type = HITTABLE_SPHERE, @@ -73,6 +71,12 @@ int main(void) { .radius = 0.5, .material = (const Material *)&material_left, }; + Sphere sphere_inside_left = { + .type = HITTABLE_SPHERE, + .center = (Point3){-1.0, 0.0, -1.0}, + .radius = -0.4, + .material = (const Material *)&material_left, + }; Sphere sphere_right = { .type = HITTABLE_SPHERE, .center = (Point3){1.0, 0.0, -1.0}, @@ -82,6 +86,7 @@ int main(void) { 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_inside_left); hittable_list_add(&world, (const Hittable *)&sphere_right); /* Camera */ diff --git a/material.c b/material.c index dd9c314..b329a19 100644 --- a/material.c +++ b/material.c @@ -1,8 +1,10 @@ #include "material.h" #include "hittable.h" +#include "utils.h" #include "vec3.h" #include +#include bool material_scatter(const Material *material, Ray r, const struct HitRecord *record, Color *attenuation, @@ -14,6 +16,9 @@ bool material_scatter(const Material *material, Ray r, case MATERIAL_METAL: return metal_scatter((const Metal *)material, r, record, attenuation, scattered); + case MATERIAL_DIELECTRIC: + return dielectric_scatter((const Dielectric *)material, r, record, + attenuation, scattered); } return false; } @@ -45,3 +50,34 @@ bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record, *attenuation = metal->albedo; return vec3_dot(scattered->direction, record->normal) > 0; } + +static double schlick_reflectance(double cosine, double eta) { + double r0 = (1 - eta) / (1 + eta); + r0 *= r0; + return r0 + (1 - r0) * pow(1 - cosine, 5); +} + +bool dielectric_scatter(const Dielectric *dielectric, Ray r, + const struct HitRecord *record, Color *attenuation, + Ray *scattered) { + *attenuation = (Color){1.0, 1.0, 1.0}; + double refraction_ratio = + record->front_face ? (1.0 / dielectric->eta) : dielectric->eta; + + Vec3 unit_direction = vec3_normalize(r.direction); + double cos_theta = + fmin(vec3_dot(vec3_neg(unit_direction), record->normal), 1.0); + double sin_theta = sqrt(1.0 - cos_theta * cos_theta); + + bool cannot_refract = refraction_ratio * sin_theta > 1.0; + + Vec3 direction; + if (cannot_refract || + schlick_reflectance(cos_theta, refraction_ratio) > random_double()) + direction = vec3_reflect(unit_direction, record->normal); + else + direction = vec3_refract(unit_direction, record->normal, refraction_ratio); + + *scattered = (Ray){record->p, direction}; + return true; +} diff --git a/material.h b/material.h index a194414..f9d3a78 100644 --- a/material.h +++ b/material.h @@ -11,6 +11,7 @@ struct HitRecord; typedef enum MaterialType { MATERIAL_LAMBERTIAN, MATERIAL_METAL, + MATERIAL_DIELECTRIC, } MaterialType; typedef struct Material { @@ -39,4 +40,13 @@ typedef struct Metal { bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record, Color *attenuation, Ray *scattered); +typedef struct Dielectric { + MaterialType type; + double eta; +} Dielectric; + +bool dielectric_scatter(const Dielectric *dielectric, Ray r, + const struct HitRecord *record, Color *attenuation, + Ray *scattered); + #endif /* INCLUDED_MATERIAL_H */ diff --git a/vec3.c b/vec3.c index 8807e9f..318c4ec 100644 --- a/vec3.c +++ b/vec3.c @@ -73,3 +73,12 @@ bool vec3_is_near_zero(Vec3 v) { Vec3 vec3_reflect(Vec3 v, Vec3 n) { return vec3_sub(v, vec3_mul(2 * vec3_dot(v, n), n)); } + +Vec3 vec3_refract(Vec3 uv, Vec3 n, double refraction_ratio) { + double cos_theta = fmin(vec3_dot(vec3_neg(uv), n), 1.0); + Vec3 r_out_perpendicular = + vec3_mul(refraction_ratio, vec3_add(uv, vec3_mul(cos_theta, n))); + Vec3 r_out_parallel = + vec3_mul(-sqrt(fabs(1.0 - vec3_length2(r_out_perpendicular))), n); + return vec3_add(r_out_perpendicular, r_out_parallel); +} diff --git a/vec3.h b/vec3.h index 71add31..dcea3f0 100644 --- a/vec3.h +++ b/vec3.h @@ -29,5 +29,6 @@ Vec3 vec3_random_unit_vector(void); bool vec3_is_near_zero(Vec3 v); Vec3 vec3_reflect(Vec3 v, Vec3 n); +Vec3 vec3_refract(Vec3 uv, Vec3 n, double refraction_ratio); #endif /* INCLUDED_VEC3_H */