diff options
| -rw-r--r-- | include/camera.hpp | 5 | ||||
| -rw-r--r-- | include/dielectric.hpp | 18 | ||||
| -rw-r--r-- | include/rt.hpp | 1 | ||||
| -rw-r--r-- | include/vec3.hpp | 2 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/camera.cpp | 22 | ||||
| -rw-r--r-- | src/dielectric.cpp | 32 | ||||
| -rw-r--r-- | src/main.cpp | 5 | ||||
| -rw-r--r-- | src/metal.cpp | 2 | ||||
| -rw-r--r-- | src/vec3.cpp | 10 |
10 files changed, 84 insertions, 14 deletions
diff --git a/include/camera.hpp b/include/camera.hpp index 82f7155..0b3d20e 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -1,16 +1,15 @@ #ifndef __CAMERA_HPP_ #define __CAMERA_HPP_ -#include "rt.hpp" +#include "ray.hpp" class camera { public: - camera(point3 position, double aspect_ratio, double focal_length); + camera(point3 position, point3 target, double v_fov, double aspect_ratio); ray get_ray(double u, double v) const; point3 position; - double focal_length; vec3 horizontal; vec3 vertical; diff --git a/include/dielectric.hpp b/include/dielectric.hpp new file mode 100644 index 0000000..91f1541 --- /dev/null +++ b/include/dielectric.hpp @@ -0,0 +1,18 @@ +#ifndef __DIELECTRIC_HPP_ +#define __DIELECTRIC_HPP_ + +#include "material.hpp" + +class dielectric : public material { + public: + dielectric(double index_of_refraction); + + virtual bool scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const; + + double ior; + + private: + static double reflectance(double cosine, double ref_idx); +}; + +#endif // !__DIELECTRIC_HPP_ diff --git a/include/rt.hpp b/include/rt.hpp index 2cf3ce2..1294232 100644 --- a/include/rt.hpp +++ b/include/rt.hpp @@ -34,5 +34,6 @@ inline double clamp(double x, double min, double max) { #include "material.hpp" #include "lambertian.hpp" #include "metal.hpp" +#include "dielectric.hpp" #endif // !__RT_HPP_ diff --git a/include/vec3.hpp b/include/vec3.hpp index 317f99b..7d38472 100644 --- a/include/vec3.hpp +++ b/include/vec3.hpp @@ -53,6 +53,8 @@ vec3 operator/(vec3 u, double scale); vec3 reflect(vec3 v, vec3 n); +vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat); + std::ostream& operator<<(std::ostream& out, vec3 vec); vec3 random_in_unit_sphere(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 691d221..bac7a7a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -11,4 +11,5 @@ add_executable( camera.cpp lambertian.cpp metal.cpp + dielectric.cpp ) diff --git a/src/camera.cpp b/src/camera.cpp index 21cf506..520cc1e 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -1,14 +1,22 @@ #include "camera.hpp" -camera::camera(point3 position, double aspect_ratio, double focal_length) - : position(position), focal_length(focal_length) { - auto viewport_height = 2.0; - auto viewport_width = viewport_height * aspect_ratio; +#include "rt.hpp" - horizontal = vec3 { viewport_width, 0.0, 0.0 }; - vertical = vec3 { 0.0, viewport_height, 0.0 }; +camera::camera(point3 position, point3 target, double v_fov, double aspect_ratio) + : position(position) { - bottom_left_pixel = position - horizontal / 2.0 - vertical / 2.0 - vec3 { 0.0, 0.0, focal_length }; + auto forward = (position - target).unit(); + auto right = vec3{ 0.0, 1.0, 0.0 }.cross(forward).unit(); + auto up = forward.cross(right).unit(); + + auto h = tan(deg_to_rad(v_fov) / 2.0); + auto viewport_height = 2.0 * h; + auto viewport_width = viewport_height * aspect_ratio; + + horizontal = viewport_width * right; + vertical = viewport_height * up; + + bottom_left_pixel = position - horizontal / 2.0 - vertical / 2.0 - forward; } ray camera::get_ray(double u, double v) const { diff --git a/src/dielectric.cpp b/src/dielectric.cpp new file mode 100644 index 0000000..80ca069 --- /dev/null +++ b/src/dielectric.cpp @@ -0,0 +1,32 @@ +#include "dielectric.hpp" +#include "rt.hpp" +#include "hittable.hpp" + +dielectric::dielectric(double index_of_refraction) + : ior(index_of_refraction) {} + +bool dielectric::scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const { + auto unit_direction = r.direction.unit(); + auto refraction_ratio = info.front_face ? (1.0 / ior) : ior; + double cos_theta = fmin(info.normal.dot(-unit_direction), 1.0); + double sin_theta = sqrt(1.0 - cos_theta * cos_theta); + + vec3 direction; + if (refraction_ratio * sin_theta > 1.0 || reflectance(cos_theta, refraction_ratio) > randd()) { + direction = reflect(unit_direction, info.normal); + } else { + direction = refract(unit_direction, info.normal, refraction_ratio); + } + + scattered = ray { info.point, direction }; + attenuation = { 1.0, 1.0, 1.0 }; + + return true; +} + +double dielectric::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); +} diff --git a/src/main.cpp b/src/main.cpp index 9718d3e..92dc01f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -35,19 +35,20 @@ int main() { const uint32_t samples_per_pixel = 100; const uint32_t max_depth = 100; - camera camera { {}, aspect_ratio, 1.0 }; + camera camera { { /*-2.0, 2.0, 1.0*/ }, { 0.0, 0.0, -1.0 }, 90.0, aspect_ratio }; // World hittable objects hittable_list world {}; auto material_ground = std::make_shared<lambertian>(color(0.8, 0.8, 0.0)); auto material_center = std::make_shared<lambertian>(color(0.7, 0.3, 0.3)); - auto material_left = std::make_shared<metal>(color(0.8, 0.8, 0.8), 0.3); + auto material_left = std::make_shared<dielectric>(1.5); auto material_right = std::make_shared<metal>(color(0.8, 0.6, 0.2), 1.0); world.add(std::make_shared<sphere>(point3( 0.0, -100.5, -1.0), 100.0, material_ground)); world.add(std::make_shared<sphere>(point3( 0.0, 0.0, -1.0), 0.5, material_center)); world.add(std::make_shared<sphere>(point3(-1.0, 0.0, -1.0), 0.5, material_left)); + world.add(std::make_shared<sphere>(point3(-1.0, 0.0, -1.0), -0.4, material_left)); world.add(std::make_shared<sphere>(point3( 1.0, 0.0, -1.0), 0.5, material_right)); // PPM format header diff --git a/src/metal.cpp b/src/metal.cpp index d02a2f7..196c95d 100644 --- a/src/metal.cpp +++ b/src/metal.cpp @@ -6,7 +6,7 @@ metal::metal(const color& albedo, double f) : albedo(albedo), fuzz(f < 1 ? f : 1) {} bool metal::scatter(const ray& r, const struct hit_info& info, color& attenuation, ray& scattered) const { - auto reflected = reflect(r.direction, info.normal).unit(); + auto reflected = reflect(r.direction.unit(), info.normal); scattered = ray { info.point, reflected + fuzz * random_in_unit_sphere() }; attenuation = albedo; diff --git a/src/vec3.cpp b/src/vec3.cpp index 92ccae4..3346973 100644 --- a/src/vec3.cpp +++ b/src/vec3.cpp @@ -53,7 +53,7 @@ vec3 vec3::cross(const vec3& vec) const { return vec3( y * vec.z - z * vec.y, z * vec.x - x * vec.z, - x * vec.y - y * vec.y + x * vec.y - y * vec.x ); } @@ -111,6 +111,14 @@ vec3 reflect(vec3 v, vec3 n) { return v - 2 * v.dot(n) * n; } +vec3 refract(const vec3& uv, const vec3& n, double etai_over_etat) { + auto cos_theta = fmin(n.dot(-uv), 1.0); + vec3 r_out_perp = etai_over_etat * (uv + cos_theta*n); + vec3 r_out_parallel = -sqrt(fabs(1.0 - r_out_perp.length_sq())) * n; + + return r_out_perp + r_out_parallel; +} + std::ostream& operator<<(std::ostream& out, vec3 vec) { return out << vec.x << ' ' << vec.y << ' ' << vec.z << std::endl; } |
