8auto get_transformed_bbox_vertices(
const bbox& AABB,
const transform& t) -> std::array<vec3, 8>
10 std::array<vec3, 8> vertices;
15 vertices[0] =
t.transform_coord(vec3(min.x, min.y, min.z));
16 vertices[1] =
t.transform_coord(vec3(max.x, min.y, min.z));
17 vertices[2] =
t.transform_coord(vec3(min.x, max.y, min.z));
18 vertices[3] =
t.transform_coord(vec3(max.x, max.y, min.z));
19 vertices[4] =
t.transform_coord(vec3(min.x, min.y, max.z));
20 vertices[5] =
t.transform_coord(vec3(max.x, min.y, max.z));
21 vertices[6] =
t.transform_coord(vec3(min.x, max.y, max.z));
22 vertices[7] =
t.transform_coord(vec3(max.x, max.y, max.z));
32 planes.fill(vec4(0.0f, 0.0f, 0.0f, 0.0f));
33 points.fill(vec3(0.0f, 0.0f, 0.0f));
39 update(View, Proj, homogeneousDepth);
127 vec3 forward = -vec3(
view[0][2],
view[1][2],
view[2][2]);
156 for(std::size_t i = 0; i < 8; ++i)
168 vec3 n1_n2 = glm::cross(n1, n2);
169 vec3 n2_n0 = glm::cross(n2, n0);
170 vec3 n0_n1 = glm::cross(n0, n1);
172 float cosTheta = glm::dot(n0, n1_n2);
173 float secTheta = 1.0f / cosTheta;
175 n1_n2 = n1_n2 * p0.
data.w;
176 n2_n0 = n2_n0 * p1.
data.w;
177 n0_n1 = n0_n1 * p2.
data.w;
179 points[i] = -(n1_n2 + n2_n0 + n0_n1) * secTheta;
190 for(
const auto&
plane : planes)
192 bool allOutside =
true;
193 bool anyOutside =
false;
196 for(
size_t i = 0; i <
count; ++i)
230 vec3 nearPoint, farPoint;
232 for(
const auto&
plane : planes)
234 nearPoint.x =
plane.
data.x > 0.0f ? AABB.min.x : AABB.max.x;
235 farPoint.x =
plane.
data.x > 0.0f ? AABB.max.x : AABB.min.x;
237 nearPoint.y =
plane.
data.y > 0.0f ? AABB.min.y : AABB.max.y;
238 farPoint.y =
plane.
data.y > 0.0f ? AABB.max.y : AABB.min.y;
240 nearPoint.z =
plane.
data.z > 0.0f ? AABB.min.z : AABB.max.z;
241 farPoint.z =
plane.
data.z > 0.0f ? AABB.max.z : AABB.min.z;
259 auto vertices = get_transformed_bbox_vertices(AABB, t);
260 return classify_vertices(vertices.data(), vertices.size());
266 vec3 nearPoint, farPoint;
268 if(lastOutside >= 0 && ((frustumBits >> lastOutside) & 0x1) == 0x0)
272 nearPoint.x =
plane.
data.x > 0.0f ? AABB.min.x : AABB.max.x;
273 farPoint.x =
plane.
data.x > 0.0f ? AABB.max.x : AABB.min.x;
275 nearPoint.y =
plane.
data.y > 0.0f ? AABB.min.y : AABB.max.y;
276 farPoint.y =
plane.
data.y > 0.0f ? AABB.max.y : AABB.min.y;
278 nearPoint.z =
plane.
data.z > 0.0f ? AABB.min.z : AABB.max.z;
279 farPoint.z =
plane.
data.z > 0.0f ? AABB.max.z : AABB.min.z;
292 frustumBits |= (0x1 << lastOutside);
296 for(
size_t i = 0; i < planes.size(); i++)
298 if(((frustumBits >> i) & 0x1) == 0x1)
300 if(lastOutside >= 0 && lastOutside ==
int(i))
305 nearPoint.x =
plane.
data.x > 0.0f ? AABB.min.x : AABB.max.x;
306 farPoint.x =
plane.
data.x > 0.0f ? AABB.max.x : AABB.min.x;
308 nearPoint.y =
plane.
data.y > 0.0f ? AABB.min.y : AABB.max.y;
309 farPoint.y =
plane.
data.y > 0.0f ? AABB.max.y : AABB.min.y;
311 nearPoint.z =
plane.
data.z > 0.0f ? AABB.min.z : AABB.max.z;
312 farPoint.z =
plane.
data.z > 0.0f ? AABB.max.z : AABB.min.z;
316 lastOutside = int(i);
326 frustumBits |= (0x1 << i);
338 for(
const auto&
plane : planes)
340 nearPoint.x =
plane.
data.x > 0.0f ? AABB.min.x : AABB.max.x;
341 nearPoint.y =
plane.
data.y > 0.0f ? AABB.min.y : AABB.max.y;
342 nearPoint.z =
plane.
data.z > 0.0f ? AABB.min.z : AABB.max.z;
359 for(
const auto&
plane : planes)
361 bool allOutside =
true;
363 for(
size_t i = 0; i < vert_count; ++i)
386 auto vertices = get_transformed_bbox_vertices(AABB, t);
387 return test_vertices(vertices.data(), vertices.size());
395 for(
const auto&
plane : planes)
400 if(fDot >= sphere.radius)
406 if(fDot >= -sphere.radius)
420 for(
const auto&
plane : planes)
425 if(fDot >= sphere.radius)
438 return test_sphere(
bsphere(t.transform_coord(sphere.position), sphere.radius));
441auto frustum::swept_sphere_intersect_plane(
float& t0,
445 const vec3& vecSweepDirection) ->
bool
452 if(b_dot_n <= sphere.radius)
456 t1 = std::numeric_limits<float>::max();
466 float tmp0 = (
sphere.radius - b_dot_n) / d_dot_n;
467 float tmp1 = (-
sphere.radius - b_dot_n) / d_dot_n;
468 t0 = glm::min<float>(tmp0, tmp1);
469 t1 = glm::max<float>(tmp0, tmp1);
477 if(test_sphere(sphere))
492 constexpr float sweep_parallel_epsilon = 1e-6f;
493 const float radius_tolerance = sphere.radius * 1.1f;
495 float t_enter = 0.0f;
496 float t_exit = (max_distance < 0.0f) ? std::numeric_limits<float>::infinity() : max_distance;
498 for(
const auto&
plane : planes)
504 if(glm::abs(d_dot_n) < sweep_parallel_epsilon)
507 if(b_dot_n > radius_tolerance)
514 const float t_bound = (radius_tolerance - b_dot_n) / d_dot_n;
518 t_exit = glm::min(t_exit, t_bound);
523 t_enter = glm::max(t_enter, t_bound);
532 return t_exit >= 0.0f;
548 constexpr float sweep_parallel_epsilon = 1e-6f;
550 float t_enter = 0.0f;
551 float t_exit = (max_distance < 0.0f) ? std::numeric_limits<float>::infinity() : max_distance;
553 for(
const auto&
plane : planes)
562 (
normal.x >= 0.0f) ? box.min.x : box.max.x,
563 (
normal.y >= 0.0f) ? box.min.y : box.max.y,
564 (
normal.z >= 0.0f) ? box.min.z : box.max.z
571 if(glm::abs(d_dot_n) < sweep_parallel_epsilon)
581 const float t_bound = -b_dot_n / d_dot_n;
585 t_exit = glm::min(t_exit, t_bound);
590 t_enter = glm::max(t_enter, t_bound);
599 return t_exit >= 0.0f;
604 return test_sphere(
bsphere(vecPoint, 0.0f));
609 int nCode1 = 0, nCode2 = 0;
610 float fDist1, fDist2, t;
612 vec3 vDir, vIntersect;
616 for(i = 0; i < 6; ++i)
621 nSide1 = (fDist1 >= 0) ? 1 : 0;
622 nSide2 = (fDist2 >= 0) ? 1 : 0;
626 nCode1 |= (nSide1 << i);
627 nCode2 |= (nSide2 << i);
631 if(nSide1 == 1 && nSide2 == 1)
637 if((nSide1 ^ nSide2) != 0)
644 if((t >= 0.0f) && (t <= 1.0f))
646 vIntersect = v1 + (vDir * t);
647 if(test_sphere(
bsphere(vIntersect, 0.01f)))
659 return (nCode1 == 0) || (nCode2 == 0);
664 unsigned int nInFrontCount = 0;
665 unsigned int nBehindCount = 0;
668 for(
unsigned int i = 0; i < 8; ++i)
683 if(nInFrontCount == 8)
689 if(nBehindCount == 8)
773 for(
auto&
plane : planes)
779 for(
auto&
point : points)
794 for(
size_t i = 0; i < planes.size(); ++i)
796 const plane& p1 = planes[i];
798 if(!(glm::abs<float>(p1.
data.x - p2.
data.x) <= glm::epsilon<float>() &&
799 glm::abs<float>(p1.
data.y - p2.
data.y) <= glm::epsilon<float>() &&
800 glm::abs<float>(p1.
data.z - p2.
data.z) <= glm::epsilon<float>() &&
801 glm::abs<float>(p1.
data.w - p2.
data.w) <= glm::epsilon<float>()))
Provides storage for common representation of spherical bounding volume, and wraps up common function...
Storage for frustum planes / values and wraps up common functionality.
auto test_swept_sphere(const bsphere &sphere, const vec3 &sweepDirection, float max_distance=-1.0f) const -> bool
Determine whether or not the specified sphere, swept along the provided direction vector,...
auto classify_aabb(const bbox &bounds) const -> volume_query
Classifies an axis-aligned bounding box (AABB) with respect to the frustum.
auto classify_sphere(const bsphere &sphere) const -> volume_query
Classifies a sphere with respect to the frustum.
auto test_swept_aabb(const bbox &box, const vec3 &sweepDirection, float max_distance=-1.0f) const -> bool
Determine whether or not the specified axis-aligned bounding box, swept along the provided direction ...
void recompute_points()
Recomputes the frustum's corner points based on its planes.
frustum()
Default constructor.
auto test_aabb(const bbox &bounds) const -> bool
Tests if an axis-aligned bounding box (AABB) is inside or intersecting the frustum.
auto test_point(const vec3 &point) const -> bool
Tests if a point is inside or intersecting the frustum.
auto test_sphere(const bsphere &sphere) const -> bool
Tests if a sphere is inside or intersecting the frustum.
auto mul(const transform &t) -> frustum &
Multiplies the frustum by a transform.
void update(const transform &view, const transform &proj, bool _oglNDC)
Updates the frustum based on the specified view and projection matrices.
std::array< plane, 6 > planes
< The 6 planes of the frustum.
auto test_vertices(const vec3 *vertices, size_t count) const -> bool
Tests if vertices are inside or intersect the frustum.
void set_planes(const std::array< plane, 6 > &new_planes)
Sets the frustum planes.
auto classify_plane(const plane &plane) const -> volume_query
Classifies a plane with respect to the frustum.
auto test_line(const vec3 &v1, const vec3 &v2) const -> bool
Tests if a line intersects the frustum.
auto classify_vertices(const vec3 *vertices, size_t count) const -> volume_query
Classifies vertices with respect to the frustum.
auto classify_obb(const bbox &bounds, const transform &t) const -> volume_query
Classifies an oriented bounding box (OBB) with respect to the frustum.
auto test_frustum(const frustum &frustum) const -> bool
Tests if another frustum intersects this frustum.
auto operator==(const frustum &f) const -> bool
Equality operator.
auto test_obb(const bbox &bounds, const transform &t) const -> bool
Tests if an oriented bounding box (OBB) is inside or intersecting the frustum.
std::array< vec3, 8 > points
The originating position of the frustum.
auto inverse(transform_t< T, Q > const &t) noexcept -> transform_t< T, Q >
transform_t< float > transform
auto transpose(transform_t< T, Q > const &t) noexcept -> transform_t< T, Q >
Storage for box vector values and wraps up common functionality.
plane get_plane(volume_plane::e side) const
Retrieves the plane for the specified side of the bounding box.
vec3 get_extents() const
Returns a vector containing the extents of the bounding box (the half-dimensions)
vec3 get_center() const
Returns a vector containing the exact center point of the box.
Storage for infinite plane.
static auto normalize(const plane &p) -> plane
Normalizes the plane.
static auto dot_normal(const plane &p, const vec3 &v) -> float
Computes the dot product of the plane normal and a vec3.
static auto dot_coord(const plane &p, const vec3 &v) -> float
Computes the dot product of the plane and a vec3 (considering the plane's distance).
static auto mul(const plane &p, const mat4 &m) -> plane
Transforms a plane by a 4x4 matrix.
vec4 data
The components of the plane.