Last active
March 14, 2024 06:59
-
-
Save marcospgp/42562d3b23b37610f29828cfef674b3a to your computer and use it in GitHub Desktop.
A floating origin script for Unity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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
@Grav8 The particle logic is based on the original script (link now dead, archived version here). I believe the only issue is that particles in world space need to be moved together with the rest of the world, otherwise it would seem as if they teleported far away.