blob: efd2806315f2209bed4e6c4774367f5351140571 [file] [log] [blame]
#ifndef MATERIAL_H
#define MATERIAL_H
//==============================================================================================
// Originally written in 2016 by Peter Shirley <ptrshrl@gmail.com>
//
// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.
//
// You should have received a copy (see file COPYING.txt) of the CC0 Public
// Domain Dedication along with this software. If not, see
// <http://creativecommons.org/publicdomain/zero/1.0/>.
//
// The original source code is from
// https://github.com/RayTracing/raytracing.github.io/tree/release/src/TheNextWeek
//
// Changes to the original code follow the following license.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//==============================================================================================
#include "rtweekend.h"
#include "hittable.h"
#include "texture.h"
class material {
public:
virtual __host__ __device__ ~material() = default;
virtual __host__ __device__ color emitted(double u, double v,
const point3 &p) const {
return color(0, 0, 0);
}
virtual __host__ __device__ bool scatter(const ray &r_in,
const hit_record &rec,
color &attenuation, ray &scattered,
unsigned &rnd) const = 0;
};
class lambertian : public material {
public:
__host__ __device__ lambertian(const color &a)
: albedo(makeShared<solid_color>(a)) {}
__host__ __device__ lambertian(SharedPtr<rt_texture> a) : albedo(a) {}
virtual __host__ __device__ bool scatter(const ray &r_in,
const hit_record &rec,
color &attenuation, ray &scattered,
unsigned &rnd) const override {
(void)r_in;
auto scatter_direction = rec.normal + random_unit_vector(rnd);
// Catch degenerate scatter direction
if (scatter_direction.near_zero())
scatter_direction = rec.normal;
scattered = ray(rec.p, scatter_direction, r_in.time());
attenuation = albedo->value(rec.u, rec.v, rec.p);
return true;
}
private:
SharedPtr<rt_texture> albedo;
};
class metal : public material {
public:
__host__ __device__ metal(const color &a, double f)
: albedo(a), fuzz(f < 1 ? f : 1) {}
__host__ __device__ bool scatter(const ray &r_in, const hit_record &rec,
color &attenuation, ray &scattered,
unsigned &rnd) const override {
vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere(rnd), r_in.time());
attenuation = albedo;
return (dot(scattered.direction(), rec.normal) > 0);
}
private:
color albedo;
double fuzz;
};
class dielectric : public material {
public:
__host__ __device__ dielectric(double index_of_refraction)
: ir(index_of_refraction) {}
__host__ __device__ bool scatter(const ray &r_in, const hit_record &rec,
color &attenuation, ray &scattered,
unsigned &rnd) const override {
attenuation = color(1.0, 1.0, 1.0);
double refraction_ratio = rec.front_face ? (1.0 / ir) : ir;
vec3 unit_direction = unit_vector(r_in.direction());
double cos_theta = fmin(dot(-unit_direction, rec.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 ||
reflectance(cos_theta, refraction_ratio) > random_double(rnd))
direction = reflect(unit_direction, rec.normal);
else
direction = refract(unit_direction, rec.normal, refraction_ratio);
scattered = ray(rec.p, direction, r_in.time());
return true;
}
private:
double ir; // Index of Refraction
static __host__ __device__ double reflectance(double cosine,
double ref_idx) {
// Use Schlick's approximation for reflectance.
auto r0 = (1 - ref_idx) / (1 + ref_idx);
r0 = r0 * r0;
return r0 + (1 - r0) * pow((1 - cosine), 5);
}
};
class diffuse_light : public material {
public:
__host__ __device__ diffuse_light(SharedPtr<rt_texture> a) : emit(a) {}
__host__ __device__ diffuse_light(color c)
: emit(makeShared<solid_color>(c)) {}
__host__ __device__ bool scatter(const ray &r_in, const hit_record &rec,
color &attenuation, ray &scattered,
unsigned &rnd) const override {
return false;
}
__host__ __device__ color emitted(double u, double v,
const point3 &p) const override {
return emit->value(u, v, p);
}
private:
SharedPtr<rt_texture> emit;
};
class isotropic : public material {
public:
__host__ __device__ isotropic(color c)
: albedo(makeShared<solid_color>(c)) {}
__host__ __device__ isotropic(SharedPtr<rt_texture> a) : albedo(a) {}
__host__ __device__ bool scatter(const ray& r_in, const hit_record& rec, color& attenuation, ray& scattered, unsigned& rnd)
const override {
scattered = ray(rec.p, random_unit_vector(rnd), r_in.time());
attenuation = albedo->value(rec.u, rec.v, rec.p);
return true;
}
private:
SharedPtr<rt_texture> albedo;
};
#endif