diff options
| author | untodesu <kirill@untode.su> | 2025-12-26 17:29:40 +0500 |
|---|---|---|
| committer | untodesu <kirill@untode.su> | 2025-12-26 17:29:40 +0500 |
| commit | 50c6db34574ce5c9d67e9a7c70a7cafb19ac2007 (patch) | |
| tree | 730a59d1f08b8344df7653b98d884328449fc8d1 /src/game/shared/world/ray_aabb.cc | |
| parent | e73282ec5c8fd2b04cdae5c2641e7bc622ccce1f (diff) | |
| download | voxelius-50c6db34574ce5c9d67e9a7c70a7cafb19ac2007.tar.bz2 voxelius-50c6db34574ce5c9d67e9a7c70a7cafb19ac2007.zip | |
Rework collision. Possibly fixes #19
Diffstat (limited to 'src/game/shared/world/ray_aabb.cc')
| -rw-r--r-- | src/game/shared/world/ray_aabb.cc | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/game/shared/world/ray_aabb.cc b/src/game/shared/world/ray_aabb.cc new file mode 100644 index 0000000..f6f2638 --- /dev/null +++ b/src/game/shared/world/ray_aabb.cc @@ -0,0 +1,64 @@ +#include "shared/pch.hh" + +#include "shared/world/ray_aabb.hh" + +RayAABB::RayAABB(const glm::fvec3& start, const glm::fvec3& dir) noexcept +{ + reset(start, dir); +} + +void RayAABB::reset(const glm::fvec3& start, const glm::fvec3& dir) noexcept +{ + assert(std::isfinite(start.x)); + assert(std::isfinite(start.y)); + assert(std::isfinite(start.z)); + assert(std::isfinite(dir.x)); + assert(std::isfinite(dir.y)); + assert(std::isfinite(dir.z)); + + m_start_pos = start; + m_direction = dir; +} + +bool RayAABB::intersect(const math::AABBf& aabb, float& distance, glm::fvec3& surface) const noexcept +{ + // Adapted from https://github.com/gdbooks/3DCollisions/blob/master/Chapter3/raycast_aabb.md + + constexpr static std::array<glm::fvec3, 6> TNORMALS = { + glm::fvec3(-1.0f, 0.0f, 0.0f), + glm::fvec3(1.0f, 0.0f, 0.0f), + glm::fvec3(0.0f, -1.0f, 0.0f), + glm::fvec3(0.0f, 1.0f, 0.0f), + glm::fvec3(0.0f, 0.0f, -1.0f), + glm::fvec3(0.0f, 0.0f, 1.0f), + }; + + std::array<float, 6> tvalues; + tvalues[0] = (aabb.min.x - m_start_pos.x) / m_direction.x; + tvalues[1] = (aabb.max.x - m_start_pos.x) / m_direction.x; + tvalues[2] = (aabb.min.y - m_start_pos.y) / m_direction.y; + tvalues[3] = (aabb.max.y - m_start_pos.y) / m_direction.y; + tvalues[4] = (aabb.min.z - m_start_pos.z) / m_direction.z; + tvalues[5] = (aabb.max.z - m_start_pos.z) / m_direction.z; + + static_assert(tvalues.size() == TNORMALS.size()); + + auto tmin = std::max(std::max(std::min(tvalues[0], tvalues[1]), std::min(tvalues[2], tvalues[3])), std::min(tvalues[4], tvalues[5])); + auto tmax = std::min(std::min(std::max(tvalues[0], tvalues[1]), std::max(tvalues[2], tvalues[3])), std::max(tvalues[4], tvalues[5])); + + if(tmax < 0.0f || tmin > tmax) { + distance = std::numeric_limits<float>::quiet_NaN(); + return false; // no intersection + } + + for(std::size_t i = 0U; i < tvalues.size(); ++i) { + if(tvalues[i] == tmin) { + surface = TNORMALS[i]; + break; + } + } + + distance = tmin < 0.0f ? tmax : tmin; + + return true; +} |
