Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
A floating origin script for Unity.
// Based on script found at http://wiki.unity3d.com/index.php/Floating_Origin
// on 2021-05-13, modified substantially - mostly to accomodate multiplayer,
// by introducing threshold and offset values.
using UnityEngine;
public class FloatingOrigin : MonoBehaviour {
public static FloatingOrigin Instance;
// Largest value allowed for the main camera's X or Z coordinate before that
// coordinate is moved by the same amount towards 0 (which updates offset).
// Pick a power of two for this, as floating point precision (the thing
// we are trying to regulate) decreases with every successive power of two.
public const float threshold = (float) Threshold._4;
private ParticleSystem.Particle[] parts = null;
private Transform anchor;
// The origin is offset by offset * threshold
public (byte x, byte y, byte z) Offset { get; private set; } = (0, 0, 0);
public enum Threshold {
_2 = 2,
_4 = 4,
_8 = 8,
_16 = 16,
_32 = 32,
_64 = 64,
_128 = 128,
_256 = 256,
_512 = 512,
_1024 = 1024
}
public void OnEnable() {
// Ensure singleton
if (Instance != null) {
Destroy(gameObject);
throw new System.Exception(
"More than one instance of singleton detected."
);
} else {
Instance = this;
}
}
public void LateUpdate() {
if (anchor == null) {
var camera = Camera.main;
if (camera != null) {
anchor = camera.transform;
} else {
return;
}
}
// Calculate offset
Vector3 offsetToApply;
float value;
if (Mathf.Abs(anchor.position.x) > threshold) {
value = anchor.position.x;
offsetToApply = new Vector3(1f, 0f, 0f);
} else if (Mathf.Abs(anchor.position.y) > threshold) {
value = anchor.position.y;
offsetToApply = new Vector3(0f, 1f, 0f);
} else if (Mathf.Abs(anchor.position.z) > threshold) {
value = anchor.position.z;
offsetToApply = new Vector3(0f, 0f, 1f);
} else {
return;
}
float times = Mathf.Floor(Mathf.Abs(value) / threshold);
float offsetSign = Mathf.Sign(value) * -1f;
Offset = (
(byte) (Offset.x + (offsetToApply.x * times * offsetSign)),
(byte) (Offset.y + (offsetToApply.y * times * offsetSign)),
(byte) (Offset.z + (offsetToApply.z * times * offsetSign))
);
float delta = threshold * times * offsetSign;
offsetToApply *= delta;
// Offset scene root objects
GameObject[] objects = UnityEngine.SceneManagement.SceneManager
.GetActiveScene().GetRootGameObjects();
foreach (var o in objects) {
Transform t = o.GetComponent<Transform>();
t.position += offsetToApply;
}
// Offset world-space particles
ParticleSystem[] particleSystems = FindObjectsOfType<ParticleSystem>();
foreach (var sys in particleSystems) {
if (sys.main.simulationSpace != ParticleSystemSimulationSpace.World)
continue;
int particlesNeeded = sys.main.maxParticles;
if (particlesNeeded <= 0)
continue;
bool wasPaused = sys.isPaused;
bool wasPlaying = sys.isPlaying;
if (!wasPaused)
sys.Pause ();
// Ensure a sufficiently large array in which to store the particles
if (parts == null || parts.Length < particlesNeeded) {
parts = new ParticleSystem.Particle[particlesNeeded];
}
// Now get the particles
int num = sys.GetParticles(parts);
for (int i = 0; i < num; i++) {
parts[i].position += offsetToApply;
}
sys.SetParticles(parts, num);
if (wasPlaying)
sys.Play ();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment