Skip to content

Commit

Permalink
One material to rule them all (#14)
Browse files Browse the repository at this point in the history
* Introduce perm<T>

* uber material

* Update plan.md
  • Loading branch information
Condzi authored Oct 18, 2023
1 parent 3c67c86 commit fc0c174
Show file tree
Hide file tree
Showing 10 changed files with 189 additions and 134 deletions.
8 changes: 7 additions & 1 deletion code/base/memory.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,10 @@ pop_temp_mem_mark(s64 size);

void
clear_temp_mem();
} // namespace rt

template <typename T>
[[nodiscard]] T*
perm(s64 count = 1) {
return (T*)alloc_perm(sizeof(T)*count);
}
} // namespace rt
4 changes: 2 additions & 2 deletions code/base/string.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ to_temp_string(String_Builder &sb) {
to_perm_string(String_Builder &sb) {
check_(sb.data != NULL);

char *buffer = (char *)alloc_perm(sb.size);
char *buffer = perm<char>(sb.size);
::memcpy(buffer, sb.data, sb.size);

return {.count = sb.size, .data = buffer};
Expand Down Expand Up @@ -96,4 +96,4 @@ as_cstr(String string) {

return buff;
}
} // namespace rt
} // namespace rt
2 changes: 1 addition & 1 deletion code/cpu_rt/bvh.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ make_BVH(BVH_Input *input, s32 begin, s32 end, AABB const &parent_aabb) {
return a.aabb.v[axis].min < b.aabb.v[axis].min;
};

BVH_Node *root = (BVH_Node *)alloc_perm(sizeof(BVH_Node));
BVH_Node *root = perm<BVH_Node>();
root->aabb = parent_aabb;

