1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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;
}
|