Imprecision problem on planet

Started by
5 comments, last by Adam_42 12 years, 1 month ago
Hello,

because sometimes it's hard to follow an explanation only in mind I added a few pictures to this post. Sorry for those which have a slow internet connection.

First of all, I'm programming a planet renderer. Im using the cube to sphere algorithm from mathproofs: http://mathproofs.bl...-to-sphere.html
My problem is that it running into the common floation point error because the algorithm forces me into a specific range (imho), and I don't know how to getting arround it.

The algo morphes all 6 sides of a cube in to a sphere.
One side look like this after morphing:

prob471dty.png

Using the algo on all 6 sides I get a sphere inbetween -1 and 1 (scale 1):

prob3m2db7.png

That LOD is implemented as an quadtree. When coming closer the chunk is seperated in 4 smaller chunks each with the same amount of vertices as the old chunk.

prob513ffd.png

These chunks can be seperated too, so I get a smooth surface even if im extremly close to the planet (in theory).
This is how it look like if I create a really deep tree and zoom out:

prob6mbdnw.png

Here comes the trouble.
On the tiny chunks the curvature is extrem small. Its so small that I run into floating point imprecision
and the result is that:

prob2zfcq9.png

As you can see the surface is not flat and when I change the angle of the camera everything is "wobbeling".
The quadtree depth is at 18 that means that the smallest chunk is one 262144th of the original chunk in sidelength.

Visualising this on 2D it looks like this:

prob16gde4.png


What can I do to solve this problem?
I already fixed my camera to Vector3.Zero and just move the world around me to get highest precision near to my camera, but I still got the problem.


I appreciate every comment. Thanks.
Advertisement
May I ask what the cell edge length actually is at the 18th subdivision of a quadree face for a cube representing, say the size of earth?
...Use double precision?
The quadtree depth is at 18 that means that the smallest chunk is one 262144th of the original chunk in sidelength.


That's a subdivision size of about 24 metres, on the earth. Do you need to get that close in?

The mantissa in a float is effectively stored with 24 bits of precision. At 18x subdivision you're left with 6 bits of precision, which isn't much - errors will be up to about 1/64th of the actual value.

If you need to get that close in and have the surface look smooth I'd suggest using double precision. That means you will probably to do at least some of the transformation work on the CPU because most GPUs don't handle doubles. You could just give the GPU screen space coordinates. Alternatively move the origin dynamically so 0,0,0 is on the bit of the surface you're looking at - it's currently about 6 million metres away!

You might find http://randomascii.wordpress.com/2012/02/13/dont-store-that-in-a-float/ and the other articles in that series helpful too.

May I ask what the cell edge length actually is at the 18th subdivision of a quadree face for a cube representing, say the size of earth?


Earth has 510,000,000km², one side is one 6th: 85,000,000km² divided by 4[sup]18[/sup] is 0,0012km² or 1,237m² with a edge length of 35m
Still huge in my opinion. sad.png


[quote name='Imprecision' timestamp='1331244191' post='4920519']The quadtree depth is at 18 that means that the smallest chunk is one 262144th of the original chunk in sidelength.


That's a subdivision size of about 24 metres, on the earth. Do you need to get that close in?
[/quote]

The 24m (or 35m) could be enough, (better would be a depth of 22 divisions) but i get imperfections already on depth of 14 which is definitely to big for me sad.png


The mantissa in a float is effectively stored with 24 bits of precision. At 18x subdivision you're left with 6 bits of precision, which isn't much - errors will be up to about 1/64th of the actual value.

If you need to get that close in and have the surface look smooth I'd suggest using double precision. That means you will probably to do at least some of the transformation work on the CPU because most GPUs don't handle doubles



...Use double precision?


I already use double precision. All calculations are one the CPU made with double precision. When I send the vertices to the vertexbuffer the're converted to 32bit float. Matrice transformations are on 32bit too.
Limiting factor is the graphicscard is working with 32bit float



. You could just give the GPU screen space coordinates. Alternatively move the origin dynamically so 0,0,0 is on the bit of the surface you're looking at - it's currently about 6 million metres away!

You might find http://randomascii.w...hat-in-a-float/ and the other articles in that series helpful too.


I tried that out (putting the top surface to (0,0,0), but it didn't helped. I already got the highest precision in range of -1 to 1. sad.png
I use more or less the same technique for my procedural planet, and I am having similar issues.
I generate the whole geometry on the gpu, which makes things even worse because I have to use 32bit precision everywhere.
The wobbliness comes mostly from floating point imprecision during the View & Projection transforms.

I have had moderate success with scaling up the planet and keeping everything close to (0, 0, 0).
In my last test, iirc I used a radius of 1000.0 and kept (0, 0, 0) at the center of the camera (I translated the world instead of the camera).
This did improve things, but I haven't really had much time to investigate this further because I was focusing on other things.

When you're saying that you get issues at level 14 already, is that 14 subdivisions on a quad or on a 33x33 grid as shown in your first picture?
I'm currently running 21 divisions on a quad, and issues are only visible if I move the camera very close to the ground (~200 meters, assuming an earth sized planet)
That is without using the scale/translate optimization for better precision.
Unfortunately I can't test it with the optimization right now, I've broken it quite badly with my latest additions.

I tried that out (putting the top surface to (0,0,0), but it didn't helped. I already got the highest precision in range of -1 to 1. Posted Image


I take it you did that translation using doubles on the CPU side of things? Doing it after the conversion to float won't help, because the precision is already gone at that point.

To check that you got it right take a look at any translation that happens in the vertex shader - that needs to be as close to zero as possible to get you the best precision.

Are you combining the world, view and projection matrices on the CPU and passing a single matrix to the vertex shader? If not that can mess up precision if for example the world and view matrices are doing equal and opposite translations.

This topic is closed to new replies.

Advertisement