Skip to content

Large-World Coordinates

DigitalHeaven.Engine treats coordinate scale as an immutable property of each World. The first playable worlds use the Compact profile: ordinary float positions, float physics, float snapshots, and float rendering. A future Large profile can add high-precision authoritative translation without making every Compact entity pay for it today.

The design has two simultaneous requirements:

  1. A world must declare its coordinate representation before entities, physics, replication, or rendering are created, so adding Large worlds does not require discovering scale per entity later.
  2. Compact worlds must remain exactly as small and direct as they are now: no coordinate tags, branches, cells, conversions, extra fields, or generic-math abstraction in entity storage or hot loops.

The result is one decision per world, not one decision per entity.

CompactLarge (deferred)
Intended scaleMaps whose authoritative positions fit comfortably in float precisionWorlds that need precise authoritative translation far from (0, 0, 0)
ECS translationExisting Position(Vector3)Distinct LargePosition Contracts component with double XYZ
Physics world translationFloatBox3D double-capable world translation
Velocity and movement deltasFloatFloat-local
Rotation, extents, shapes, normals, manifolds, solver dataFloatFloat-local
SnapshotsExisting float codecSpecialized Large codec, initially capable of double XYZ
Replica interpolationFloat canonical positionsHigh-precision canonical positions
Rendering inputFloat world transformsCPU camera-relative float transforms
Meshes, vertex buffers, GPU matricesFloatFloat
CellsNoneOptional derived index or packet encoding, only when measured scale requires it

Both profiles keep the engine’s existing convention: meters, Y-up, right-handed, and -Z forward. A coordinate profile changes the precision and boundary rules for world translation; it does not define another handedness or unit system.

For a Compact World, an entity position remains the existing Position component containing one System.Numerics.Vector3. Compact snapshots continue to write three float coordinates. Physics and rendering continue through float-specialized implementations.

Selecting Compact must not add:

  • a mode/tag field beside each entity position;
  • an integer cell or local offset component;
  • a per-entity or per-query Compact/Large branch;
  • float-to-double-to-float conversions in Compact hot loops;
  • a larger union or tagged Position value;
  • World<T> or generic-math specialization;
  • extra Compact snapshot fields.

World construction currently selects the Compact physics adapter once. Future profile-specific gameplay systems and codecs will use the same construction-time profile rather than branching over entity data in their inner loops.

Clear names matter because “world space” alone is not precise enough once rendering and packet-relative encodings exist.

Canonical server space : The authoritative, origin-independent coordinate frame of a World. Simulation state and network meaning live here. Compact canonical positions are float; Large canonical translations are double.

Physics-local values : Relative translations, velocities, forces, shape dimensions, contact normals, solver values, and similar quantities used near an operation. These remain float in both profiles. Large mode raises the precision of absolute world translation, not every physical quantity.

Snapshot-relative space : An optional future wire encoding relative to an origin carried by that same snapshot. It is a compression representation, not authoritative ECS state.

Render-relative space : Presentation coordinates after subtracting the current client render origin. Model translations and camera data become small floats before GPU upload.

Mesh-local space : Float vertex and asset coordinates relative to an object or region. This stays float for every profile.

The M2 coordinate contract is intentionally small:

  • The design reserves an immutable WorldCoordinateProfile for every World, including a WorldCoordinateMode of Compact or, later, Large.
  • The profile is selected when the World is created and cannot change while the world is alive.
  • The profile is available to the networking layer for a future connection-handshake field before the client loads the map or interprets snapshots.
  • Construction dispatches once to a profile-aware physics factory. Profile-specific gameplay systems, snapshot codecs, replica storage, and renderer factories remain future integration points.
  • M2 remains Compact-only. Asking for Large fails during construction rather than falling back silently.

This is a world/session property, not content attached to entities. A process may eventually host Compact and Large worlds at the same time, but an entity belongs to one world and therefore has one unambiguous coordinate contract.

The current source has an explicit Compact profile:

  • Position still stores exactly one float Vector3.
  • Universe.CreateWorld validates the requested immutable profile before creating profile-matched physics.
  • World.CoordinateProfile and World.CoordinateMode expose that selection for future networking and rendering integration.
  • Physics advertises its supported coordinate mode through IPhysicsWorld; the current Box3D factory accepts Compact only.
  • Snapshots, replica interpolation, camera state, and renderer uniforms remain unchanged floats.

The first content that actually needs Large coordinates activates a separate path rather than widening the Compact one.

A LargePosition component will live in DigitalHeaven.Engine.Contracts, the stable schema assembly, and carry canonical double XYZ translation. It will be a distinct component, not another case hidden inside Position.

Large-specialized movement, physics, replication, and presentation systems query LargePosition. Compact systems continue to query Position. This keeps both schemas explicit and lets the construction-time profile select the correct systems without branching over entity data.

Only absolute translation becomes double. Velocity, acceleration, rotation, extents, shapes, normals, movement deltas, local transforms, and solver state remain float unless a future measured problem demonstrates otherwise.

The pinned Box3D revision already exposes the model this design needs. With BOX3D_DOUBLE_PRECISION, b3Pos uses three doubles and b3WorldTransform combines that translation with a float quaternion. Velocities, forces, shapes, local transforms, manifolds, solver data, AABBs, broad-phase storage, and SIMD calculations remain float. The exact type boundary is visible in math_functions.h.

DigitalHeaven currently ships and binds the single-precision ABI. Box3D precision is a compile-time choice, and changing it changes interop layouts. When one process must support both profiles, the Physics module will therefore need separately named f32 and f64 native binaries plus matching managed adapters. World construction will select one adapter once; it will not probe precision for every body or query.

That second ABI, its binaries, and its adapters should not be built until Large content needs them. Keeping only the f32 binary today avoids release, test, and platform maintenance for an unused path.

Large canonical positions do not flow directly into float GPU matrices. For each visible object, the CPU computes:

renderTranslation = float(canonicalTranslation - currentRenderOrigin)

The subtraction happens in double, while both operands still preserve the large absolute value. Only the small result is converted to float and used to build model/view data. Mesh vertices, Vulkan buffers, shader inputs, and matrices remain float.

A render origin belongs only to one client’s presentation. It is commonly chosen near the camera, may move whenever presentation needs it, and is never authoritative entity state. The server does not simulate in a client’s render frame, and clients do not replicate render-origin changes as entity movement.

UE5’s large-world rendering documentation is useful comparative reading on translated world space, but its types and implementation are not DigitalHeaven’s contract.

The server’s canonical coordinates never depend on a client camera or render origin. This gives all clients one stable frame for authority, reconciliation, interest tests, and persistence.

For rendering a replicated Large entity:

  1. Decode both snapshot endpoints into canonical high-precision positions.
  2. Interpolate those canonical positions in the same high-precision frame.
  3. Subtract the current render origin once.
  4. Convert the small relative result to float for rendering.

Do not subtract a different render origin from each endpoint and then interpolate those unrelated local values. Do not make the server shift its authoritative origin when any client camera moves.

This design rejects an authoritative global floating-origin simulation for multiplayer. A global shift would introduce coordination epochs into physics, snapshots, prediction, persistence, and every connected client. Camera-relative rendering achieves presentation precision without changing authoritative meaning.

The current full snapshot record is 30 bytes per entity:

  • 4 bytes entity ID;
  • 1 byte kind;
  • 12 bytes float position XYZ;
  • 12 bytes yaw, pitch, and eye height;
  • 1 byte flags.

Replacing only position XYZ with raw doubles would make the record 42 bytes, an increase of 12 bytes or 40%. That is acceptable as a simple first Large codec if needed, but it makes position compression worth measuring once real Large-world traffic exists. It does not justify burdening Compact ECS storage now.

Integer cells may later help with:

  • spatial streaming and region lookup;
  • interest-management indices;
  • packet-relative position compression.

They are derived indices or encodings, not a mandatory per-entity authoritative representation. Canonical server positions remain origin-independent.

If a future codec encodes a position as cell plus local offset, negative coordinates must use floor-based normalization. For cell size S:

cell = floor(position / S)
local = position - cell * S

For positive S, this keeps local in [0, S) even when position is negative. Truncating toward zero would assign inconsistent cells across the origin.

Every unreliable full snapshot that uses a relative encoding must carry its own canonical origin (or equivalent complete decoding basis). A later snapshot must remain decodable if an earlier packet is lost or arrives out of order. After decoding, convert both endpoints to one common high-precision canonical frame and interpolate there. Never lerp cell indices and local offsets independently: crossing a cell boundary would produce the wrong path.

For background on the interpolation-buffer model rather than DigitalHeaven-specific coordinate design, see Snapshot Interpolation.

Generic World<T> or generic vector math : Precision choice is a world-construction concern, while generic math would spread through ECS, gameplay, physics, networking, and rendering APIs. Separate specialized paths keep the hot code direct and the Contracts schema stable.

A union or tagged Position component : Every entity would carry representation metadata or excess storage, and every consumer would branch. The owning World already supplies the invariant.

All-double simulation and rendering : Double translation is useful; double velocities, shapes, mesh vertices, GPU matrices, and solver internals generally are not. It would increase bandwidth and storage, reduce SIMD/GPU efficiency, and diverge from Box3D’s supported hybrid boundary.

Mandatory integer cell plus float local position : It complicates arithmetic, negative normalization, interpolation, editor tooling, and networking even for tiny maps. Cells remain available as derived indices or measured compression tools.

Authoritative global floating origin : Rebasing the shared simulation couples unrelated clients and adds origin epochs throughout multiplayer state. Canonical authority plus client-local camera-relative rendering avoids that coupling.

Per-entity precision selection : Mixed representations inside one world make queries, relationships, snapshots, and system iteration branch on data. Precision is fixed for the whole world instead.

PhaseScope
Now: cheap seamsMake the profile immutable at world creation and select profile-matched physics once. Support only Compact; preserve the existing float entity and wire layouts. Handshake reporting and profile-specific systems/codecs remain deferred.
First Large contentAdd LargePosition to Contracts; add a separately named f64 Box3D ABI and adapter; select Large-specialized systems, replica storage, and snapshot codec; make rendering camera-relative at the CPU/GPU boundary.
Measured scaleAdd cell-derived streaming and interest indices, packet-relative compression, or regional simulation only where profiling and content scale justify them.

This sequencing buys the compatibility seam now while postponing every recurring Large-world cost until a world actually needs it.