2022-11-11 14:39:48 +01:00
|
|
|
#include "common/ray.h"
|
|
|
|
#include "primitive/box.h"
|
|
|
|
#include <cmath>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
// Constructor /////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
Box::Box(std::shared_ptr<Shader> const &shader) : Primitive(shader), size(Vector3d(1, 1, 1)) {}
|
|
|
|
|
|
|
|
Box::Box(Vector3d const ¢er, Vector3d const &size, std::shared_ptr<Shader> const &shader)
|
|
|
|
: Primitive(shader), center(center), size(size) {}
|
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
// Helper functions /////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
float intersectionParameterDimension(Vector3d bounds, Ray &ray, int dimension)
|
|
|
|
{
|
|
|
|
return (bounds[dimension] - ray.origin[dimension]) / ray.direction[dimension];
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3d intersectionParameter(Vector3d bounds, Ray &ray)
|
|
|
|
{
|
|
|
|
return Vector3d(intersectionParameterDimension(bounds, ray, 0),
|
|
|
|
intersectionParameterDimension(bounds, ray, 1),
|
|
|
|
intersectionParameterDimension(bounds, ray, 2));
|
|
|
|
}
|
|
|
|
|
2022-11-11 14:39:48 +01:00
|
|
|
// Primitive functions /////////////////////////////////////////////////////////
|
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
bool Box::intersect(Ray &ray) const
|
|
|
|
{
|
|
|
|
// IMPLEMENT ME!
|
|
|
|
|
|
|
|
// Determine whether the ray intersects the box
|
|
|
|
|
|
|
|
Vector3d minBounds(this->minimumBounds(0), this->minimumBounds(1), this->minimumBounds(2));
|
|
|
|
Vector3d maxBounds(this->maximumBounds(0), this->maximumBounds(1), this->maximumBounds(2));
|
|
|
|
|
|
|
|
Vector3d tMin = intersectionParameter(minBounds, ray);
|
|
|
|
Vector3d tMax = intersectionParameter(maxBounds, ray);
|
|
|
|
|
|
|
|
Vector3d tInAll = Vector3d(std::min(tMin[0], tMax[0]), std::min(tMin[1], tMax[1]), std::min(tMin[2], tMax[2]));
|
|
|
|
Vector3d tOutAll = Vector3d(std::max(tMin[0], tMax[0]), std::max(tMin[1], tMax[1]), std::max(tMin[2], tMax[2]));
|
|
|
|
|
|
|
|
float tIn = std::max(std::max(tInAll[0], tInAll[1]), tInAll[2]);
|
|
|
|
float tOut = std::min(std::min(tOutAll[0], tOutAll[1]), tOutAll[2]);
|
|
|
|
|
|
|
|
if (tIn > tOut || tOut < 0)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
float t = tIn;
|
|
|
|
|
|
|
|
// Test whether this is the foremost primitive in front of the camera
|
|
|
|
if (t >= ray.length)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2022-11-11 14:39:48 +01:00
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
// (Optional for now) Calculate the normal
|
|
|
|
// On what side of the box did the ray hit?
|
|
|
|
Vector3d normal;
|
|
|
|
if (tInAll[0] == tIn)
|
|
|
|
{
|
|
|
|
normal = Vector3d(1, 0, 0);
|
|
|
|
}
|
|
|
|
else if (tInAll[1] == tIn)
|
|
|
|
{
|
|
|
|
normal = Vector3d(0, 1, 0);
|
|
|
|
}
|
|
|
|
else // tInAll[2] == tIn
|
|
|
|
{
|
|
|
|
normal = Vector3d(0, 0, 1);
|
|
|
|
}
|
2022-11-11 14:39:48 +01:00
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
// Make sure sign is correct
|
|
|
|
if (dotProduct(ray.direction, normal) > 0)
|
|
|
|
{
|
|
|
|
normal = -normal;
|
|
|
|
}
|
2022-11-11 14:39:48 +01:00
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
ray.normal = normalized(normal);
|
2022-11-11 14:39:48 +01:00
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
// (Optional for now) Calculate the surface position
|
2022-11-11 14:39:48 +01:00
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
// Set the new length and the current primitive
|
|
|
|
ray.length = t;
|
|
|
|
ray.primitive = this;
|
2022-11-11 14:39:48 +01:00
|
|
|
|
2022-11-15 13:49:33 +01:00
|
|
|
return false;
|
2022-11-11 14:39:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Bounding box ////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
float Box::minimumBounds(int dimension) const { return this->center[dimension] - this->size[dimension] / 2; }
|
|
|
|
|
|
|
|
float Box::maximumBounds(int dimension) const { return this->center[dimension] + this->size[dimension] / 2; }
|