Add glass material

This commit is contained in:
Jean-Michel Gorius 2022-11-11 12:27:06 +01:00
parent 21b3d0e713
commit 7e6ba7d445
5 changed files with 66 additions and 5 deletions

15
main.c
View File

@ -47,13 +47,11 @@ int main(void) {
Lambertian material_ground = {.type = MATERIAL_LAMBERTIAN, Lambertian material_ground = {.type = MATERIAL_LAMBERTIAN,
.albedo = (Color){0.8, 0.8, 0.0}}; .albedo = (Color){0.8, 0.8, 0.0}};
Lambertian material_center = {.type = MATERIAL_LAMBERTIAN, Lambertian material_center = {.type = MATERIAL_LAMBERTIAN,
.albedo = (Color){0.7, 0.3, 0.3}}; .albedo = (Color){0.1, 0.2, 0.5}};
Metal material_left = {.type = MATERIAL_METAL, Dielectric material_left = {.type = MATERIAL_DIELECTRIC, .eta = 1.5};
.albedo = (Color){0.8, 0.8, 0.8},
.fuzziness = 0.3};
Metal material_right = {.type = MATERIAL_METAL, Metal material_right = {.type = MATERIAL_METAL,
.albedo = (Color){0.8, 0.6, 0.2}, .albedo = (Color){0.8, 0.6, 0.2},
.fuzziness = 1.0}; .fuzziness = 0.0};
Sphere sphere_ground = { Sphere sphere_ground = {
.type = HITTABLE_SPHERE, .type = HITTABLE_SPHERE,
@ -73,6 +71,12 @@ int main(void) {
.radius = 0.5, .radius = 0.5,
.material = (const Material *)&material_left, .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 = { Sphere sphere_right = {
.type = HITTABLE_SPHERE, .type = HITTABLE_SPHERE,
.center = (Point3){1.0, 0.0, -1.0}, .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_ground);
hittable_list_add(&world, (const Hittable *)&sphere_center); hittable_list_add(&world, (const Hittable *)&sphere_center);
hittable_list_add(&world, (const Hittable *)&sphere_left); 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); hittable_list_add(&world, (const Hittable *)&sphere_right);
/* Camera */ /* Camera */

View File

@ -1,8 +1,10 @@
#include "material.h" #include "material.h"
#include "hittable.h" #include "hittable.h"
#include "utils.h"
#include "vec3.h" #include "vec3.h"
#include <assert.h> #include <assert.h>
#include <math.h>
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,
@ -14,6 +16,9 @@ bool material_scatter(const Material *material, Ray r,
case MATERIAL_METAL: case MATERIAL_METAL:
return metal_scatter((const Metal *)material, r, record, attenuation, return metal_scatter((const Metal *)material, r, record, attenuation,
scattered); scattered);
case MATERIAL_DIELECTRIC:
return dielectric_scatter((const Dielectric *)material, r, record,
attenuation, scattered);
} }
return false; return false;
} }
@ -45,3 +50,34 @@ bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record,
*attenuation = metal->albedo; *attenuation = metal->albedo;
return vec3_dot(scattered->direction, record->normal) > 0; 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;
}

View File

@ -11,6 +11,7 @@ struct HitRecord;
typedef enum MaterialType { typedef enum MaterialType {
MATERIAL_LAMBERTIAN, MATERIAL_LAMBERTIAN,
MATERIAL_METAL, MATERIAL_METAL,
MATERIAL_DIELECTRIC,
} MaterialType; } MaterialType;
typedef struct Material { typedef struct Material {
@ -39,4 +40,13 @@ typedef struct Metal {
bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record, bool metal_scatter(const Metal *metal, Ray r, const struct HitRecord *record,
Color *attenuation, Ray *scattered); 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 */ #endif /* INCLUDED_MATERIAL_H */

9
vec3.c
View File

@ -73,3 +73,12 @@ bool vec3_is_near_zero(Vec3 v) {
Vec3 vec3_reflect(Vec3 v, Vec3 n) { Vec3 vec3_reflect(Vec3 v, Vec3 n) {
return vec3_sub(v, vec3_mul(2 * vec3_dot(v, n), 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);
}

1
vec3.h
View File

@ -29,5 +29,6 @@ Vec3 vec3_random_unit_vector(void);
bool vec3_is_near_zero(Vec3 v); bool vec3_is_near_zero(Vec3 v);
Vec3 vec3_reflect(Vec3 v, Vec3 n); Vec3 vec3_reflect(Vec3 v, Vec3 n);
Vec3 vec3_refract(Vec3 uv, Vec3 n, double refraction_ratio);
#endif /* INCLUDED_VEC3_H */ #endif /* INCLUDED_VEC3_H */