s32 const object_span = end - begin;
Expand Down
6 changes: 3 additions & 3 deletions code/cpu_rt/cpu_rt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,9 @@ ray_color(World const &world, Ray const &r, BVH_Node *const root, s32 depth) {
Ray scattered;
Vec3 attenuated_color;
// @Note: we don't support textures yet, so we emit a solid color.
Vec3 emission = hi.material->emitted();
Vec3 emission = emit(*hi.material);

if (!hi.material->scatter(r, hi, attenuated_color, scattered)) {
if (!scatter(*hi.material, r, hi, attenuated_color, scattered)) {
return emission;
}

Expand Down Expand Up @@ -281,7 +281,7 @@ do_ray_tracing() {

// Render

u8 *buffer = (u8 *)alloc_perm(image_width * image_height * NUM_CHANNELS);
u8 *buffer = perm<u8>(image_width * image_height * NUM_CHANNELS);

s32 const num_of_threads_supported = (s32)std::thread::hardware_concurrency();

Expand Down
118 changes: 92 additions & 26 deletions code/cpu_rt/materials.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,24 @@ refract(Vec3 uv, Vec3 n, f32 etai_over_etat) {
return r_out_perp + r_out_parallel;
}

// Schlick's approximation of reflactance
// Schlick's approximation of reflectance
[[nodiscard]] f32
reflactance(f32 cosine, f32 refraction_index) {
reflectance(f32 cosine, f32 refraction_index) {
f32 r0 = (1 - refraction_index) / (1 + refraction_index);
r0 = r0 * r0;

return r0 + (1 - r0) * ::powf((1 - cosine), 5);
}

Lambertian::Lambertian(Vec3 albedo_) : albedo(albedo_) {};
/**
* Specializations for different materials
*/

[[nodiscard]] bool
Lambertian::scatter(Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) {
(void)in;
scatter_lambertian(Material const &material,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) {
#if 0 // Alternative formulas
Vec3 scatter_direction = hi.normal + random_in_unit_sphere();
Vec3 scatter_direction = random_in_hemisphere(hi.normal);
Expand All @@ -45,44 +46,44 @@ Lambertian::scatter(Ray const &in,
}

out = make_ray(hi.p, scatter_direction);
attenuation_color = albedo;
attenuation_color = material.lambertian.albedo;

return true;
}

Metal::Metal(Vec3 albedo_, f32 fuzz_)
: albedo(albedo_), fuzz(fuzz_ < 1 ? fuzz_ : 1) {}

[[nodiscard]] bool
Metal::scatter(Ray const &in, Hit_Info const &hi, Vec3 &attenuation_color, Ray &out) {
scatter_metal(Material const &material,
Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) {
Vec3 const reflected = reflect(normalized(in.direction), hi.normal);
Vec3 const direction = reflected + random_in_unit_sphere() * fuzz;
Vec3 const direction = reflected + random_in_unit_sphere() * material.metal.fuzz;
out = make_ray(hi.p, direction);

attenuation_color = albedo;
attenuation_color = material.metal.albedo;
return (dot(out.direction, hi.normal) > 0);
}

Dielectric::Dielectric(f32 refraction_index_) : refraction_index(refraction_index_) {}

[[nodiscard]] bool
Dielectric::scatter(Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) {
f32 const refraction_ratio =
hi.front_face ? (1.0f / refraction_index) : (refraction_index);
scatter_dielectric(Material const &material,
Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) {
f32 const refraction_ratio = hi.front_face ? (1.0f / material.dielectric.refraction_index)
: (material.dielectric.refraction_index);

Vec3 const unit_direction = normalized(in.direction);
f32 const cos_theta = fmin(dot(unit_direction * -1.f, hi.normal), 1.0);
f32 const sin_theta = ::sqrt(1.0f - cos_theta * cos_theta);

bool const can_refract = (refraction_ratio * sin_theta) <= 1.0f;
bool const reflactance_test =
reflactance(cos_theta, refraction_ratio) > random_f32();
bool const reflectance_test =
reflectance(cos_theta, refraction_ratio) > random_f32();

Vec3 direction;
if (can_refract && !reflactance_test) {
if (can_refract && !reflectance_test) {
direction = refract(unit_direction, hi.normal, refraction_ratio);
} else {
direction = reflect(unit_direction, hi.normal);
Expand All @@ -93,4 +94,69 @@ Dielectric::scatter(Ray const &in,

return true;
}

[[nodiscard]] Vec3
emit_diffuse_light(Material const &material) {
return material.diffuse_light.albedo;
}

/**
* Actual scatter and emit definitions
*/

[[nodiscard]] bool
scatter(Material const &material,
Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) {

switch (material.type) {
case MaterialType_Lambertian: {
return scatter_lambertian(material, hi, attenuation_color, out);
} break;

case MaterialType_Metal: {
return scatter_metal(material, in, hi, attenuation_color, out);
} break;

case MaterialType_Dielectric: {
return scatter_dielectric(material, in, hi, attenuation_color, out);
} break;

default: {
return false;
}
}
}

[[nodiscard]] Vec3
emit(Material const &material) {
if (material.type == MaterialType_Diffuse_Light) {
return emit_diffuse_light(material);
}

return {0, 0, 0};
}

[[nodiscard]] Material
make_lambertian(Vec3 const &albedo) {
return {.type = MaterialType_Lambertian, .lambertian {.albedo = albedo}};
}

[[nodiscard]] Material
make_metal(Vec3 const &albedo, f32 fuzz) {
return {.type = MaterialType_Metal, .metal {.albedo = albedo, .fuzz = fuzz}};
}

[[nodiscard]] Material
make_dielectric(f32 refraction_index) {
return {.type = MaterialType_Dielectric,
.dielectric {.refraction_index = refraction_index}};
}

[[nodiscard]] Material
make_diffuse_light(Vec3 const &albedo) {
return {.type = MaterialType_Diffuse_Light, .diffuse_light {.albedo = albedo}};
}
} // namespace rt
97 changes: 41 additions & 56 deletions code/cpu_rt/materials.hxx
Original file line number Diff line number Diff line change
@@ -1,69 +1,54 @@
namespace rt {
struct Hit_Info;

// @TODO: remove polymorphism; use function pointers instead so we can use malloc
// and don't have to care about vtable ptr. -- kkubacki 07.09.2023
struct Material {
// Returns true when the ray was absorbed.
// Calculates the new color and ray.
virtual bool
scatter(Ray const &in, Hit_Info const &hi, Vec3 &attenuation_color, Ray &out) = 0;

virtual Vec3
emitted() {
return {0, 0, 0};
}
};

struct Lambertian : Material {
Vec3 albedo;

Lambertian(Vec3 albedo_);

[[nodiscard]] bool
scatter(Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) override;
enum Material_Type {
MaterialType_None = 0,
MaterialType_Lambertian,
MaterialType_Metal,
MaterialType_Dielectric,
MaterialType_Diffuse_Light,

MaterialType__count
};

struct Metal : Material {
Vec3 albedo;
f32 fuzz;

Metal(Vec3 albedo_, f32 fuzz_);

[[nodiscard]] bool
scatter(Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) override;
struct Material {
Material_Type type;
union {
struct {
Vec3 albedo;
} lambertian;
struct {
Vec3 albedo;
f32 fuzz;
} metal;
struct {
f32 refraction_index;
} dielectric;
struct {
Vec3 albedo;
} diffuse_light;
};
};

struct Dielectric : Material {
f32 refraction_index;
[[nodiscard]] bool
scatter(Material const &material,
Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out);

Dielectric(f32 refraction_index_);
[[nodiscard]] Vec3
emit(Material const &material);

[[nodiscard]] bool
scatter(Ray const &in,
Hit_Info const &hi,
Vec3 &attenuation_color,
Ray &out) override;
};
[[nodiscard]] Material
make_lambertian(Vec3 const &albedo);

struct Diffuse_Light : Material {
Vec3 color;
Diffuse_Light(Vec3 col_) : color(col_) {};
[[nodiscard]] Material
make_metal(Vec3 const &albedo, f32 fuzz);

bool
scatter(Ray const &, Hit_Info const &, Vec3 &, Ray &) {
return false;
}
[[nodiscard]] Material
make_dielectric(f32 refraction_index);

virtual Vec3
emitted() {
return color;
}
};
[[nodiscard]] Material
make_diffuse_light(Vec3 const &albedo);
} // namespace rt
Loading

0 comments on commit fc0c174

Please sign in to comment.