Skip to content

Instantly share code, notes, and snippets.

@brihernandez
Last active April 29, 2024 16:04
Show Gist options
  • Star 47 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save brihernandez/9ebbaf35070181fa1ee56f9e702cc7a5 to your computer and use it in GitHub Desktop.
Save brihernandez/9ebbaf35070181fa1ee56f9e702cc7a5 to your computer and use it in GitHub Desktop.
Floating origin to handle large worlds in Unity.
// Based on the Unity Wiki FloatingOrigin script by Peter Stirling
// URL: http://wiki.unity3d.com/index.php/Floating_Origin
using UnityEngine;
using UnityEngine.SceneManagement;
public class FloatingOrigin : MonoBehaviour
{
[Tooltip("Point of reference from which to check the distance to origin.")]
public Transform ReferenceObject = null;
[Tooltip("Distance from the origin the reference object must be in order to trigger an origin shift.")]
public float Threshold = 5000f;
[Header("Options")]
[Tooltip("When true, origin shifts are considered only from the horizontal distance to orign.")]
public bool Use2DDistance = false;
[Tooltip("When true, updates ALL open scenes. When false, updates only the active scene.")]
public bool UpdateAllScenes = true;
[Tooltip("Should ParticleSystems be moved with an origin shift.")]
public bool UpdateParticles = true;
[Tooltip("Should TrailRenderers be moved with an origin shift.")]
public bool UpdateTrailRenderers = true;
[Tooltip("Should LineRenderers be moved with an origin shift.")]
public bool UpdateLineRenderers = true;
private ParticleSystem.Particle[] parts = null;
void LateUpdate()
{
if (ReferenceObject == null)
return;
Vector3 referencePosition = ReferenceObject.position;
if (Use2DDistance)
referencePosition.y = 0f;
if (referencePosition.magnitude > Threshold)
{
MoveRootTransforms(referencePosition);
if (UpdateParticles)
MoveParticles(referencePosition);
if (UpdateTrailRenderers)
MoveTrailRenderers(referencePosition);
if (UpdateLineRenderers)
MoveLineRenderers(referencePosition);
}
}
private void MoveRootTransforms(Vector3 offset)
{
if (UpdateAllScenes)
{
for (int z = 0; z < SceneManager.sceneCount; z++)
{
foreach (GameObject g in SceneManager.GetSceneAt(z).GetRootGameObjects())
g.transform.position -= offset;
}
}
else
{
foreach (GameObject g in SceneManager.GetActiveScene().GetRootGameObjects())
g.transform.position -= offset;
}
}
private void MoveTrailRenderers(Vector3 offset)
{
var trails = FindObjectsOfType<TrailRenderer>() as TrailRenderer[];
foreach (var trail in trails)
{
Vector3[] positions = new Vector3[trail.positionCount];
int positionCount = trail.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
trail.SetPositions(positions);
}
}
private void MoveLineRenderers(Vector3 offset)
{
var lines = FindObjectsOfType<LineRenderer>() as LineRenderer[];
foreach (var line in lines)
{
Vector3[] positions = new Vector3[line.positionCount];
int positionCount = line.GetPositions(positions);
for (int i = 0; i < positionCount; ++i)
positions[i] -= offset;
line.SetPositions(positions);
}
}
private void MoveParticles(Vector3 offset)
{
var particles = FindObjectsOfType<ParticleSystem>() as ParticleSystem[];
foreach (ParticleSystem system in particles)
{
if (system.main.simulationSpace != ParticleSystemSimulationSpace.World)
continue;
int particlesNeeded = system.main.maxParticles;
if (particlesNeeded <= 0)
continue;
// 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 = system.GetParticles(parts);
for (int i = 0; i < num; i++)
{
parts[i].position -= offset;
}
system.SetParticles(parts, num);
}
}
}
@skyspy
Copy link

skyspy commented Jan 20, 2023

Unfortunately, this threshold-based shifting is not floating origin. It never was. Real floating origin has no threshold. It never moves the player from the origin. Therefore, this shifting system is really the exact opposite.
Please rename the references to "floating origin" to something that reflects the truth: Unreal used the term "origin-rebasing". It serves no good purpose to misrepresent the work of others and mislead developers.
@AviaSimDev whenever there is a shift there is a large instantaneous acceleration, so it is not a surprise there are issues. Also, try moving at a speed that exceeds the shift size per second. That is when the shifting system goes into continuous failure.

@marcospgp
Copy link

@skyspy mom: we have floating origin at home
floating origin at home:

@boarnoah
Copy link

boarnoah commented Jan 8, 2024

It fascinates me, how at least at a surface level this looks relatively straightforward to do in Unity.
In terms of getting references to things like all relevant particle systems in the world and then moving them around etc...

One of the blessings that come with a curse in Unreal I've noticed is that you get a lot of very feature rich systems out of the box, but doing something like this is very much non trivial without making relatively significant changes to the engine source.

@skyspy
Copy link

skyspy commented Jan 8, 2024

It fascinates me, how at least at a surface level this looks relatively straightforward to do in Unity. In terms of getting references to things like all relevant particle systems in the world and then moving them around etc...

One of the blessings that come with a curse in Unreal I've noticed is that you get a lot of very feature rich systems out of the box, but doing something like this is very much non trivial without making relatively significant changes to the engine source.

You are right, the basic idea is very simple, and the continuous floating origin method is simpler than the shifty approach, but designing such an algorithm at the core of a framework for games/sim requires an entirely new structure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment