#include "object.hpp" #include #include #include "core/common.hpp" Material::Material(Spectrum color, double defuse, double spectral, double spectral_pow, double emissive) { m_color = color; m_defuse = defuse; m_emissive = emissive; m_spectral = spectral; m_spectral_pow = spectral_pow; } Spectrum Material::reflect(const Vec3d &normal, const Vec3d &in, const Vec3d &out, const Spectrum &incol) const { // Emissive Spectrum c = m_color * m_emissive; // Defuse c += (m_color * incol) * (in.dot(normal) * m_defuse); // Spectral if (m_spectral > 0) { auto R = normal * (2 * normal.dot(in)) - in; c += incol * pow(out.dot(R) * m_spectral, m_spectral_pow); } return c; } Sphere::Sphere(const Material &mat, Vec3d center, double radius) : Shape(mat) { m_center = center; m_radius = radius; } Plane::Plane(const Material &mat, Vec3d start, Vec3d norm) : Shape(mat) { m_start = start; m_norm = norm; m_norm.normalize(); } Vec3d Sphere::norm_at(const Vec3d &point, const Vec3d&) const { auto res = point - m_center; res.normalize(); return res; } // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection double Sphere::intersect(const Ray &ray, bool skip_dist) const { // Calculate O - C used multiple places auto oc = ray.m_start - m_center; // Calculate components of quadratic formula // a = 1 when ray.direction is a unit vector auto a = 1; auto b = 2 * ray.m_direction.dot(oc); auto c = oc.dot(oc) - m_radius * m_radius; // Solve quadratic function auto discr = b * b - 4 * a * c; if (discr < 0) { // No solution return -1; } if (skip_dist) { // Do not calculate distance return 1; } auto q = (b > 0) ? -0.5 * (b + sqrt(discr)): -0.5 * (b - sqrt(discr)); auto t1 = q; // Assuming a = 1 auto t0 = c / q; // Find correct result if (t0 <= ZERO_APPROX) { t0 = t1; } if (t0 <= ZERO_APPROX) { return -1; } return t0; } Vec3d Plane::norm_at(const Vec3d&, const Vec3d &indir) const { auto scale = m_norm.dot(indir); return scale > 0 ? -m_norm : m_norm; } // https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection // Requires that vectors are normalized // Skip dist is ignored as distance must be calculated double Plane::intersect(const Ray &ray, bool) const { // If ray is parallel auto nr = m_norm.dot(ray.m_direction); if (abs(nr) < ZERO_APPROX) { return -1; } // Calculate distance auto dist = m_norm.dot(m_start - ray.m_start) / nr; if (dist < 0) { return -1; } return dist; }