Add participating media

This commit is contained in:
Jean-Michel Gorius 2022-11-13 20:19:45 +01:00
parent 990b36d9eb
commit 3e90f7e7cd
5 changed files with 171 additions and 6 deletions

View File

@ -247,6 +247,24 @@ Hittable *hittable_create_y_rotation(Hittable *ptr, double angle,
return result;
}
Hittable *hittable_create_constant_medium(Hittable *boundary, double density,
const Texture *phase, Arena *arena) {
Hittable *result = arena_alloc(arena, sizeof(Hittable));
result->type = HITTABLE_CONSTANT_MEDIUM;
result->constant_medium.boundary = boundary;
result->constant_medium.neg_inv_density = -1.0 / density;
result->constant_medium.phase_function =
material_create_isotropic(phase, arena);
return result;
}
Hittable *hittable_create_constant_medium_color(Hittable *boundary,
double density, Color albedo,
Arena *arena) {
return hittable_create_constant_medium(
boundary, density, texture_create_solid_color(albedo, arena), arena);
}
/*===----------------------------------------------------------------------===*/
static bool hittable_list_hit(const HittableList *list, Ray r, double t_min,
@ -469,6 +487,43 @@ static bool y_rotation_hit(const YRotation *rotation, Ray r, double t_min,
return true;
}
static bool constant_medium_hit(const ConstantMedium *constant_medium, Ray r,
double t_min, double t_max, HitRecord *record) {
/* TODO: Handle non-convex boundaries */
HitRecord record1, record2;
if (!hittable_hit(constant_medium->boundary, r, -DBL_MAX, DBL_MAX, &record1))
return false;
if (!hittable_hit(constant_medium->boundary, r, record1.t + 0.0001, DBL_MAX,
&record2))
return false;
if (record1.t < t_min)
record1.t = t_min;
if (record2.t > t_max)
record2.t = t_max;
if (record1.t >= record2.t)
return false;
if (record1.t < 0)
record1.t = 0;
double ray_length = vec3_length(r.direction);
double distance_inside_boundary = (record2.t - record1.t) * ray_length;
double hit_distance = constant_medium->neg_inv_density * log(random_double());
if (hit_distance > distance_inside_boundary)
return false;
/* Arbitrary values */
record->normal = (Vec3){1.0, 0.0, 0.0};
record->front_face = true;
record->material = constant_medium->phase_function;
return true;
}
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
HitRecord *record) {
switch (hittable->type) {
@ -492,6 +547,9 @@ bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
return translation_hit(&hittable->translation, r, t_min, t_max, record);
case HITTABLE_Y_ROTATION:
return y_rotation_hit(&hittable->y_rotation, r, t_min, t_max, record);
case HITTABLE_CONSTANT_MEDIUM:
return constant_medium_hit(&hittable->constant_medium, r, t_min, t_max,
record);
}
return false;
}
@ -608,6 +666,13 @@ static bool y_rotation_bounding_box(const YRotation *rotation,
return true;
}
static bool constant_medium_bounding_box(const ConstantMedium *constant_medium,
double time_start, double time_end,
AABB *bounding_box) {
return hittable_bounding_box(constant_medium->boundary, time_start, time_end,
bounding_box);
}
bool hittable_bounding_box(const Hittable *hittable, double time_start,
double time_end, AABB *bounding_box) {
switch (hittable->type) {
@ -634,6 +699,9 @@ bool hittable_bounding_box(const Hittable *hittable, double time_start,
time_end, bounding_box);
case HITTABLE_Y_ROTATION:
return y_rotation_bounding_box(&hittable->y_rotation, bounding_box);
case HITTABLE_CONSTANT_MEDIUM:
return constant_medium_bounding_box(&hittable->constant_medium, time_start,
time_end, bounding_box);
}
return false;
}

View File

@ -33,6 +33,7 @@ typedef enum HittableType {
HITTABLE_BOX,
HITTABLE_TRANSLATION,
HITTABLE_Y_ROTATION,
HITTABLE_CONSTANT_MEDIUM,
} HittableType;
typedef struct Hittable Hittable;
@ -96,6 +97,12 @@ typedef struct YRotation {
AABB bounding_box;
} YRotation;
typedef struct ConstantMedium {
const Hittable *boundary;
const Material *phase_function;
double neg_inv_density;
} ConstantMedium;
struct Hittable {
HittableType type;
union {
@ -109,6 +116,7 @@ struct Hittable {
Box box;
Translation translation;
YRotation y_rotation;
ConstantMedium constant_medium;
};
};
@ -134,6 +142,11 @@ Hittable *hittable_create_box(Point3 p0, Point3 p1, const Material *material,
Arena *arena);
Hittable *hittable_create_translation(Hittable *ptr, Vec3 offset, Arena *arena);
Hittable *hittable_create_y_rotation(Hittable *ptr, double angle, Arena *arena);
Hittable *hittable_create_constant_medium(Hittable *boundary, double density,
const Texture *phase, Arena *arena);
Hittable *hittable_create_constant_medium_color(Hittable *boundary,
double density, Color albedo,
Arena *arena);
bool hittable_hit(const Hittable *hittable, Ray r, double t_min, double t_max,
HitRecord *record);

68
main.c
View File

@ -23,9 +23,10 @@
#define SCENE_EARTH 3
#define SCENE_SIMPLE_LIGHT 4
#define SCENE_CORNELL_BOX 5
#define SCENE_CORNELL_BOX_SMOKE 6
#ifndef SCENE_SELECT
#define SCENE_SELECT SCENE_CORNELL_BOX
#define SCENE_SELECT SCENE_CORNELL_BOX_SMOKE
#endif
static Color ray_color(Ray r, Color background_color, const Hittable *world,
@ -231,9 +232,60 @@ static Hittable *cornell_box(Arena *arena) {
box2 = hittable_create_translation(box2, (Vec3){130, 0, 65}, arena);
hittable_list_add(&world->list, box2, arena);
Hittable *bvh_root = hittable_create_bvh_node(
world->list.objects, 0, world->list.size, 0.0, 1.0, arena);
return bvh_root;
return world;
}
static Hittable *cornell_box_smoke(Arena *arena) {
Hittable *world = hittable_create_hittable_list(arena);
Material *red =
material_create_lambertian_color((Color){0.65, 0.05, 0.05}, arena);
Material *white =
material_create_lambertian_color((Color){0.73, 0.73, 0.73}, arena);
Material *green =
material_create_lambertian_color((Color){0.12, 0.45, 0.15}, arena);
Material *light =
material_create_diffuse_light_color((Color){7.0, 7.0, 7.0}, arena);
hittable_list_add(
&world->list,
hittable_create_yz_rectangle(0, 555, 0, 555, 555, green, arena), arena);
hittable_list_add(&world->list,
hittable_create_yz_rectangle(0, 555, 0, 555, 0, red, arena),
arena);
hittable_list_add(
&world->list,
hittable_create_xz_rectangle(113, 443, 127, 432, 554, light, arena),
arena);
hittable_list_add(
&world->list,
hittable_create_xz_rectangle(0, 555, 0, 555, 0, white, arena), arena);
hittable_list_add(
&world->list,
hittable_create_xz_rectangle(0, 555, 0, 555, 555, white, arena), arena);
hittable_list_add(
&world->list,
hittable_create_xy_rectangle(0, 555, 0, 555, 555, white, arena), arena);
Hittable *box1 = hittable_create_box((Point3){0, 0, 0},
(Point3){165, 330, 165}, white, arena);
box1 = hittable_create_y_rotation(box1, 15, arena);
box1 = hittable_create_translation(box1, (Vec3){265, 0, 295}, arena);
hittable_list_add(&world->list,
hittable_create_constant_medium_color(
box1, 0.01, (Color){0.0, 0.0, 0.0}, arena),
arena);
Hittable *box2 = hittable_create_box((Point3){0, 0, 0},
(Point3){165, 165, 165}, white, arena);
box2 = hittable_create_y_rotation(box2, -18, arena);
box2 = hittable_create_translation(box2, (Vec3){130, 0, 65}, arena);
hittable_list_add(&world->list,
hittable_create_constant_medium_color(
box2, 0.01, (Color){1.0, 1.0, 1.0}, arena),
arena);
return world;
}
int main(int argc, char *argv[]) {
@ -318,6 +370,14 @@ int main(int argc, char *argv[]) {
look_from = (Point3){278.0, 278.0, -800.0};
look_at = (Point3){278.0, 278.0, 0.0};
vfov = 40.0;
#elif SCENE_SELECT == SCENE_CORNELL_BOX_SMOKE
world = cornell_box_smoke(&arena);
aspect_ratio = 1.0;
image_width = 600;
samples_per_pixel = 200;
look_from = (Point3){278.0, 278.0, -800.0};
look_at = (Point3){278.0, 278.0, 0.0};
vfov = 40.0;
#else
#error Unknown scene selected
#endif

View File

@ -70,6 +70,15 @@ static bool dielectric_scatter(const Dielectric *dielectric, Ray r,
return true;
}
static bool isotropic_scatter(const Isotropic *isotropic, Ray r,
const struct HitRecord *record,
Color *attenuation, Ray *scattered) {
*scattered = (Ray){record->p, vec3_random_in_unit_sphere(), r.time};
*attenuation =
texture_value(isotropic->albedo, record->u, record->v, record->p);
return true;
}
bool material_scatter(const Material *material, Ray r,
const struct HitRecord *record, Color *attenuation,
Ray *scattered) {
@ -84,6 +93,9 @@ bool material_scatter(const Material *material, Ray r,
scattered);
case MATERIAL_DIFFUSE_LIGHT:
return false;
case MATERIAL_ISOTROPIC:
return isotropic_scatter(&material->isotropic, r, record, attenuation,
scattered);
}
return false;
}
@ -145,8 +157,13 @@ Material *material_create_diffuse_light(const Texture *emit, Arena *arena) {
}
Material *material_create_diffuse_light_color(Color color, Arena *arena) {
return material_create_diffuse_light(texture_create_solid_color(color, arena),
arena);
}
Material *material_create_isotropic(const Texture *albedo, Arena *arena) {
Material *result = arena_alloc(arena, sizeof(Material));
result->type = MATERIAL_DIFFUSE_LIGHT;
result->diffuse_light.emit = texture_create_solid_color(color, arena);
result->type = MATERIAL_ISOTROPIC;
result->isotropic.albedo = albedo;
return result;
}

View File

@ -14,6 +14,7 @@ typedef enum MaterialType {
MATERIAL_METAL,
MATERIAL_DIELECTRIC,
MATERIAL_DIFFUSE_LIGHT,
MATERIAL_ISOTROPIC,
} MaterialType;
typedef struct Lambertian {
@ -33,6 +34,10 @@ typedef struct DiffuseLight {
const Texture *emit;
} DiffuseLight;
typedef struct Isotropic {
const Texture *albedo;
} Isotropic;
typedef struct Material {
MaterialType type;
union {
@ -40,6 +45,7 @@ typedef struct Material {
Metal metal;
Dielectric dielectric;
DiffuseLight diffuse_light;
Isotropic isotropic;
};
} Material;
@ -57,5 +63,6 @@ Material *material_create_metal_color(Color albedo, double fuzziness,
Material *material_create_dielectric(double eta, Arena *arena);
Material *material_create_diffuse_light(const Texture *emit, Arena *arena);
Material *material_create_diffuse_light_color(Color color, Arena *arena);
Material *material_create_isotropic(const Texture *albedo, Arena *arena);
#endif /* INCLUDED_MATERIAL_H */