raytracer/src/objects.cpp

71 lines
2.5 KiB
C++
Raw Normal View History

2022-12-17 17:22:51 +00:00
#include "../include/objects.hpp"
/* Plane */
Plane::Plane(const v3& n, choice_t offset, const Material& specs, int surface_type)
: Renderable(specs), n(n), offset(offset), surface_type(surface_type) {}
Plane::Plane(const v3& n, choice_t offset, const Material& specs) : Plane(n, offset, specs, 2) {}
int Plane::intersect(const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
{
const choice_t d = dir ^ n;
if(d <= 0) return 0;
const choice_t k = -((eye ^ n) + offset) / d;
hit_loc = eye + dir * k;
hit_normal = n;
hit_dist = (hit_loc - eye).len();
return surface_type;
}
/* Sphere */
Sphere::Sphere(const v3& origin, choice_t r, const Material& specs, int surface_type)
: Renderable(specs), o(origin), r(r), surface_type(surface_type) {}
Sphere::Sphere(const v3& origin, choice_t r) : Sphere(origin, r, Material(), 1) {}
template<int K = 1>
static inline int _sphere_intersect(Sphere& self, const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
{
const v3 d = self.o - eye;
const choice_t dist_above_o = dir ^ d;
// We're facing directly away from the sphere
if(dist_above_o < 0) { return -1; }
// The ray is pointing directly at the center of the sphere
// if(fabs(dist_above_o - d.len()) < 1e-5) {
// hit_loc = eye + d.norm() * (d.len() - self.r);
// hit_normal = self.normal(hit_loc);
// hit_dist = (hit_loc - eye).len();
// return self.surface_type;
// }
const choice_t rejection = sqrtf(d.len() * d.len() - dist_above_o * dist_above_o);
// The ray is tangent/missing the sphere
if(rejection >= self.r) return -1;
choice_t inside = sqrt(self.r*self.r - rejection*rejection) * K;
hit_dist = dist_above_o - inside;
hit_loc = eye + dir * hit_dist;
hit_normal = self.normal(hit_loc);
return self.surface_type;
}
int Sphere::intersect(const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
{ return _sphere_intersect(*this, eye, dir, hit_dist, hit_loc, hit_normal); }
int Sphere::transmit(const v3& eye, const v3& dir, choice_t& hit_dist, v3& hit_loc, v3& hit_normal)
{ return _sphere_intersect<-1>(*this, eye, dir, hit_dist, hit_loc, hit_normal); }
/* Light */
Light::Light(const v3& origin, choice_t r, const v3& colour) : Light(origin, r,
Material{ .specular = 0,
.roughness = 1,
.colour = colour }) {}
Light::Light(const v3& origin, choice_t r, const Material& specs) : Sphere(origin, r, specs, 0) {}