@ -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 | |||