diff --git a/RayTracer/shape/Sphere.cpp b/RayTracer/shape/Sphere.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8ad940f4100828cc7670bea0c67ca11e543900df --- /dev/null +++ b/RayTracer/shape/Sphere.cpp @@ -0,0 +1,44 @@ +#define _USE_MATH_DEFINES + +#include "Sphere.h" +#include "math.h" + +namespace shapes { +Sphere::Sphere(float radius, const std::shared_ptr<material::Material>& material) + : radius(radius) + , material(material) +{ +} +std::shared_ptr<cam::Hit> Sphere::intersect(const cam::Ray& r) +{ + util::Vec3 d = r.d; + util::Vec3 x0 = r.x0; + float a = util::dot(d, d); + float b = 2 * util::dot(x0, d); + float c = util::dot(x0, x0) - (radius * radius); + float discrim = b * b - 4 * a * c; + + if (discrim >= 0) { + double t1 = (-b - sqrt(b * b - 4 * a * c)) / (2 * a); + + if (r.in_range(t1)) { + util::Vec3 t1HitPoint = r(t1); + double theta = acos(t1HitPoint.y() / radius); + double phi = M_PI + atan2(t1HitPoint.x(), t1HitPoint.z()); + return std::make_shared<cam::Hit>(cam::Hit(t1HitPoint, t1HitPoint, t1, material)); + } else { + double t2 = (-b + sqrt(b * b - 4 * a * c)) / (2 * a); + if (r.in_range(t2)) { + util::Vec3 t2HitPoint = r(t2); + double theta = acos(t2HitPoint.y() / radius); + double phi = M_PI + atan2(t2HitPoint.x(), t2HitPoint.z()); + return std::make_shared<cam::Hit>(cam::Hit(t2HitPoint, t2HitPoint, t2, material)); + } else { + return nullptr; + } + } + } else { + return nullptr; + } +} +} diff --git a/RayTracer/shape/Sphere.h b/RayTracer/shape/Sphere.h new file mode 100644 index 0000000000000000000000000000000000000000..cd980d0b9d45894d736dd64a915f5499c6e90163 --- /dev/null +++ b/RayTracer/shape/Sphere.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Shape.h" + +namespace shapes { +class Sphere : public Shape { +public: + Sphere(float radius, const std::shared_ptr<material::Material>& material); + std::shared_ptr<cam::Hit> intersect(const cam::Ray& r); + +private: + std::shared_ptr<material::Material> material; + const float radius; +}; +}