CNA-BUG-066: BoundingFrustum::Contains(Vector3) answers Intersects for a point exactly on a plane and skips the remaining planes

CNA snapshot 009d40f5  ·  Known Issues › Current bugs  ·  source links pinned to 009d40f5

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 009d40f5; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

BoundingFrustum::Contains(point) returns Disjoint for any positive plane distance and, for a distance of exactly zero, Intersects without testing the remaining planes; XNA never answers Intersects for a point and uses a 1e-5 tolerance.

Identifier
CNA-BUG-066
Category
Bug
Subsystem
Math & geometry
Status
Open
Verified against
CNA 009d40f5 (009d40f5dd085c4e674d3479675fac84b12b3e0a)
Severity
Low (a triage suggestion, not a project priority)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
ContainmentType BoundingFrustum::Contains(Vector3) const and its output-parameter form; C ABI cna_bounding_frustum_contains_point

Expected behaviour

XNA 4.0 (read from the IL of the genuine XNA 4.0 Microsoft.Xna.Framework assembly; not executed) computes d = Dot(plane.Normal, point) + plane.D for each of the six planes, returns Disjoint as soon as d > 1E-05, and otherwise returns Contains. A point on a plane, or within the tolerance outside it, is contained; Intersects is never returned for a point.

Actual behaviour at TARGET

BoundingFrustum::Contains(const Vector3&, ContainmentType&) in BoundingFrustum.cpp returns Disjoint for d > 0.0f and, when d == 0.0f, sets Intersects and breaks out of the loop. So:

  • a point lying on one plane's extension but outside a later plane (plane order: near, far, left, right, top, bottom) is reported as Intersects instead of Disjoint;
  • a point exactly on the boundary is Intersects where XNA says Contains (this is the answer that makes BoundingFrustum::Intersects(Ray) throw, CNA-BUG-004);
  • a point up to 1e-5 outside a plane is Disjoint where XNA says Contains.

The code is an unchanged port of FNA's C# implementation (read at FNA commit 1358793, 2026-08-01).

Source locations

Evidence

Checked by reading at 009d40f5; nothing was built or executed for this entry. The loop was read; XNA's point test and tolerance were read from its IL. The Intersects(Ray) consequence is recorded in CNA-BUG-004.

Focused reproduction

Illustrative; not compiled or run for this entry.

BoundingFrustum f(Matrix::getIdentityProperty()); // planes z = 0 (near), z = 1 (far), x = +-1, y = +-1
ContainmentType a = f.Contains(Vector3(0.0f, 0.0f, 0.0f));   // on the near plane: XNA Contains, TARGET Intersects
ContainmentType b = f.Contains(Vector3(5.0f, 0.0f, 0.0f));   // on the near plane, outside the right plane:
                                                              // XNA Disjoint, TARGET Intersects

Current tests

The four point cases in BoundingFrustumTests.cpp use points clearly inside or outside. The C ABI GeometrySmoke.c asserts CNA_CONTAINMENT_INTERSECTS for the origin against the identity frustum, pinning the current on-plane answer; it must change with a fix.

Regression test

The two cases above (expecting Contains and Disjoint), a point 5e-6 outside a plane (Contains), and a point 2e-5 outside (Disjoint); update the C ABI smoke expectation for the origin.

Blast radius

Affected: both Contains(Vector3) overloads, cna_bounding_frustum_contains_point, and through it BoundingFrustum::Intersects(Ray). Not affected: frustum containment of boxes, spheres and frustums (they classify volumes against planes) and BoundingBox::Contains(const BoundingFrustum&) (it uses the box's own point test).

Workaround

Test the six planes yourself with a tolerance, treating a point as outside only when Dot(N, p) + D exceeds it.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index