-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Welcome to the poncelet wiki. This is a growing FAQ seeded from common questions — if yours isn't answered below, open an issue and we'll add it here.
For the full API and guarantees, start with README.md, docs/guide.md, and the cookbook for copy-pasteable recipes. This wiki is for the questions those don't answer directly.
The BitExact FMA bug hunt — a real cross-platform
determinism bug hunt: a "fixed" digest that turned out to be proof of the
wrong fix, and an Apple-Clang -O0 gap that ignored -ffp-contract=off.
bindings/ has four starting points:
- Godot 4 — a GDExtension over the C++ API. Pick this if you're on Godot; positions/directions pass straight through (both use SI metres, Y-up, right-handed).
- Unity — a native plugin, C# P/Invoke over the C ABI. Same frame convention as Godot, straight pass-through.
- Unreal Engine — the odd one out: UE is centimetres, Z-up. The plugin does a real coordinate conversion (see the mirrored-spin gotcha below) — don't try to reuse the Godot/Unity pattern of "just pass the vector through" here.
-
raylib — not an engine, just a rendering/windowing library, so this
is the smallest possible sample: no plugin system, no editor, a single
main.cppcallingpon::preview_arcdirectly. Good starting point if you're not using any of the above three, or just want the leanest possible reference for wiring poncelet into your own loop.
None of the four bindings pull in collision/geometry — that's always your
engine's job; poncelet's World callback is what you feed real hit
detection through.
-
Loose— no determinism guarantees at all, fastest. Fine for a single-player game where nobody's comparing two runs. -
PlatformStable(the default) — the same platform + compiler + inputs produce an identical trajectory every time. Enough for local replay/demo recording, but two different machines (say, a Windows client and a Linux dedicated server) are not guaranteed to agree bit-for-bit. -
BitExact— the integrator runs on a Q32.32 fixed-point core instead ofdouble, so the result is identical on every OS, compiler, and optimization level. This is the one you want for rollback netcode or server-authoritative hit validation, where a client and server (or two peers) silently disagreeing about a bullet's position means silently disagreeing about who died.
BitExact costs a small amount of accuracy (sub-millimetre over a
transonic kilometre flight in testing) and a small amount of performance
versus the double path — worth it only when cross-machine agreement is
actually load-bearing for your game.
Known, documented gap: the core integrator (drag, gravity, 6-DOF, spin
drift, Coriolis, the AdaptiveRKF45 step-size controller) is fully on the
fixed-point path now, but the guidance law's steering computation
(GuidanceDesc/compute_guidance) is still plain double. It's
per-platform-deterministic (same machine, same result every time) but not
yet guaranteed identical across different platforms. This is tracked as
future work — if you need bit-exact guided munitions specifically, open an
issue so it can be prioritized.
This is the one thing about the Unreal binding that can't be caught by an
automated test: converting between poncelet's right-handed metre frame and
UE's left-handed centimetre frame is an axis swap, which flips
chirality. Position and velocity round-trip exactly (that part is
tested), but a chirality-dependent effect computed inside poncelet's own
frame — Magnus lift direction (curveball curve), gyroscopic spin drift —
can come out mirrored relative to what looks intuitive from UE's side. If
it looks backwards: negate the converted spin axis's Y (poncelet-space)
component before spawning. See PonceletConversion.h in the Unreal
binding for the full explanation.
Check your launch height against your groundY. preview_arc stops once
the projectile's height reaches groundY — if you launch from exactly
y = 0 with groundY = 0.0, that check can trip on the very first sample
since you start exactly at it. Launch from a real height instead (a
standing shooter is usually ~1.5-1.7 m) the way every cookbook recipe and
example does.
No built-in zeroing function — it's a few lines of caller code around
preview_arc (bisect the launch pitch until point-of-impact matches
line-of-sight height at your zero range). Full worked example: cookbook
recipe 1 ("Real-dope sniper rifle").
No — poncelet never owns geometry. You supply a World (a raycast/medium/
material callback), and poncelet's integrator does the swept query against
it every sub-step. docs/examples/custom_world.cpp and
include/poncelet/worlds.hpp's stock primitives (PlaneWorld,
SphereWorld, AabbWorld, SlabStackWorld, CompositeWorld) are the
starting points depending on how much you want to write yourself.
Don't see your question here? Open an issue and it'll get added.