Comment on page
World Origin Shifting
Creating massive multiplayer worlds
Unity has a well-known limitation of offering high precision positioning only within a few kilometers from the center of the world. A common technique to get around this limitation is to move the whole world underneath the player. This is called floating origin. Here's how you can use floating origin with coherence.
Unity uses 32-bit floating-point numbers to represent the world position of game objects in memory. While this format can represent numbers up to
, its precision decreases as the number gets larger. You can use this site to see that already around the distance of
meters the precision of a 32-bit float is 1 meter, which means that the position can only be represented in steps of one meter or more. So if your Game Object moves away from the origin by 1000 kilometers it can be only positioned with the accuracy of 1000km and one meter, or at 1000km and two meters, but not in between. As a result, usable virtual worlds can be limited to a range of as little as 5km, depending on how precisely GameObjects like bullets need to be tracked.
Having a single floating world origin as used in single player games is not sufficient for multiplayer games since each player can be located in different parts of the virtual world. For that reason, in coherence, all positions on the Replication Server are stored in absolute coordinates, while each Client has its own floating origin position, to which all of their game object positions are relative.
To represent the absolute position of Game Objects on the Replication Server, we use the 64-bit floating-point format. This format allows for sub-1mm precision out to distances of 5 billion kilometers. To keep the implementation simple, floating origin position and any Game Object's absolute position is limited to the 32-bit float range, but because of the Floating Origin, it will have precision of a 64-bit float when networked with other Clients.
Here is a simple example how the floating origin could be used. We will create a script that is attached to the player Prefab and is active only on the Client with authority.
public class PlayerShifter : MonoBehaviour
private CoherenceSync sync;
private void Awake()
sync = GetComponent<CoherenceSync>();
private void Update()
// We don't want to shift floating origin based on other player's position.
// The same can be achieved via components configuration in the CoherenceSync.
// If player moves farther than 100 meters from the current floating origin
if (transform.position.magnitude > 100)
// Translate the floating origin so the player is back at (0, 0, 0)
CoherenceBridge.TranslateFloatingOriginwill shift all CoherenceSync objects by the translated vector, but you have to shift other non-networked objects by yourself. We will create another script which takes care of this.
public class WorldShifter : MonoBehaviour
public CoherenceBridge bridge;
public Transform nonNetworkedObjectsToShift;
private void Start()
bridge.OnFloatingOriginShifted += OnFloatingOriginShifted;
private void OnFloatingOriginShifted(FloatingOriginShiftArgs args)
foreach (var nonNetworkedObj in nonNetworkedObjectsToShift)
nonNetworkedObj.position -= args.Delta.ToUnityVector3();
When your floating origin changes, the
CoherenceBridge.OnFloatingOriginShiftedevent is invoked. It contains arguments such as the last floating origin, the new one, and the delta between them. We use the delta to shift back all non-networked game objects ourselves. Since the floating origin is
Vector3of doubles we need to use
ToUnityVector3method to convert it to
To control what happens to your entities when you change your floating origin, you can use CoherenceSync's
floatingOriginParentedModefields. Both are accessible from the inspector under Advanced Settings.
Available options for both fields are:
MoveWithFloatingOrigin- when you change your floating origin, the Entity is moved with it, so its relative position is the same and absolute position is shifted.
DontMoveWithFloatingOrigin- when you change your floating origin, the Entity is left behind, so its absolute position is the same and relative position is shifted.
Floating Origin Mode dictates what happens to the Entity when it is a Root Object in the scene hierarchy, and Floating Origin Parented Mode dictates what happens to it when its parented under another non-synced Game Object.