Having a problem with a visual oscillation in Unity. I’m not able to identify if it’s camera or object related because in the debugger they both appear to share correct coordinates with a specific offset. To make this even more strange, when the object is near coordinates 0,0,0, I don’t see the oscillation. As the object goes higher into the coordinates system, the oscillation/wiggle/jiggle becomes more pronounced, especially for objects attached to the camera.
This is a released/production game so I made a copy of the code and tore everything down to just these three objects and the camera. Removed and cleaned up all packages, reset the project settings.
Important items
Build is the latest version of Unity 2019
Have tried moving the objects using rigidbody.addforce, rigidbody.moveposition, and directly setting transform.position with time.delta. The movement is smooth in all cases but the oscillation continues.
Have tried multiple combinations of Update, FixedUpdate, and LateUpdate
The oscillation does not occur when the objects and the camera are close to 0,0,0
Small oscillation occurs when a coordinate axis gets near 400
Oscillation gets larger in coordinates above 2000
Two objects (cubes) are at scene root and show the same issue
Issue is much worse for an object attached to the camera
I posted an example of the issue here, you may need to full screen the video to fully see the oscillation.
I’ve searched quite a bit but cannot find anyone having a similar problem. Lots of oscillation issues out there but everything I found has been code related. The code here is very simple. Also very strange that it doesn’t occur when the object is closer to 0,0,0 and then gets worse further out in the coordinate system.
Update 08.04.2021:
I’ve zipped up and attached the project to this thread for reference.
This project contains two scenes:
wigglesfarout - this scene starts the objects and camera at 4000,0,9000 with high oscillation
startsnowiggle - this scene starts the objects and camera near 0,0,0, the oscillation starts as the cubes move higher in the coordinate system.
Resolution 08.18.2021
Thanks to the helpful comments below, the issue was identified as a floating-point precision problem with transform.position. Since the camera was following an object, then objects were attached to the camera, the loss of precision, even at a low number like 400, was noticeable.
The final solution was to include a script that offsets the world based on the object that the camera is following. Here’s some details:
Script runs every five seconds to attempt a world shift.
Method added to script to delay the five seconds as needed. For instance, after jumping into a new star system.
If there’s heavy activity in the game, like combat, or a system jump is in progress, the shift skips and runs again later.
The object that the camera is following has its coordinates shifted as close to 0,0,0 as possible using only whole numbers.
Anything that is serializing and storing object coordinates now inherits some code to set the world back to normal coordinates before the serialization occurs. Would have been better to just abstract all coordinate calls in the game but that would be too heavy a change for now.
Interesting. I had to go full screen to see the changes in the line rendering.
I get pink boxes when loading the project tho, so can’t test it. (using OSX).
Thanks for trying it out! It is hard to see, though in my game it becomes very pronounced when a ship goes high into the coordinate system. I updated the project so that the cubes in both scenes should have a texture on them. I also added some text on the screen to show the current coordinates. My original post is updated with the new project.
Yes, an excellent article on the importance of floating point precision. Unity warns you when your position coordinates start to exceed “99999.” for this reason. As the article mentions, some coordinate systems will start to lose precision on the right side of the decimal as you move beyond 15-20k.
The issue I’m having starts to appear when a coordinate hits around 400, then grows worse towards 2000, so we’re still pretty low in the available coordinate range.
ok, I still get pink cubes but I was able to see the wiggle of the black cube start as the program ran.
These issues are very typical of spatial jitter. I have researched this area for a long time and have also found that highly sensitive calculations can exhibit visible jitter much closer to the origin than most people would expect. This jitter is always there because computers are not infinitely accurate. The main issue with jitter is that one has to acknowledge it is a form of error and if it can be minimised then it should be.
What makes your example most interesting to me is that my best example of sensitive calculations (floating origin fighting cubes), showing early visible jitter, was based on simple physics and that was not visible until about 1000 from the origin. Yours is much clearer and from about 400. And it is a much better example than mine.
There are two known solutions, both named “floating origin”, unfortunately.
The first, now named Continuous Floating Origin, optimally minimises jitter by keeping the camera always at the origin. In this algorithm, movement is relative: the World moves around the camera and the camera never moves (translates). This is available on the unity store: https://assetstore.unity.com/packages/templates/packs/continuous-floating-origin-195971.
The second has been on the Unity wiki since Peter Stirling published it in 2010 and there are other versions. It and other versions are named floating origin but are actually shifting algorithms: they shift objects (or the origin if you like) when the camera has moved some distance from the origin. Unreal engine have a similar one but they named it accurately: they called it origin rebasing. The shifting/rebasing methods were an approximate algorithm for solving visible jitter while allowing for larger scale worlds. However, it is not the real floating origin algorithm and suffers all kinds of issues.
I wrote the paper Healing Cracks in Cyberspace to explain the differences with the above approach. One point is relevant to your issue is the rule that closing the last mile to zero yields the greatest increase in accuracy. In other words, by moving just 400 from the origin, the base error (geometric error) in the 3D space is magnified by approximately 3.4 x 256, before calculation. This is then magnified by calculations, so if you have a multiply by 10, the error multiplier is now 3.4 x 256 * 10. These factors are multiplied by the machine epsilon to get the absolute error, and that is so small that magnification (error propagation) is normally not noticed.
As you are exposing the degree of error in a highly error sensitive calculation, we can actually see the effect of error propagation very early.
One other thing. You appear to be drawing lines on the cube surfaces. if the lines are part of a pre-calculated texture then no problem. Are you drawing lines and cubes separately? and are the lines in the same plane as cube faces?
Well folks, at this point I stand firmly corrected. Both kdgalla and cosmochristo nailed it. This is indeed an issue related to floating point precision within the coordinate system. I was able to create a brand new project and reproduce the problem.
Here’s what I know as of now:
The camera uses a relative position offset Vector3 that it adds to the current ship’s position. The coordinates of that offset are usually less than 100, so the left hand digits are typically two digits, leaving five digits to the right.
At coordinates >= 100 the precision loss on the camera position calculation is up to 0.0001f, then at 1000 the loss is up to 0.001f. That is compounded by the fact that I sometimes have objects as children of the camera and the precision of their coordinates becomes subject to the that precision error.
Some general thoughts I’ll try:
Precision estimation based on the left hand of the decimal. Not a solution but can smooth out some movement.
Scheduled world shift, keeping the active ship under 1000,1000,1000. When things are quiet in the game, sneak a world shift in a single frame for objects in view, lazy shift everything else over a few frames.
Actively shift the world… not likely.
Thanks again everyone. Unfortunately this is a released game so doing a major update to the coordinate system is going to be super exciting.
I’ve heard that HDRP uses a floating origin relative to the camera, so if it’s purely a rendering issue then HDRP may automatically fix the problem. Converting your project might not be easy if you’re using a lot of custom shaders and there’s no built-in facility for converting it back to the built-in renderer. You could always try making a copy of your project to experiment with, though.
Good information, thank you. The scheduled shift of the world seems to be working well. We’ll see how it gets through testing once the next build goes experimental.
Seems like we’re good at this point. No issues with the schedule world shift. One useful point I discovered. Only shift the world using whole numbers, otherwise the shift itself is loosing precision for object’s coordinates in the world.