55#pragma once
66
77#include " omath/3d_primitives/aabb.hpp"
8+ #include " omath/3d_primitives/obb.hpp"
89#include " omath/linear_algebra/mat.hpp"
910#include " omath/linear_algebra/triangle.hpp"
1011#include " omath/linear_algebra/vector3.hpp"
@@ -380,49 +381,9 @@ namespace omath::projection
380381
381382 [[nodiscard]] bool is_aabb_culled_by_frustum (const primitives::Aabb<NumericType>& aabb) const noexcept
382383 {
383- const auto & m = get_view_projection_matrix ();
384-
385- // Gribb-Hartmann: extract 6 frustum planes from the view-projection matrix.
386- // Each plane is (a, b, c, d) such that ax + by + cz + d >= 0 means inside.
387- // For a 4x4 matrix with rows r0..r3:
388- // Left = r3 + r0
389- // Right = r3 - r0
390- // Bottom = r3 + r1
391- // Top = r3 - r1
392- // Near = r3 + r2 ([-1,1]) or r2 ([0,1])
393- // Far = r3 - r2
394- struct Plane final
395- {
396- NumericType a, b, c, d;
397- };
398-
399- const auto extract_plane = [&m](const int sign, const int row) -> Plane
400- {
401- return {
402- m.at (3 , 0 ) + static_cast <NumericType>(sign) * m.at (row, 0 ),
403- m.at (3 , 1 ) + static_cast <NumericType>(sign) * m.at (row, 1 ),
404- m.at (3 , 2 ) + static_cast <NumericType>(sign) * m.at (row, 2 ),
405- m.at (3 , 3 ) + static_cast <NumericType>(sign) * m.at (row, 3 ),
406- };
407- };
408-
409- std::array<Plane, 6 > planes = {
410- extract_plane (1 , 0 ), // left
411- extract_plane (-1 , 0 ), // right
412- extract_plane (1 , 1 ), // bottom
413- extract_plane (-1 , 1 ), // top
414- extract_plane (-1 , 2 ), // far
415- };
416-
417- // Near plane depends on NDC depth range
418- if constexpr (depth_range == NDCDepthRange::ZERO_TO_ONE)
419- planes[5 ] = {m.at (2 , 0 ), m.at (2 , 1 ), m.at (2 , 2 ), m.at (2 , 3 )};
420- else
421- planes[5 ] = extract_plane (1 , 2 );
422-
423384 // For each plane, find the AABB corner most in the direction of the plane normal
424385 // (the "positive vertex"). If it's outside, the entire AABB is outside.
425- for (const auto & [a, b, c, d] : planes )
386+ for (const auto & [a, b, c, d] : extract_frustum_planes () )
426387 {
427388 const auto px = a >= NumericType{0 } ? aabb.max .x : aabb.min .x ;
428389 const auto py = b >= NumericType{0 } ? aabb.max .y : aabb.min .y ;
@@ -435,6 +396,26 @@ namespace omath::projection
435396 return false ;
436397 }
437398
399+ [[nodiscard]] bool is_obb_culled_by_frustum (const primitives::Obb<NumericType>& obb) const noexcept
400+ {
401+ // For each plane, project the OBB extents onto the plane normal to get the
402+ // effective radius, then test the center's signed distance against it.
403+ for (const auto & [a, b, c, d] : extract_frustum_planes ())
404+ {
405+ const Vector3<NumericType> normal{a, b, c};
406+
407+ const auto center_distance = normal.dot (obb.center ) + d;
408+ const auto radius = obb.half_extents .x * std::abs (normal.dot (obb.axis_x ))
409+ + obb.half_extents .y * std::abs (normal.dot (obb.axis_y ))
410+ + obb.half_extents .z * std::abs (normal.dot (obb.axis_z ));
411+
412+ if (center_distance + radius < NumericType{0 })
413+ return true ;
414+ }
415+
416+ return false ;
417+ }
418+
438419 [[nodiscard]] std::expected<Vector3<NumericType>, Error>
439420 world_to_view_port (const Vector3<NumericType>& world_position,
440421 const ViewPortClipping& clipping = ViewPortClipping::AUTO) const noexcept
@@ -517,6 +498,51 @@ namespace omath::projection
517498 Vector3<NumericType> m_origin;
518499
519500 private:
501+ struct FrustumPlane final
502+ {
503+ NumericType a, b, c, d;
504+ };
505+
506+ // Gribb-Hartmann: extract 6 frustum planes from the view-projection matrix.
507+ // Each plane is (a, b, c, d) such that ax + by + cz + d >= 0 means inside.
508+ // For a 4x4 matrix with rows r0..r3:
509+ // Left = r3 + r0
510+ // Right = r3 - r0
511+ // Bottom = r3 + r1
512+ // Top = r3 - r1
513+ // Near = r3 + r2 ([-1,1]) or r2 ([0,1])
514+ // Far = r3 - r2
515+ [[nodiscard]] std::array<FrustumPlane, 6 > extract_frustum_planes () const noexcept
516+ {
517+ const auto & m = get_view_projection_matrix ();
518+
519+ const auto extract_plane = [&m](const int sign, const int row) -> FrustumPlane
520+ {
521+ return {
522+ m.at (3 , 0 ) + static_cast <NumericType>(sign) * m.at (row, 0 ),
523+ m.at (3 , 1 ) + static_cast <NumericType>(sign) * m.at (row, 1 ),
524+ m.at (3 , 2 ) + static_cast <NumericType>(sign) * m.at (row, 2 ),
525+ m.at (3 , 3 ) + static_cast <NumericType>(sign) * m.at (row, 3 ),
526+ };
527+ };
528+
529+ std::array<FrustumPlane, 6 > planes = {
530+ extract_plane (1 , 0 ), // left
531+ extract_plane (-1 , 0 ), // right
532+ extract_plane (1 , 1 ), // bottom
533+ extract_plane (-1 , 1 ), // top
534+ extract_plane (-1 , 2 ), // far
535+ };
536+
537+ // Near plane depends on NDC depth range
538+ if constexpr (depth_range == NDCDepthRange::ZERO_TO_ONE)
539+ planes[5 ] = {m.at (2 , 0 ), m.at (2 , 1 ), m.at (2 , 2 ), m.at (2 , 3 )};
540+ else
541+ planes[5 ] = extract_plane (1 , 2 );
542+
543+ return planes;
544+ }
545+
520546 template <class Type >
521547 [[nodiscard]] constexpr static bool is_ndc_out_of_bounds (const Type& ndc) noexcept
522548 {
0 commit comments