Large coordinates: precision and origin shifting
Understand float limits, check the installed SDK and preserve logical position while rebasing.
Check scale first
The issue is coordinate magnitude versus required precision, not only map area or object count. At large magnitudes, adjacent floats are farther apart, so small motion can disappear through rounding. In the checked SDK, Vector3.X is Single and Vector3 occupies 12 bytes. PhysicsBackendProbe prints the field type.
| Coordinate magnitude | Adjacent-float spacing near that value |
|---|---|
| 10 000 | 0.0009765625 |
| 100 000 | 0.0078125 |
| 1 000 000 | 0.0625 |
| 10 000 000 | 1 |
| 100 000 000 | 8 |
With conventional metre units, spacing 8 means eight metres. This describes number representation, not a complete game-size limit. The test shows Vector3 X = 100 000 000 losing an addition of 0.1. Enlarging models or camera range does not restore lost bits. Keep sensible object dimensions and test the minimum collision/render precision you require.
Separate logical world and local simulation
Retain global position in suitably precise logical coordinates, such as doubles or integer region indices plus local offsets. Keep active physics/rendering near the origin. On rebasing, retain the logical offset and shift active entities consistently. Network messages, saves, navigation and background tasks must identify each point's coordinate system.
Rebasing does not load or remove world regions. Streaming, region ownership and activation policy are separate project systems. A huge plane alone does not provide precise infinite simulation.
Working rebase example
Attach OriginShiftLab3D.cs to an Entity3D root in a separate C# level, build and press F6. Use 60 ticks/s, downward gravity 9.8 and a stationary unit-scale root. The character automatically walks along X. At distance 32 from zero, code shifts WorldRoot's direct spatial children, retains a double offset and prints OriginShift to Output. Local position returns near zero while logical position keeps growing.
OriginShiftLab3D.cs
using Reckfell;
public partial class OriginShiftLab3D : Entity3D
{
public Entity3D WorldRoot { get; private set; } = null!;
public CharacterBody3D Player { get; private set; } = null!;
public Camera3D Camera { get; private set; } = null!;
public Vector2 MoveInput { get; set; } = Vector2.Right;
public float Speed { get; set; } = 12;
public float Threshold { get; set; } = 32;
public double OriginX { get; private set; }
public double OriginY { get; private set; }
public double OriginZ { get; private set; }
public int Shifts { get; private set; }
public (double X,double Y,double Z) LogicalPosition => (OriginX + Player.GlobalPosition.X,OriginY + Player.GlobalPosition.Y,OriginZ + Player.GlobalPosition.Z);
public override void _Ready()
{
WorldRoot = new Entity3D { Name = "World" }; AddChild(WorldRoot);
var floor = new StaticBody3D { Position = new Vector3(0,-.25f,0), CollisionLayer = 1, CollisionMask = 0 };
floor.AddChild(new CollisionShape3D { Shape = new BoxShape3D { Size = new Vector3(512,.5f,32) } });
floor.AddChild(new MeshInstance3D { Mesh = new BoxMesh { Size = new Vector3(512,.5f,32) }, MaterialOverride = Material(new Color(.55f,.55f,.6f)) }); WorldRoot.AddChild(floor);
Player = new CharacterBody3D { Position = new Vector3(0,.9f,0), CollisionLayer = 2, CollisionMask = 1, FloorSnapLength = .2f };
Player.AddChild(new CollisionShape3D { Shape = new CapsuleShape3D { Radius = .35f, Height = 1.8f } });
Player.AddChild(new MeshInstance3D { Mesh = new CapsuleMesh { Radius = .35f, Height = 1.8f }, MaterialOverride = Material(new Color(.25f,.45f,1)) }); WorldRoot.AddChild(Player);
Camera = new Camera3D { Current = true }; WorldRoot.AddChild(Camera); FollowCamera(); ResetPhysicsInterpolation();
}
private static StandardMaterial3D Material(Color color) => new() { AlbedoColor = color, ShadingMode = BaseMaterial3D.ShadingModeEnum.Unshaded };
private void FollowCamera() { Camera.GlobalPosition = Player.GlobalPosition + new Vector3(7,5,8); Camera.LookAt(Player.GlobalPosition); }
public override void _PhysicsProcess(double delta)
{
Vector2 input = MoveInput.IsFinite() ? MoveInput.LimitLength() : Vector2.Zero;
Vector3 velocity = Player.Velocity;
velocity.X = input.X * Speed; velocity.Z = input.Y * Speed;
if (!Player.IsOnFloor()) velocity += Player.GetGravity() * (float)delta;
Player.Velocity = velocity; Player.MoveAndSlide(); FollowCamera(); RebaseIfNeeded();
}
public bool RebaseIfNeeded()
{
if (!float.IsFinite(Threshold) || Threshold <= 0) return false;
Vector3 shift = Player.GlobalPosition;
if (!shift.IsFinite() || shift.Length() < Threshold) return false;
foreach (Entity child in WorldRoot.GetChildren())
if (child is Entity3D spatial) { spatial.GlobalPosition -= shift; spatial.ResetPhysicsInterpolation(); }
OriginX += shift.X; OriginY += shift.Y; OriginZ += shift.Z; Shifts++;
ReckfellApi.Print($"OriginShift {Shifts}: ({OriginX:F2}, {OriginY:F2}, {OriginZ:F2})"); return true;
}
}This finite level has a 512-long floor and no region streaming. Camera, StaticBody and CharacterBody are direct children of a stationary WorldRoot. WorldRoot itself does not accumulate a huge transform. Ordinary nested entities follow their spatial parent; separate TopLevel branches, other viewport/worlds, retained world points and external systems are not automatically repaired by this loop.
RigidBody, physical bones, SoftBody, particles, world-space shader coordinates, trails and network buffers require coordinated handling of their own. Do not apply this foreach to an arbitrary entire project without auditing systems. Here physical changes follow MoveAndSlide in the same _PhysicsProcess, with visual interpolation reset after the discontinuity. That reset does not replace logical coordinate-system changes.
Double-precision builds
The source build system offers precision=double; managed math types also depend on ReckfellFloat64. Switching one C# constant or mixing an SDK of another precision with the existing native runtime is invalid. Rebuild runtime, managed bindings/SDK, extensions and export templates consistently, then separately verify/install that set. This material was checked on the current single-precision build; no double build was executed here.
Double precision does not automatically make every GPU calculation, material, particle system or external library 64-bit. Retain clear units and test your renderer/export. Physics frequency or interpolation changes do not repair arithmetic precision loss; they solve different problems.
Verify your rebase
Compare logical positions before/after shifting, relative distances, floor contacts, cameras and stored paths/targets. The test performs six shifts and checks position/contact preservation on both backends. It does not prove arbitrary streaming, every shader/animation system or network consistency. Begin with a minimal level and add systems one at a time.