@ -1,208 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_AABB_HPP | |||||
#define ANTKEEPER_GEOM_AABB_HPP | |||||
#include <engine/geom/bounding-volume.hpp> | |||||
#include <engine/geom/sphere.hpp> | |||||
#include <engine/math/vector.hpp> | |||||
#include <engine/math/matrix.hpp> | |||||
#include <engine/math/transform-type.hpp> | |||||
#include <limits> | |||||
namespace geom { | |||||
/** | |||||
* Axis-aligned bounding box. | |||||
*/ | |||||
template <class T> | |||||
struct aabb: public bounding_volume<T> | |||||
{ | |||||
typedef math::vector<T, 3> vector_type; | |||||
typedef math::matrix<T, 4, 4> matrix_type; | |||||
typedef math::transform<T> transform_type; | |||||
vector_type min_point; | |||||
vector_type max_point; | |||||
/** | |||||
* Transforms an AABB. | |||||
* | |||||
* @param a AABB to be transformed. | |||||
* @param t Transform by which the AABB should be transformed. | |||||
* @return Transformed AABB. | |||||
*/ | |||||
static aabb transform(const aabb& a, const transform_type& t); | |||||
/** | |||||
* Transforms an AABB. | |||||
* | |||||
* @param a AABB to be transformed. | |||||
* @param m Matrix by which the AABB should be transformed. | |||||
* @return Transformed AABB. | |||||
*/ | |||||
static aabb transform(const aabb& a, const matrix_type& m); | |||||
aabb(const vector_type& min_point, const vector_type& max_point); | |||||
aabb(); | |||||
virtual bounding_volume_type get_bounding_volume_type() const; | |||||
virtual bool intersects(const sphere<T>& sphere) const; | |||||
virtual bool intersects(const aabb<T>& aabb) const; | |||||
virtual bool contains(const sphere<T>& sphere) const; | |||||
virtual bool contains(const aabb<T>& aabb) const; | |||||
virtual bool contains(const vector_type& point) const; | |||||
/** | |||||
* Returns the position of the specified corner. | |||||
* | |||||
* @param index Index of a corner. | |||||
* @return Position of the specified corner. | |||||
*/ | |||||
vector_type corner(std::size_t index) const noexcept; | |||||
}; | |||||
template <class T> | |||||
aabb<T> aabb<T>::transform(const aabb& a, const transform_type& t) | |||||
{ | |||||
vector_type min_point = {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()}; | |||||
vector_type max_point = {-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity()}; | |||||
for (std::size_t i = 0; i < 8; ++i) | |||||
{ | |||||
vector_type transformed_corner = math::mul(t, a.corner(i)); | |||||
for (std::size_t j = 0; j < 3; ++j) | |||||
{ | |||||
min_point[j] = std::min<T>(min_point[j], transformed_corner[j]); | |||||
max_point[j] = std::max<T>(max_point[j], transformed_corner[j]); | |||||
} | |||||
} | |||||
return {min_point, max_point}; | |||||
} | |||||
template <class T> | |||||
aabb<T> aabb<T>::transform(const aabb& a, const matrix_type& m) | |||||
{ | |||||
vector_type min_point = {std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity()}; | |||||
vector_type max_point = {-std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity(), -std::numeric_limits<T>::infinity()}; | |||||
for (std::size_t i = 0; i < 8; ++i) | |||||
{ | |||||
vector_type corner = a.corner(i); | |||||
math::vector<T, 4> transformed_corner = math::mul(m, math::vector<T, 4>{corner.x(), corner.y(), corner.z(), T{1}}); | |||||
for (std::size_t j = 0; j < 3; ++j) | |||||
{ | |||||
min_point[j] = std::min<T>(min_point[j], transformed_corner[j]); | |||||
max_point[j] = std::max<T>(max_point[j], transformed_corner[j]); | |||||
} | |||||
} | |||||
return {min_point, max_point}; | |||||
} | |||||
template <class T> | |||||
aabb<T>::aabb(const vector_type& min_point, const vector_type& max_point): | |||||
min_point(min_point), | |||||
max_point(max_point) | |||||
{} | |||||
template <class T> | |||||
aabb<T>::aabb() | |||||
{} | |||||
template <class T> | |||||
inline bounding_volume_type aabb<T>::get_bounding_volume_type() const | |||||
{ | |||||
return bounding_volume_type::aabb; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::intersects(const sphere<T>& sphere) const | |||||
{ | |||||
const vector_type radius_vector = {sphere.radius, sphere.radius, sphere.radius}; | |||||
return aabb<T>(min_point - radius_vector, max_point + radius_vector).contains(sphere.center); | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::intersects(const aabb<T>& aabb) const | |||||
{ | |||||
if (max_point.x() < aabb.min_point.x() || min_point.x() > aabb.max_point.x()) | |||||
return false; | |||||
if (max_point.y() < aabb.min_point.y() || min_point.y() > aabb.max_point.y()) | |||||
return false; | |||||
if (max_point.z() < aabb.min_point.z() || min_point.z() > aabb.max_point.z()) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::contains(const sphere<T>& sphere) const | |||||
{ | |||||
if (sphere.center.x() - sphere.radius < min_point.x() || sphere.center.x() + sphere.radius > max_point.x()) | |||||
return false; | |||||
if (sphere.center.y() - sphere.radius < min_point.y() || sphere.center.y() + sphere.radius > max_point.y()) | |||||
return false; | |||||
if (sphere.center.z() - sphere.radius < min_point.z() || sphere.center.z() + sphere.radius > max_point.z()) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::contains(const aabb<T>& aabb) const | |||||
{ | |||||
if (aabb.min_point.x() < min_point.x() || aabb.max_point.x() > max_point.x()) | |||||
return false; | |||||
if (aabb.min_point.y() < min_point.y() || aabb.max_point.y() > max_point.y()) | |||||
return false; | |||||
if (aabb.min_point.z() < min_point.z() || aabb.max_point.z() > max_point.z()) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool aabb<T>::contains(const vector_type& point) const | |||||
{ | |||||
if (point.x() < min_point.x() || point.x() > max_point.x()) | |||||
return false; | |||||
if (point.y() < min_point.y() || point.y() > max_point.y()) | |||||
return false; | |||||
if (point.z() < min_point.z() || point.z() > max_point.z()) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
typename aabb<T>::vector_type aabb<T>::corner(std::size_t index) const noexcept | |||||
{ | |||||
return | |||||
{ | |||||
((index >> 2) & 1) ? max_point[0] : min_point[0], | |||||
((index >> 1) & 1) ? max_point[1] : min_point[1], | |||||
((index >> 0) & 1) ? max_point[2] : min_point[2] | |||||
}; | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_AABB_HPP | |||||
@ -1,95 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_BOUNDING_VOLUME_HPP | |||||
#define ANTKEEPER_GEOM_BOUNDING_VOLUME_HPP | |||||
#include <engine/math/vector.hpp> | |||||
#include <stdexcept> | |||||
namespace geom { | |||||
template <class T> | |||||
struct sphere; | |||||
template <class T> | |||||
struct aabb; | |||||
/// Enumerates bounding volume types. | |||||
enum class bounding_volume_type | |||||
{ | |||||
aabb, ///< Indicates the bounding volume is an axis-aligned bounding box. | |||||
sphere, ///< Indicates the bounding volume is a sphere. | |||||
convex_hull ///< Indicates the bounding volume is a convex hull. | |||||
}; | |||||
/** | |||||
* Abstract base class for bounding volumes. | |||||
* | |||||
* @tparam T Scalar type. | |||||
*/ | |||||
template <class T> | |||||
class bounding_volume | |||||
{ | |||||
public: | |||||
/// Returns the enumerated type of this bounding volume. | |||||
virtual bounding_volume_type get_bounding_volume_type() const = 0; | |||||
/// Tests for intersection between this bounding volume and a bounding sphere. | |||||
virtual bool intersects(const sphere<T>& sphere) const = 0; | |||||
/// Tests for intersection between this bounding volume and an axis-aligned bounding box. | |||||
virtual bool intersects(const aabb<T>& aabb) const = 0; | |||||
/// Tests whether this bounding volume contains a sphere. | |||||
virtual bool contains(const sphere<T>& sphere) const = 0; | |||||
/// Tests whether this bounding volume contains an axis-aligned bounding box. | |||||
virtual bool contains(const aabb<T>& aabb) const = 0; | |||||
/// Tests whether this bounding volume contains a point. | |||||
virtual bool contains(const math::vector<T, 3>& point) const = 0; | |||||
/// Tests for intersection between this bounding volume and another bounding volume. | |||||
bool intersects(const bounding_volume& volume) const; | |||||
}; | |||||
/// Tests for intersection between this bounding volume and another bounding volume. | |||||
template <class T> | |||||
bool bounding_volume<T>::intersects(const bounding_volume& volume) const | |||||
{ | |||||
const bounding_volume_type type = volume.get_bounding_volume_type(); | |||||
switch (type) | |||||
{ | |||||
case bounding_volume_type::sphere: | |||||
return intersects(static_cast<const sphere<T>&>(volume)); | |||||
break; | |||||
case bounding_volume_type::aabb: | |||||
return intersects(static_cast<const aabb<T>&>(volume)); | |||||
break; | |||||
default: | |||||
throw std::runtime_error("unimplemented"); | |||||
break; | |||||
} | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_BOUNDING_VOLUME_HPP |
@ -1,143 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_CONVEX_HULL_HPP | |||||
#define ANTKEEPER_GEOM_CONVEX_HULL_HPP | |||||
#include <engine/geom/bounding-volume.hpp> | |||||
#include <engine/geom/plane.hpp> | |||||
#include <engine/geom/sphere.hpp> | |||||
#include <engine/geom/aabb.hpp> | |||||
#include <cstddef> | |||||
#include <vector> | |||||
namespace geom { | |||||
/** | |||||
* A plane-bounded convex hull. | |||||
*/ | |||||
template <class T> | |||||
struct convex_hull: public bounding_volume<T> | |||||
{ | |||||
/// Vector of planes with descibe the bounds of the convex hull. | |||||
std::vector<plane<T>> planes; | |||||
/** | |||||
* Creates a convex hull. | |||||
* | |||||
* @param size Number of planes the convex hull should accommodate. | |||||
*/ | |||||
explicit convex_hull(std::size_t size); | |||||
/// Creates a convex hull. | |||||
convex_hull(); | |||||
virtual bounding_volume_type get_bounding_volume_type() const; | |||||
virtual bool intersects(const sphere<T>& sphere) const; | |||||
virtual bool intersects(const aabb<T>& aabb) const; | |||||
virtual bool contains(const sphere<T>& sphere) const; | |||||
virtual bool contains(const aabb<T>& aabb) const; | |||||
virtual bool contains(const math::vector<T, 3>& point) const; | |||||
}; | |||||
template <class T> | |||||
convex_hull<T>::convex_hull(std::size_t size): | |||||
planes(size, plane<T>()) | |||||
{} | |||||
template <class T> | |||||
convex_hull<T>::convex_hull() | |||||
{} | |||||
template <class T> | |||||
inline bounding_volume_type convex_hull<T>::get_bounding_volume_type() const | |||||
{ | |||||
return bounding_volume_type::convex_hull; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::intersects(const sphere<T>& sphere) const | |||||
{ | |||||
for (const plane<T>& plane: planes) | |||||
if (plane.signed_distance(sphere.center) < -sphere.radius) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::intersects(const aabb<T>& aabb) const | |||||
{ | |||||
math::vector<T, 3> pv; | |||||
for (const plane<T>& plane: planes) | |||||
{ | |||||
pv.x() = (plane.normal.x() > T(0)) ? aabb.max_point.x() : aabb.min_point.x(); | |||||
pv.y() = (plane.normal.y() > T(0)) ? aabb.max_point.y() : aabb.min_point.y(); | |||||
pv.z() = (plane.normal.z() > T(0)) ? aabb.max_point.z() : aabb.min_point.z(); | |||||
if (plane.signed_distance(pv) < T(0)) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::contains(const sphere<T>& sphere) const | |||||
{ | |||||
for (const plane<T>& plane: planes) | |||||
if (plane.signed_distance(sphere.center) < sphere.radius) | |||||
return false; | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::contains(const aabb<T>& aabb) const | |||||
{ | |||||
math::vector<T, 3> pv; | |||||
math::vector<T, 3> nv; | |||||
for (const plane<T>& plane: planes) | |||||
{ | |||||
pv.x() = (plane.normal.x() > T(0)) ? aabb.max_point.x() : aabb.min_point.x(); | |||||
pv.y() = (plane.normal.y() > T(0)) ? aabb.max_point.y() : aabb.min_point.y(); | |||||
pv.z() = (plane.normal.z() > T(0)) ? aabb.max_point.z() : aabb.min_point.z(); | |||||
nv.x() = (plane.normal.x() < T(0)) ? aabb.max_point.x() : aabb.min_point.x(); | |||||
nv.y() = (plane.normal.y() < T(0)) ? aabb.max_point.y() : aabb.min_point.y(); | |||||
nv.z() = (plane.normal.z() < T(0)) ? aabb.max_point.z() : aabb.min_point.z(); | |||||
if (plane.signed_distance(pv) < T(0) || plane.signed_distance(nv) < T(0)) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
template <class T> | |||||
bool convex_hull<T>::contains(const math::vector<T, 3>& point) const | |||||
{ | |||||
for (const plane<T>& plane: planes) | |||||
if (plane.signed_distance(point) < T(0)) | |||||
return false; | |||||
return true; | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_CONVEX_HULL_HPP | |||||
@ -1,187 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include <engine/geom/intersection.hpp> | |||||
#include <limits> | |||||
namespace geom { | |||||
std::tuple<bool, float> ray_plane_intersection(const ray<float>& ray, const plane<float>& plane) | |||||
{ | |||||
float denom = math::dot(ray.direction, plane.normal); | |||||
if (denom != 0.0f) | |||||
{ | |||||
float t = -(math::dot(ray.origin, plane.normal) + plane.distance) / denom; | |||||
if (t >= 0.0f) | |||||
{ | |||||
return std::make_tuple(true, t); | |||||
} | |||||
} | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity()); | |||||
} | |||||
std::tuple<bool, float, float, float> ray_triangle_intersection(const ray<float>& ray, const float3& a, const float3& b, const float3& c) | |||||
{ | |||||
// Find edges | |||||
float3 edge10 = b - a; | |||||
float3 edge20 = c - a; | |||||
// Calculate determinant | |||||
float3 pv = math::cross(ray.direction, edge20); | |||||
float det = math::dot(edge10, pv); | |||||
if (!det) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
float inverse_det = 1.0f / det; | |||||
// Calculate u | |||||
float3 tv = ray.origin - a; | |||||
float u = math::dot(tv, pv) * inverse_det; | |||||
if (u < 0.0f || u > 1.0f) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
// Calculate v | |||||
float3 qv = math::cross(tv, edge10); | |||||
float v = math::dot(ray.direction, qv) * inverse_det; | |||||
if (v < 0.0f || u + v > 1.0f) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
// Calculate t | |||||
float t = math::dot(edge20, qv) * inverse_det; | |||||
if (t > 0.0f) | |||||
{ | |||||
return std::make_tuple(true, t, u, v); | |||||
} | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), 0.0f, 0.0f); | |||||
} | |||||
std::tuple<bool, float, float> ray_aabb_intersection(const ray<float>& ray, const aabb<float>& aabb) | |||||
{ | |||||
float t0 = -std::numeric_limits<float>::infinity(); | |||||
float t1 = std::numeric_limits<float>::infinity(); | |||||
for (std::size_t i = 0; i < 3; ++i) | |||||
{ | |||||
if (ray.direction[i] == 0.0f) | |||||
{ | |||||
if (ray.origin[i] < aabb.min_point[i] || ray.origin[i] > aabb.max_point[i]) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()); | |||||
} | |||||
} | |||||
else | |||||
{ | |||||
float tmin = (aabb.min_point[i] - ray.origin[i]) / ray.direction[i]; | |||||
float tmax = (aabb.max_point[i] - ray.origin[i]) / ray.direction[i]; | |||||
t0 = std::max(t0, std::min(tmin, tmax)); | |||||
t1 = std::min(t1, std::max(tmin, tmax)); | |||||
} | |||||
} | |||||
if (t0 > t1 || t1 < 0.0f) | |||||
{ | |||||
return std::make_tuple(false, std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity()); | |||||
} | |||||
return std::make_tuple(true, t0, t1); | |||||
} | |||||
std::tuple<bool, float, float, std::size_t, std::size_t> ray_mesh_intersection(const ray<float>& ray, const mesh& mesh) | |||||
{ | |||||
const std::vector<mesh::face*>& triangles = mesh.get_faces(); | |||||
bool intersection = false; | |||||
float t0 = std::numeric_limits<float>::infinity(); | |||||
float t1 = -std::numeric_limits<float>::infinity(); | |||||
std::size_t index0 = triangles.size(); | |||||
std::size_t index1 = triangles.size(); | |||||
for (std::size_t i = 0; i < triangles.size(); ++i) | |||||
{ | |||||
const mesh::face* triangle = triangles[i]; | |||||
const float3& a = reinterpret_cast<const float3&>(triangle->edge->vertex->position); | |||||
const float3& b = reinterpret_cast<const float3&>(triangle->edge->next->vertex->position); | |||||
const float3& c = reinterpret_cast<const float3&>(triangle->edge->previous->vertex->position); | |||||
auto result = ray_triangle_intersection(ray, a, b, c); | |||||
if (std::get<0>(result)) | |||||
{ | |||||
intersection = true; | |||||
float t = std::get<1>(result); | |||||
if (t < t0) | |||||
{ | |||||
t0 = t; | |||||
index0 = i; | |||||
} | |||||
if (t > t1) | |||||
{ | |||||
t1 = t; | |||||
index1 = i; | |||||
} | |||||
} | |||||
} | |||||
return std::make_tuple(intersection, t0, t1, index0, index1); | |||||
} | |||||
bool aabb_aabb_intersection(const aabb<float>& a, const aabb<float>& b) | |||||
{ | |||||
if (a.max_point.x() < b.min_point.x() || a.min_point.x() > b.max_point.x()) | |||||
return false; | |||||
if (a.max_point.y() < b.min_point.y() || a.min_point.y() > b.max_point.y()) | |||||
return false; | |||||
if (a.max_point.z() < b.min_point.z() || a.min_point.z() > b.max_point.z()) | |||||
return false; | |||||
return true; | |||||
} | |||||
bool aabb_sphere_intersection(const aabb<float>& aabb, const float3& center, float radius) | |||||
{ | |||||
float sqr_distance = 0.0f; | |||||
for (int i = 0; i < 3; ++i) | |||||
{ | |||||
float v = center[i]; | |||||
if (v < aabb.min_point[i]) | |||||
sqr_distance += (aabb.min_point[i] - v) * (aabb.min_point[i] - v); | |||||
if (v > aabb.max_point[i]) | |||||
sqr_distance += (v - aabb.max_point[i]) * (v - aabb.max_point[i]); | |||||
} | |||||
return (sqr_distance <= (radius * radius)); | |||||
} | |||||
} // namespace geom |
@ -1,123 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_PLANE_HPP | |||||
#define ANTKEEPER_GEOM_PLANE_HPP | |||||
#include <engine/math/vector.hpp> | |||||
namespace geom { | |||||
/** | |||||
* A flat 2-dimensional surface. | |||||
*/ | |||||
template <class T> | |||||
struct plane | |||||
{ | |||||
typedef math::vector<T, 3> vector_type; | |||||
/// Plane normal vector. | |||||
vector_type normal; | |||||
/// Plane distance. | |||||
T distance; | |||||
/** | |||||
* Creates a plane given a normal vector and distance. | |||||
*/ | |||||
plane(const vector_type& normal, T distance); | |||||
/** | |||||
* Creates a plane given a normal vector and offset vector. | |||||
*/ | |||||
plane(const vector_type& normal, const vector_type& offset); | |||||
/** | |||||
* Creates a plane given three points. | |||||
*/ | |||||
plane(const vector_type& a, const vector_type& b, const vector_type& c); | |||||
/** | |||||
* Creates a plane given its coefficients. | |||||
* | |||||
* @param coefficients Vector containing the plane coefficients, A, B, C and D, as x, y, z, and w, respectively. | |||||
*/ | |||||
explicit plane(const math::vector<T, 4>& coefficients); | |||||
/// Creates an uninitialized plane. | |||||
plane() = default; | |||||
/** | |||||
* Calculates the signed distance between a plane and a vector. | |||||
* | |||||
* @param v Vector. | |||||
* @return Signed distance between the plane and vector. | |||||
*/ | |||||
T signed_distance(const vector_type& v) const; | |||||
/** | |||||
* Calculates the point of intersection between three planes. | |||||
*/ | |||||
static vector_type intersection(const plane& p0, const plane& p1, const plane& p2); | |||||
}; | |||||
template <class T> | |||||
inline plane<T>::plane(const vector_type& normal, T distance): | |||||
normal(normal), | |||||
distance(distance) | |||||
{} | |||||
template <class T> | |||||
plane<T>::plane(const vector_type& normal, const vector_type& offset): | |||||
normal(normal), | |||||
distance(-math::dot(normal, offset)) | |||||
{} | |||||
template <class T> | |||||
plane<T>::plane(const vector_type& a, const vector_type& b, const vector_type& c) | |||||
{ | |||||
normal = math::normalize(math::cross(c - b, a - b)); | |||||
distance = -(math::dot(normal, b)); | |||||
} | |||||
template <class T> | |||||
plane<T>::plane(const math::vector<T, 4>& coefficients) | |||||
{ | |||||
const vector_type abc = math::vector<T, 3>(coefficients); | |||||
const float inverse_length = T(1) / math::length(abc); | |||||
normal = abc * inverse_length; | |||||
distance = coefficients[3] * inverse_length; | |||||
} | |||||
template <class T> | |||||
inline T plane<T>::signed_distance(const vector_type& v) const | |||||
{ | |||||
return distance + math::dot(normal, v); | |||||
} | |||||
template <class T> | |||||
typename plane<T>::vector_type plane<T>::intersection(const plane& p0, const plane& p1, const plane& p2) | |||||
{ | |||||
return -(p0.distance * math::cross(p1.normal, p2.normal) + p1.distance * math::cross(p2.normal, p0.normal) + p2.distance * math::cross(p0.normal, p1.normal)) / math::dot(p0.normal, math::cross(p1.normal, p2.normal)); | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_PLANE_HPP |
@ -1,207 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_PRIMITIVES_INTERSECTION_HPP | |||||
#define ANTKEEPER_GEOM_PRIMITIVES_INTERSECTION_HPP | |||||
#include <engine/geom/primitives/hyperplane.hpp> | |||||
#include <engine/geom/primitives/hyperrectangle.hpp> | |||||
#include <engine/geom/primitives/hypersphere.hpp> | |||||
#include <engine/geom/primitives/ray.hpp> | |||||
#include <algorithm> | |||||
#include <optional> | |||||
namespace geom { | |||||
namespace primitive { | |||||
/** | |||||
* Ray-hyperplane intersection test. | |||||
* | |||||
* @param ray Ray. | |||||
* @param hyperplane Hyperplane. | |||||
* | |||||
* @return Distance along the ray to the point of intersection, or `std::nullopt` if no intersection occurred. | |||||
*/ | |||||
/// @{ | |||||
template <class T, std::size_t N> | |||||
constexpr std::optional<T> intersection(const ray<T, N>& ray, const hyperplane<T, N>& hyperplane) noexcept | |||||
{ | |||||
const T cos_theta = math::dot(ray.direction, hyperplane.normal); | |||||
if (cos_theta != T{0}) | |||||
{ | |||||
const T t = -hyperplane.distance(ray.origin) / cos_theta; | |||||
if (t >= T{0}) | |||||
return t; | |||||
} | |||||
return std::nullopt; | |||||
} | |||||
template <class T, std::size_t N> | |||||
inline constexpr std::optional<T> intersection(const hyperplane<T, N>& hyperplane, const ray<T, N>& ray) noexcept | |||||
{ | |||||
return intersection<T, N>(ray, hyperplane); | |||||
} | |||||
/// @} | |||||
/** | |||||
* Ray-hyperrectangle intersection test. | |||||
* | |||||
* @param ray Ray. | |||||
* @param hyperrectangle Hyperrectangle. | |||||
* | |||||
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred. | |||||
*/ | |||||
/// @{ | |||||
template <class T, std::size_t N> | |||||
constexpr std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hyperrectangle<T, N>& hyperrectangle) noexcept | |||||
{ | |||||
T t0 = -std::numeric_limits<T>::infinity(); | |||||
T t1 = std::numeric_limits<T>::infinity(); | |||||
for (std::size_t i = 0; i < N; ++i) | |||||
{ | |||||
if (!ray.direction[i]) | |||||
{ | |||||
if (ray.origin[i] < hyperrectangle.min[i] || ray.origin[i] > hyperrectangle.max[i]) | |||||
return std::nullopt; | |||||
} | |||||
else | |||||
{ | |||||
T min = (hyperrectangle.min[i] - ray.origin[i]) / ray.direction[i]; | |||||
T max = (hyperrectangle.max[i] - ray.origin[i]) / ray.direction[i]; | |||||
t0 = std::max(t0, std::min(min, max)); | |||||
t1 = std::min(t1, std::max(min, max)); | |||||
} | |||||
} | |||||
if (t0 > t1 || t1 < T{0}) | |||||
return std::nullopt; | |||||
return {t0, t1}; | |||||
} | |||||
template <class T, std::size_t N> | |||||
inline constexpr std::optional<std::tuple<T, T>> intersection(const hyperrectangle<T, N>& hyperrectangle, const ray<T, N>& ray) noexcept | |||||
{ | |||||
return intersection<T, N>(ray, hyperrectangle); | |||||
} | |||||
/// @} | |||||
/** | |||||
* Ray-hypersphere intersection test. | |||||
* | |||||
* @param ray Ray. | |||||
* @param hypersphere Hypersphere. | |||||
* | |||||
* @return Tuple containing the distances along the ray to the first and second points of intersection, or `std::nullopt` if no intersection occurred. | |||||
*/ | |||||
template <class T, std::size_t N> | |||||
std::optional<std::tuple<T, T>> intersection(const ray<T, N>& ray, const hypersphere<T, N>& hypersphere) noexcept | |||||
{ | |||||
const math::vector<T, N> displacement = ray.origin - hypersphere.center; | |||||
const T b = math::dot(displacement, ray.direction); | |||||
const T c = math::sqr_length(displacement) - hypersphere.radius * hypersphere.radius; | |||||
T h = b * b - c; | |||||
if (h < T{0}) | |||||
return std::nullopt; | |||||
h = std::sqrt(h); | |||||
T t0 = -b - h; | |||||
T t1 = -b + h; | |||||
if (t0 > t1) | |||||
std::swap(t0, t1); | |||||
if (t0 < T{0}) | |||||
return std::nullopt; | |||||
return std::tuple<T, T>{t0, t1}; | |||||
} | |||||
/** | |||||
* Hyperrectangle-hyperrectangle intersection test. | |||||
* | |||||
* @param a First hyperrectangle. | |||||
* @param b Second hyperrectangle. | |||||
* | |||||
* @return `true` if an intersection occurred, `false` otherwise. | |||||
*/ | |||||
template <class T, std::size_t N> | |||||
inline constexpr bool intersection(const hyperrectangle<T, N>& a, const hyperrectangle<T, N>& b) noexcept | |||||
{ | |||||
return a.intersects(b); | |||||
} | |||||
/** | |||||
* Hyperrectangle-hypersphere intersection test. | |||||
* | |||||
* @param hyperrectangle Hyperrectangle. | |||||
* @param hypersphere Hypersphere. | |||||
* | |||||
* @return `true` if an intersection occurred, `false` otherwise. | |||||
*/ | |||||
/// @{ | |||||
template <class T, std::size_t N> | |||||
constexpr bool intersection(const hyperrectangle<T, N>& hyperrectangle, const hypersphere<T, N>& hypersphere) noexcept | |||||
{ | |||||
T sqr_distance{0}; | |||||
for (std::size_t i = 0; i < N; ++i) | |||||
{ | |||||
if (hypersphere.center[i] < hyperrectangle.min[i]) | |||||
{ | |||||
const T difference = hyperrectangle.min[i] - hypersphere.center[i]; | |||||
sqr_distance += difference * difference; | |||||
} | |||||
else if (hypersphere.center[i] > hyperrectangle.max[i]) | |||||
{ | |||||
const T difference = hypersphere.center[i] - hyperrectangle.max[i]; | |||||
sqr_distance += difference * difference; | |||||
} | |||||
} | |||||
return sqr_distance <= hypersphere.radius * hypersphere.radius; | |||||
} | |||||
template <class T, std::size_t N> | |||||
inline constexpr bool intersection(const hypersphere<T, N>& hypersphere, const hyperrectangle<T, N>& hyperrectangle) noexcept | |||||
{ | |||||
return intersection<T, N>(hyperrectangle, hypersphere); | |||||
} | |||||
/// @} | |||||
/** | |||||
* Hypersphere-hypersphere intersection test. | |||||
* | |||||
* @param a First hypersphere. | |||||
* @param b Second hypersphere. | |||||
* | |||||
* @return `true` if an intersection occurred, `false` otherwise. | |||||
*/ | |||||
template <class T, std::size_t N> | |||||
inline constexpr bool intersection(const hypersphere<T, N>& a, const hypersphere<T, N>& b) noexcept | |||||
{ | |||||
return a.intersects(b); | |||||
} | |||||
} // namespace primitive | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_PRIMITIVES_INTERSECTION_HPP |
@ -0,0 +1,317 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_PRIMITIVES_VIEW_FRUSTUM_HPP | |||||
#define ANTKEEPER_GEOM_PRIMITIVES_VIEW_FRUSTUM_HPP | |||||
#include <engine/math/vector.hpp> | |||||
#include <engine/math/matrix.hpp> | |||||
#include <engine/geom/primitives/plane.hpp> | |||||
#include <engine/geom/primitives/box.hpp> | |||||
#include <engine/geom/primitives/sphere.hpp> | |||||
namespace geom { | |||||
namespace primitives { | |||||
/** | |||||
* View frustum. | |||||
* | |||||
* @tparam T Real type. | |||||
*/ | |||||
template <class T> | |||||
struct view_frustum | |||||
{ | |||||
/// Vector type. | |||||
using vector_type = math::vector<T, 3>; | |||||
/// Plane type. | |||||
using plane_type = geom::plane<T>; | |||||
/// View-projection matrix type. | |||||
using matrix_type = math::matrix<T, 4, 4>; | |||||
/// Box type. | |||||
using box_type = geom::box<T>; | |||||
/// Sphere type. | |||||
using sphere_type = geom::sphere<T>; | |||||
/// Constructs a view frustum | |||||
constexpr view_frustum() noexcept = default; | |||||
/** | |||||
* Constructs a view frustum by extracting planes from view-projection matrix. | |||||
* | |||||
* @param matrix View-projection matrix from which to extract view frustum planes. | |||||
*/ | |||||
inline explicit constexpr view_frustum(const matrix_type& matrix) noexcept | |||||
{ | |||||
extract(matrix); | |||||
} | |||||
/// Returns the left clipping plane. | |||||
/// @{ | |||||
[[nodiscard]] inline constexpr const plane_type& left() const noexcept | |||||
{ | |||||
return planes[0]; | |||||
} | |||||
[[nodiscard]] inline constexpr plane_type& left() noexcept | |||||
{ | |||||
return planes[0]; | |||||
} | |||||
/// @} | |||||
/// Returns the right clipping plane. | |||||
/// @{ | |||||
[[nodiscard]] inline constexpr const plane_type& right() const noexcept | |||||
{ | |||||
return planes[1]; | |||||
} | |||||
[[nodiscard]] inline constexpr plane_type& right() noexcept | |||||
{ | |||||
return planes[1]; | |||||
} | |||||
/// @} | |||||
/// Returns the bottom clipping plane. | |||||
/// @{ | |||||
[[nodiscard]] inline constexpr const plane_type& bottom() const noexcept | |||||
{ | |||||
return planes[2]; | |||||
} | |||||
[[nodiscard]] inline constexpr plane_type& bottom() noexcept | |||||
{ | |||||
return planes[2]; | |||||
} | |||||
/// @} | |||||
/// Returns the top clipping plane. | |||||
/// @{ | |||||
[[nodiscard]] inline constexpr const plane_type& top() const noexcept | |||||
{ | |||||
return planes[3]; | |||||
} | |||||
[[nodiscard]] inline constexpr plane_type& top() noexcept | |||||
{ | |||||
return planes[3]; | |||||
} | |||||
/// @} | |||||
/// Returns the near clipping plane. | |||||
/// @{ | |||||
[[nodiscard]] inline constexpr const plane_type& near() const noexcept | |||||
{ | |||||
return planes[4]; | |||||
} | |||||
[[nodiscard]] inline constexpr plane_type& near() noexcept | |||||
{ | |||||
return planes[4]; | |||||
} | |||||
/// @} | |||||
/// Returns the far clipping plane. | |||||
/// @{ | |||||
[[nodiscard]] inline constexpr const plane_type& far() const noexcept | |||||
{ | |||||
return planes[5]; | |||||
} | |||||
[[nodiscard]] inline constexpr plane_type& far() noexcept | |||||
{ | |||||
return planes[5]; | |||||
} | |||||
/// @} | |||||
/** | |||||
* Extracts the view frustum planes from a view-projection matrix. | |||||
* | |||||
* @param matrix View-projection matrix from which to extract view frustum planes. | |||||
*/ | |||||
void extract(const matrix_type& matrix) noexcept | |||||
{ | |||||
for (std::size_t i = 0; i < 6; ++i) | |||||
{ | |||||
plane_type& plane = planes[i]; | |||||
const std::size_t j = i >> 1; | |||||
// Extract plane coefficients | |||||
if (i % 2) | |||||
{ | |||||
plane.normal.x() = matrix[0][3] - matrix[0][j]; | |||||
plane.normal.y() = matrix[1][3] - matrix[1][j]; | |||||
plane.normal.z() = matrix[2][3] - matrix[2][j]; | |||||
plane.constant = matrix[3][3] - matrix[3][j]; | |||||
} | |||||
else | |||||
{ | |||||
plane.normal.x() = matrix[0][3] + matrix[0][j]; | |||||
plane.normal.y() = matrix[1][3] + matrix[1][j]; | |||||
plane.normal.z() = matrix[2][3] + matrix[2][j]; | |||||
plane.constant = matrix[3][3] + matrix[3][j]; | |||||
} | |||||
// Normalize plane coefficients | |||||
const T inv_length = math::inv_length(plane.normal); | |||||
plane.normal *= inv_length; | |||||
plane.constant *= inv_length; | |||||
} | |||||
} | |||||
/** | |||||
* Tests for intersection between an axis-aligned box and the view frustum. | |||||
* | |||||
* @param box Box to test for intersection with the view frustum. | |||||
* | |||||
* @return `true` if the axis-aligned box intersects the view frustum, `false` otherwise. | |||||
*/ | |||||
[[nodiscard]] bool intersects(const box_type& box) const noexcept | |||||
{ | |||||
for (const auto& plane: planes) | |||||
{ | |||||
const vector_type p | |||||
{ | |||||
(plane.normal.x() > T{0}) ? box.max.x() : box.min.x(), | |||||
(plane.normal.y() > T{0}) ? box.max.y() : box.min.y(), | |||||
(plane.normal.z() > T{0}) ? box.max.z() : box.min.z() | |||||
}; | |||||
if (plane.distance(p) < T{0}) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Tests for intersection between a sphere and the view frustum. | |||||
* | |||||
* @param sphere Sphere to test for intersection with the view frustum. | |||||
* | |||||
* @return `true` if the sphere intersects the view frustum, `false` otherwise. | |||||
*/ | |||||
[[nodiscard]] bool intersects(const sphere_type& sphere) const noexcept | |||||
{ | |||||
for (const auto& plane: planes) | |||||
{ | |||||
if (plane.distance(sphere.center) < -sphere.radius) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Tests whether a point is contained within this view frustum. | |||||
* | |||||
* @param point Point to test for containment. | |||||
* | |||||
* @return `true` if the point is contained within this view frustum, `false` otherwise. | |||||
*/ | |||||
[[nodiscard]] constexpr bool contains(const vector_type& point) const noexcept | |||||
{ | |||||
for (const auto& plane: planes) | |||||
{ | |||||
if (plane.distance(point) < T{0}) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Checks if an axis-aligned box is completely contained within the view frustum. | |||||
* | |||||
* @param box Box to test for containment within the view frustum. | |||||
* | |||||
* @return `true` if the axis-aligned box is completely contained within the view frustum, `false` otherwise. | |||||
*/ | |||||
[[nodiscard]] bool contains(const box_type& box) const noexcept | |||||
{ | |||||
for (const auto& plane: planes) | |||||
{ | |||||
const vector_type p | |||||
{ | |||||
(plane.normal.x() > T{0}) ? box.max.x() : box.min.x(), | |||||
(plane.normal.y() > T{0}) ? box.max.y() : box.min.y(), | |||||
(plane.normal.z() > T{0}) ? box.max.z() : box.min.z() | |||||
}; | |||||
const vector_type n | |||||
{ | |||||
(plane.normal.x() < T{0}) ? box.max.x() : box.min.x(), | |||||
(plane.normal.y() < T{0}) ? box.max.y() : box.min.y(), | |||||
(plane.normal.z() < T{0}) ? box.max.z() : box.min.z() | |||||
}; | |||||
if (plane.distance(p) < T{0} || plane.distance(n) < T{0}) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Checks if a sphere is completely contained within the view frustum. | |||||
* | |||||
* @param sphere Sphere to test for containment within the view frustum. | |||||
* | |||||
* @return `true` if the sphere is completely contained within the view frustum, `false` otherwise. | |||||
*/ | |||||
[[nodiscard]] bool contains(const sphere_type& sphere) const noexcept | |||||
{ | |||||
for (const auto& plane: planes) | |||||
{ | |||||
if (plane.distance(sphere.center) < sphere.radius) | |||||
{ | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* View frustum clipping planes. | |||||
* | |||||
* Clipping planes are stored in the following order: | |||||
* | |||||
* 1. left | |||||
* 2. right | |||||
* 3. bottom | |||||
* 4. top | |||||
* 5. near | |||||
* 6. far | |||||
*/ | |||||
plane_type planes[6]; | |||||
}; | |||||
} // namespace primitives | |||||
using namespace primitives; | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_PRIMITIVES_VIEW_FRUSTUM_HPP |
@ -1,59 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_RAY_HPP | |||||
#define ANTKEEPER_GEOM_RAY_HPP | |||||
#include <engine/math/vector.hpp> | |||||
namespace geom { | |||||
/** | |||||
* Half of a line proceeding from an initial point. | |||||
*/ | |||||
template <class T> | |||||
struct ray | |||||
{ | |||||
typedef math::vector<T, 3> vector_type; | |||||
/// Origin of the ray. | |||||
vector_type origin; | |||||
/// Normalized direction vector of the ray. | |||||
vector_type direction; | |||||
/** | |||||
* Extrapolates from the ray origin along the ray direction vector. | |||||
* | |||||
* @param distance Distance to extrapolate. | |||||
* @return Extrapolated coordinates. | |||||
*/ | |||||
vector_type extrapolate(T distance) const; | |||||
}; | |||||
template <class T> | |||||
inline typename ray<T>::vector_type ray<T>::extrapolate(T distance) const | |||||
{ | |||||
return origin + direction * distance; | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_RAY_HPP | |||||
@ -1,41 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_RECT_HPP | |||||
#define ANTKEEPER_GEOM_RECT_HPP | |||||
#include <engine/math/vector.hpp> | |||||
namespace geom { | |||||
/** | |||||
* 2D rectangle. | |||||
*/ | |||||
template <class T> | |||||
struct rect | |||||
{ | |||||
typedef math::vector<T, 2> vector_type; | |||||
vector_type min; | |||||
vector_type max; | |||||
}; | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_RECT_HPP |
@ -1,117 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_SPHERE_HPP | |||||
#define ANTKEEPER_GEOM_SPHERE_HPP | |||||
#include <engine/geom/bounding-volume.hpp> | |||||
#include <engine/geom/aabb.hpp> | |||||
#include <engine/math/vector.hpp> | |||||
#include <algorithm> | |||||
namespace geom { | |||||
/** | |||||
* Bounding sphere. | |||||
*/ | |||||
template <class T> | |||||
struct sphere: public bounding_volume<T> | |||||
{ | |||||
typedef math::vector<T, 3> vector_type; | |||||
vector_type center; | |||||
T radius; | |||||
sphere(const vector_type& center, T radius); | |||||
sphere(); | |||||
virtual bounding_volume_type get_bounding_volume_type() const; | |||||
virtual bool intersects(const sphere<T>& sphere) const; | |||||
virtual bool intersects(const aabb<T>& aabb) const; | |||||
virtual bool contains(const sphere<T>& sphere) const; | |||||
virtual bool contains(const aabb<T>& aabb) const; | |||||
virtual bool contains(const vector_type& point) const; | |||||
}; | |||||
template <class T> | |||||
sphere<T>::sphere(const vector_type& center, T radius): | |||||
center(center), | |||||
radius(radius) | |||||
{} | |||||
template <class T> | |||||
sphere<T>::sphere() | |||||
{} | |||||
template <class T> | |||||
inline bounding_volume_type sphere<T>::get_bounding_volume_type() const | |||||
{ | |||||
return bounding_volume_type::sphere; | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::intersects(const sphere<T>& sphere) const | |||||
{ | |||||
vector_type d = center - sphere.center; | |||||
T r = radius + sphere.radius; | |||||
return (math::dot(d, d) <= r * r); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::intersects(const aabb<T>& aabb) const | |||||
{ | |||||
return aabb.intersects(*this); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::contains(const sphere<T>& sphere) const | |||||
{ | |||||
T containment_radius = radius - sphere.radius; | |||||
if (containment_radius < T(0)) | |||||
return false; | |||||
vector_type d = center - sphere.center; | |||||
return (math::dot(d, d) <= containment_radius * containment_radius); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::contains(const aabb<T>& aabb) const | |||||
{ | |||||
T distance = T(0); | |||||
vector_type a = center - aabb.min_point; | |||||
vector_type b = center - aabb.max_point; | |||||
distance += std::max(a.x() * a.x(), b.x() * b.x()); | |||||
distance += std::max(a.y() * a.y(), b.y() * b.y()); | |||||
distance += std::max(a.z() * a.z(), b.z() * b.z()); | |||||
return (distance <= radius * radius); | |||||
} | |||||
template <class T> | |||||
bool sphere<T>::contains(const vector_type& point) const | |||||
{ | |||||
vector_type d = center - point; | |||||
return (math::dot(d, d) <= radius * radius); | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_SPHERE_HPP |
@ -1,190 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GEOM_VIEW_FRUSTUM_HPP | |||||
#define ANTKEEPER_GEOM_VIEW_FRUSTUM_HPP | |||||
#include <engine/geom/convex-hull.hpp> | |||||
#include <engine/math/vector.hpp> | |||||
#include <engine/math/matrix.hpp> | |||||
#include <array> | |||||
namespace geom { | |||||
/** | |||||
* View frustum. | |||||
*/ | |||||
template <class T> | |||||
class view_frustum | |||||
{ | |||||
public: | |||||
typedef math::vector<T, 3> vector_type; | |||||
typedef math::matrix<T, 4, 4> matrix_type; | |||||
typedef plane<T> plane_type; | |||||
/** | |||||
* Creates a view frustum from a view-projection matrix. | |||||
* | |||||
* @param view_projection View-projection matrix. | |||||
*/ | |||||
explicit view_frustum(const matrix_type& view_projection); | |||||
/// Creates an uninitialized view frustum. | |||||
view_frustum(); | |||||
/** | |||||
* Recalculates the view frustum from a view-projection matrix. | |||||
* | |||||
* @param view_projection View-projection matrix. | |||||
*/ | |||||
void set_matrix(const matrix_type& view_projection); | |||||
/// Returns a convex hull which describes the bounds of the view frustum. | |||||
const convex_hull<T>& get_bounds() const; | |||||
/// Returns the left clipping plane. | |||||
const plane_type& get_left() const; | |||||
/// Returns the right clipping plane. | |||||
const plane_type& get_right() const; | |||||
/// Returns the bottom clipping plane. | |||||
const plane_type& get_bottom() const; | |||||
/// Returns the top clipping plane. | |||||
const plane_type& get_top() const; | |||||
/// Returns the near clipping plane. | |||||
const plane_type& get_near() const; | |||||
/// Returns the far clipping plane. | |||||
const plane_type& get_far() const; | |||||
/** | |||||
* Returns an array containing the corners of the view frustum bounds. | |||||
* | |||||
* @return Array containing the corners of the view frustum bounds. Corners are stored in the following order: NTL, NTR, NBL, NBR, FTL, FTR, FBL, FBR; where N is near, F is far, T is top, B is bottom, L is left, and R is right, therefore NTL refers to the corner shared between the near, top, and left clipping planes. | |||||
*/ | |||||
const std::array<vector_type, 8>& get_corners() const; | |||||
private: | |||||
void recalculate_planes(const matrix_type& view_projection); | |||||
void recalculate_corners(); | |||||
convex_hull<T> bounds; | |||||
std::array<vector_type, 8> corners; | |||||
}; | |||||
template <class T> | |||||
view_frustum<T>::view_frustum(const matrix_type& view_projection): | |||||
bounds(6) | |||||
{ | |||||
set_matrix(view_projection); | |||||
} | |||||
template <class T> | |||||
view_frustum<T>::view_frustum(): | |||||
view_frustum(math::matrix4<T>::identity()) | |||||
{} | |||||
template <class T> | |||||
void view_frustum<T>::set_matrix(const matrix_type& view_projection) | |||||
{ | |||||
recalculate_planes(view_projection); | |||||
recalculate_corners(); | |||||
} | |||||
template <class T> | |||||
inline const convex_hull<T>& view_frustum<T>::get_bounds() const | |||||
{ | |||||
return bounds; | |||||
} | |||||
template <class T> | |||||
inline const typename view_frustum<T>::plane_type& view_frustum<T>::get_left() const | |||||
{ | |||||
return bounds.planes[0]; | |||||
} | |||||
template <class T> | |||||
inline const typename view_frustum<T>::plane_type& view_frustum<T>::get_right() const | |||||
{ | |||||
return bounds.planes[1]; | |||||
} | |||||
template <class T> | |||||
inline const typename view_frustum<T>::plane_type& view_frustum<T>::get_bottom() const | |||||
{ | |||||
return bounds.planes[2]; | |||||
} | |||||
template <class T> | |||||
inline const typename view_frustum<T>::plane_type& view_frustum<T>::get_top() const | |||||
{ | |||||
return bounds.planes[3]; | |||||
} | |||||
template <class T> | |||||
inline const typename view_frustum<T>::plane_type& view_frustum<T>::get_near() const | |||||
{ | |||||
return bounds.planes[4]; | |||||
} | |||||
template <class T> | |||||
inline const typename view_frustum<T>::plane_type& view_frustum<T>::get_far() const | |||||
{ | |||||
return bounds.planes[5]; | |||||
} | |||||
template <class T> | |||||
inline const std::array<typename view_frustum<T>::vector_type, 8>& view_frustum<T>::get_corners() const | |||||
{ | |||||
return corners; | |||||
} | |||||
template <class T> | |||||
void view_frustum<T>::recalculate_planes(const matrix_type& view_projection) | |||||
{ | |||||
matrix_type transpose = math::transpose(view_projection); | |||||
bounds.planes[0] = plane_type(transpose[3] + transpose[0]); | |||||
bounds.planes[1] = plane_type(transpose[3] - transpose[0]); | |||||
bounds.planes[2] = plane_type(transpose[3] + transpose[1]); | |||||
bounds.planes[3] = plane_type(transpose[3] - transpose[1]); | |||||
bounds.planes[4] = plane_type(transpose[3] + transpose[2]); | |||||
bounds.planes[5] = plane_type(transpose[3] - transpose[2]); | |||||
} | |||||
template <class T> | |||||
void view_frustum<T>::recalculate_corners() | |||||
{ | |||||
/// @TODO THESE CORNERS MAY BE INCORRECT!!!!!!!!!!! | |||||
corners[0] = plane_type::intersection(get_near(), get_top(), get_left()); | |||||
corners[1] = plane_type::intersection(get_near(), get_top(), get_right()); | |||||
corners[2] = plane_type::intersection(get_near(), get_bottom(), get_left()); | |||||
corners[3] = plane_type::intersection(get_near(), get_bottom(), get_right()); | |||||
corners[4] = plane_type::intersection(get_far(), get_top(), get_left()); | |||||
corners[5] = plane_type::intersection(get_far(), get_top(), get_right()); | |||||
corners[6] = plane_type::intersection(get_far(), get_bottom(), get_left()); | |||||
corners[7] = plane_type::intersection(get_far(), get_bottom(), get_right()); | |||||
} | |||||
} // namespace geom | |||||
#endif // ANTKEEPER_GEOM_VIEW_FRUSTUM_HPP | |||||
@ -1,39 +0,0 @@ | |||||
/* | |||||
* Copyright (C) 2023 Christopher J. Howard | |||||
* | |||||
* This file is part of Antkeeper source code. | |||||
* | |||||
* Antkeeper source code is free software: you can redistribute it and/or modify | |||||
* it under the terms of the GNU General Public License as published by | |||||
* the Free Software Foundation, either version 3 of the License, or | |||||
* (at your option) any later version. | |||||
* | |||||
* Antkeeper source code is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||||
* GNU General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU General Public License | |||||
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANTKEEPER_GAME_COLLISION_COMPONENT_HPP | |||||
#define ANTKEEPER_GAME_COLLISION_COMPONENT_HPP | |||||
#include <engine/geom/aabb.hpp> | |||||
#include <engine/geom/mesh.hpp> | |||||
#include <engine/geom/mesh-accelerator.hpp> | |||||
struct collision_component | |||||
{ | |||||
geom::mesh* mesh; | |||||
geom::aabb<float> bounds; | |||||
geom::mesh_accelerator mesh_accelerator; | |||||
float radius{0.0f}; | |||||
}; | |||||
#endif // ANTKEEPER_GAME_COLLISION_COMPONENT_HPP | |||||