Culling (visibility helpers)
Mibo.Elmish.Culling is a helper module that keeps visibility math separate from your renderer and your spatial partitioning (the data structure that organizes objects by position).
It operates on geometric primitives:
- A view frustum (built from a camera or light View×Projection matrix; the frustum is the pyramid-shaped volume the camera sees)
- A bounding sphere / bounding box to test against it
- 2D rectangle overlap
3D: frustum culling
Build a frustum from a View×Projection matrix and test geometry against it. The frustum type is backend-specific: raylib ships its own Frustum (it has no native one), while MonoGame uses its native BoundingFrustum:
// raylib: Mibo.Elmish.Frustum over System.Numerics.Matrix4x4
let frustum = Frustum(viewProjection)
// MonoGame: Microsoft.Xna.Framework.BoundingFrustum
let frustum = BoundingFrustum(viewProjection)
if Culling.isVisible frustum entitySphere then
// submit draw commands
()
Or for axis-aligned bounding boxes:
if Culling.isVisibleBox frustum nodeBounds then
()
_Where does the View×Projection matrix come from?_ Neither backend's camera carries ready-made matrices. On MonoGame, build them from the
Camera3Dfields:Matrix.CreateLookAt(cam.Position, cam.Target, cam.Up)for the view, andMatrix.CreatePerspectiveFieldOfView(cam.FovY, aspect, cam.NearPlane, cam.FarPlane)for the projection. On raylib, capture the pair insideBeginMode3D(Rlgl.GetMatrixModelview() * Rlgl.GetMatrixProjection()), or build it fromRaylib.GetCameraMatrix3D(camera)and a perspective matrix.
2D: rectangle overlap
Use Camera2D.viewportBounds with Culling.isVisible2D (the rectangle type is
the backend's native one: float Rectangle on raylib, int Rectangle on
MonoGame):
// raylib: viewportBounds takes the camera by reference (&)
let viewBounds = Camera2D.viewportBounds &camera viewportWidth viewportHeight
// MonoGame: immutable camera, passed by value
let viewBounds = Camera2D.viewportBounds camera viewportWidth viewportHeight
if Culling.isVisible2D viewBounds spriteBounds then
()
What this is not
This module doesn't try to be your spatial index.
- If you have many objects: use a grid / quadtree / BVH / octree.
- Use these helpers at the edge: "is this node/object worth considering for rendering?"
See also: Camera and Rendering overview.
Mibo