Working to a Solution in Precision issues
GOOD NEWS/UPDATE: Chris has just implemented a much quicker, novel solution in the latest source code. As a result, I'm tabling this problem until we get to 1" pixels :-). Thank you Chris!
It's getting close to implementation time for solving the precision problems in the WorldWind base. To review, worldwind uses a lat,lon,meters coordinate system. When navigating in this space, any given location is subject to the precision of the numbers being used to represent your position (and the precision of all objects in the space). WW is constrained (as are most PC-based 3D applications) to Single precision 32 bit floating point precision. This works great for viewing the earth from outerspace, all the way down to a few meters. But, starting dealing with items below a few meters and the precision errors cause a number of problems, including jitter in the camera.
For more background, please see the earlier post (I believe the first post).
There are several potential implementation solutions, but lets first talk about why some of the quick hacks don't work (to remind ourselves why TANFL):
- Why not just switch to doubles? Great idea! Except the graphics cards these days do not support doubles in hardware. All rendering would become software based, and there goes those lovely framerates.
- Why not just use doubles everywhere, and then switch to singles at the last moment? This actually does help -- anytime you multiply/add/trig-ify single precision floating point numbers you worsen their error. Making all these calcs be double precision minimizes that error. This is a necessity in any solution. But the end problems still exist inside WW the moment you do your final double to single conversion. The viewpoint is inherent constrained to be at the finite and discrete set of numbers representable by single precision. You camera and objects will always be jumping to those points.
- What if we just make the viewpoint be super high res through some custom method (e.g. doublizing), and then just update the viewpoint calculations to be CPU based instead of native GPU based? Great... except you've got all the objects on the planet too... what coordinate space are they in? -- still the same old single-fp coordinate system. How do you map the two together? Ultimately, they will have to be mapped together, and as long as you are using geodetic lat/lon/alt centered in the earth, you'll hit the issue.
- What if we maximize our coordinate system around zero by using smaller numbers? The discrete space representated by floating points inherently have more precision around zero. When not make lat/lon be represented by radians, and altitude to be representated by kms? I actually like this as a quick fix... but at most it will give you a 2-3X improvement, which will get you down to 2 foot resolution, but still with areas of inconsistency. And the solution has its limits -- significant digits are significant digits in the end, despite the radial nature of the floating point implementation around zero.
- What if we just put the fix into QTS? I like it, but this is still problematic... think of the lat/lon grid lines. Ultimately, they must all share the same rendered coordinate system in order to be visually consistent.
Ok.. quick hacks are a no go. What next?
In his paper at http://planet-earth.org/cw05/FloatingOrigin.pdf, Chris Thorne points out three classes of solutions:
- On the fly shifting of coordinates
- Multiple local coordinate systems
- Piecewise shifting of coordinates in a continuous virtual world
I've taken the bent that we should strive to have Worldwind operate in as much of a continuous world as possible. The user should be able to zoom in smoothly to any spot on the globe... This presents problems with nearly all approaches, except his FO solution.
A problem that Chris Thorne does not seem to address in his paper regarding his Floating Origin solution lies in the updating of all those objects to be moved around the now constant eyepoint. Before, with a roaming eyepoint, we allowed the GPU to perform one last matrix operation near the end of the pipeline to construct the rendered image. With the FO approach, however, you've taken that operation out of the pipeline and have placed it in the object's position earlier in the pipeline. But worse, you've likely taken it out of the GPU and into the CPU. All objects must be recalced with a viewpoint change.
There are likely some ways to ensure that the change stays in the GPU. (Need to think more here).
But until then, I personally am leaning towards a piecewise solution of multiple local coordinate systems. Here, we make the origin be to some local location, and then move the eyepoint within this state. Recalculation of all the object locations only occurs when you transition from this local coordinate space to another.
First question: what grid structure?
Well.. what do you know... Worldwind already has a grid structure in place as defined by its QTS naming scheme. Granted, this structure varies from one QTS to the next, but the underlying SRTM terrain grid effectively is always loaded. I am thinking to use this SRTM level 0 (or more likely 1 or 2) gridding to be basis for the local coordinate systems.
The grid structure needs to be not just lat/lon based, but altitude based. This allows us to retain our current earth centered coordinate system when zoomed completely out. We can then rotate the earth like crazy without incurring coordinate system shifts.
Next question: how do we implement the local coordinate system?
Well, first off, we base the coordinate system on the lat/lon/alt of level 1 or 2 of SRTM. All objects call a single routine (usually) to convert a lat/lon/altitude into the final coordinate space. This function needs to be updated to take into account the local coordinate system if present. All objects drawing items into the coordinate space must use this function to translate from lat/lon/alt to coordinate space. If they don’t, then they won’t work. Furthermore, this function needs knowledge of the current coordinate system in place. I don’t think it will always be derivable from the current camera position, so better to store it directly in the drawArgs, which gets passed into these coordinate translation routines.
Next question: how do we handle the transition – specifically the recalculation of all the objects? Doing the smoothly is the biggest question, and one that I’m not going to try and solve. Why?... read on
The recalculation to the new coordinate space is effectively like performing a device reset (e.g. resize the window). I believe that the coordinate system switch should even force such a path of execution to occur in the code. Force all items to dispose themselves (or at least their MDX resources) and reconstruct themselves based on the new coordinate space. This seems drastic yes... but think about it... after a device reset, the various (well-behaved) layers do what they can immediately on the primary render thread, and then use the background update thread to load up their various resources. This will allow us to do all of the moving of the objects on the background thread with no new code. The downside is that after a transition, you’ll see data disappear and then reappear.
That’s not too bad.. But bad enough that I think a fix for QTS is warranted to prevent it from doing an actual dispose of the MDX resources, but rather, just a remapping (it’s the reloading of those textures from disk that scares me).
Next question: how do we prevent jitter on the transition boundaries?
First.. remember how I suggest that we make the coordinate systems be 3D? This is to allow us to keep our existing global coordinate system at zoomed out locations.
Noting this makes it clear that transitions, however, occur in a 3D space. You can hover between two coordinate systems in both lat,lon locations as well as altitude.
Now, how to handle these 3D boundaries? We should have plenty of room in the precision of the coordinate spaces to not worry about being a full grid off. Therefore, we should have a “tolerance” of grid changes to be a full grid size. That is, don’t switch to the next coordinate system until we’ve gone two coordinate systems away. This effectively makes each coordinate system have a bleeding edge of one additional unit.
Next question: how do we handle flight? What if we are going from one location in one coordinate space to another location in another coordinate space?
The camera movement class must also be aware of coordinate space transitions.
So, in going with a local coordinate system, we incur a frame rate spike on a coordinate system switch.
Open Item : adjusting the clipping planes and z-buffer

