Math API
GodotECS.Math — pure static helpers, zero allocations, no LINQ/boxing. Source: addons/godotecs/src/math/.
Aabb
public struct Aabb
{
public Godot.Vector3 Min;
public Godot.Vector3 Max;
public Aabb(Godot.Vector3 min, Godot.Vector3 max) { Min = min; Max = max; }
public static Aabb FromCenterRadius(in Godot.Vector3 c, float r);
public static Aabb Merge(in Aabb a, in Aabb b);
public bool Overlaps(in Aabb o);
public bool Contains(in Godot.Vector3 p);
}FromCenterRadius builds {c - r, c + r}. Overlaps / Contains are inclusive on borders (touching counts). No constructor validation — a Min > Max box is simply empty under these tests.
EcsMath
public static class EcsMath
{
public static bool SimdSupported => EcsMathSimd.IsSupported; // SSE available
public static float Dot(in Godot.Vector3 a, in Godot.Vector3 b);
public static Godot.Vector3 Cross(in Godot.Vector3 a, in Godot.Vector3 b);
public static float LengthSq(in Godot.Vector3 v);
public static Godot.Vector3 NormalizeSafe(in Godot.Vector3 v); // Zero when |v|^2 <= 1e-12
public static Godot.Vector3 Lerp(in Godot.Vector3 a, in Godot.Vector3 b, float t);
public static bool SphereVsSphere(in Godot.Vector3 a, float ra, in Godot.Vector3 b, float rb,
out Godot.Vector3 normal, out float depth);
public static bool SphereVsSphereScalar(in Godot.Vector3 a, float ra, in Godot.Vector3 b, float rb,
out Godot.Vector3 normal, out float depth); // reference kernel
public static Godot.Vector3 ClosestPointBox(in Godot.Vector3 p,
in Godot.Vector3 boxMin, in Godot.Vector3 boxMax);
public static bool SphereVsBox(in Godot.Vector3 c, float r,
in Godot.Vector3 boxMin, in Godot.Vector3 boxMax,
out Godot.Vector3 normal, out float depth);
public static bool SphereVsBoxScalar(in Godot.Vector3 c, float r,
in Godot.Vector3 boxMin, in Godot.Vector3 boxMax,
out Godot.Vector3 normal, out float depth); // reference kernel
public static void IntegrateSoA(float[] px, float[] py, float[] pz,
float[] vx, float[] vy, float[] vz, int n, float dt);
public static void IntegrateSimd(float[] px, float[] py, float[] pz,
float[] vx, float[] vy, float[] vz, int n, float dt);
}
public static class EcsMathSimd
{
public static bool IsSupported => ...; // Sse.IsSupported (false on ARM/non-x86)
public static bool SphereVsSphereSimd(in Godot.Vector3 a, float ra,
in Godot.Vector3 b, float rb, out Godot.Vector3 normal, out float depth);
public static bool SphereVsBoxSimd(in Godot.Vector3 c, float r,
in Godot.Vector3 boxMin, in Godot.Vector3 boxMax,
out Godot.Vector3 normal, out float depth);
}SphereVsSphere / SphereVsBox are runtime dispatchers: on x86 with SSE they call the Vector128 SIMD kernels (EcsMathSimd, stack-only, zero allocations); otherwise the scalar path. The two paths are bit-identical by construction (same lane order, same horizontal sum, same thresholds) — verified by parity tests — so determinism holds across CPUs. SphereVsSphereScalar / SphereVsBoxScalar are the public reference kernels used as fallback and in parity tests.
Contact semantics: touching counts (dist <= ra + rb / dist <= r, depth ~ 0). Outputs on a miss are normal = Vector3.Zero, depth = 0. Degenerate cases pick an arbitrary axis rather than NaN: coincident sphere centers report normal +X with depth = ra + rb; a sphere center inside a box reports the minimum-penetration axis with depth = r + distance-to-nearest-face. IntegrateSoA is the scalar p += v * dt reference kernel; IntegrateSimd is the same kernel via System.Numerics.Vector<float> with a scalar tail for non-multiple counts. Measured note: the SIMD sphere kernel showed no end-to-end win in the physics bench (narrowphase is memory-bound) — it stays as the default path because parity is proven, not as a speed claim.
Frustum
public struct Frustum
{
// 6 planes as Vector4 (inward normal + W). A point is inside when N.p + W >= 0.
public Godot.Vector4 P0, P1, P2, P3, P4, P5;
public static Frustum FromCamera(Godot.Camera3D cam); // throws on null
public static Frustum FromCamera2D(Godot.Camera2D cam, Godot.Vector2 viewport);
public bool Intersects(in Aabb box); // p-vertex test
}FromCamera normalizes each plane from Camera3D.GetFrustum() and flips normals inward against the frustum center, so Intersects holds regardless of the engine's plane convention. FromCamera2D derives 4 side planes from screen-center position, zoom, and viewport size, plus two generous Z planes (-1000..1000) so 3D AABBs still test sensibly; near-zero zoom axes fall back to 1. Intersects tests only the furthest (p-)vertex per plane — exact for boxes.