So far from world origin

Hi All,

As you all know if you have the model close to the origin you see it perfectly:

But when it is very far from the origin you see it like:

This issue can be easily fixed doing:

glMatrix(PROJECTION);
glLoadIdentity();
glPerspective(...);
glMatrix(MODELVIEW);
glLoadIdentity();
>>>>>>>>>>>>>> glTranslate(-1000000, -1000000, 0) // moves the model onto the origin
gluLookAt(...);

But what happen when you do screen to client conversion like:

gluUnProject(mousePos.X, height - mousePos.Y, 0, modelViewMatrix, projectionMatrix, viewport, P0.X, P0.Y, P0.Z);
gluUnProject(mousePos.X, height - mousePos.Y, 1, modelViewMatrix, projectionMatrix, viewport, P1.X, P1.Y, P1.Z);
            
intPoint = LinePlaneIntersection(P0, P1, planeEquation)

We get the wrong 3D point right?

Shall we use the following solution or a better/more accurate approach exists?

gluUnProject(mousePos.X, height - mousePos.Y, 0, modelViewMatrix, projectionMatrix, viewport, P0.X, P0.Y, P0.Z);
gluUnProject(mousePos.X, height - mousePos.Y, 1, modelViewMatrix, projectionMatrix, viewport, P1.X, P1.Y, P1.Z);
            
intPoint = LinePlaneIntersection(P0, P1, planeEquation)

intPoint.X += 1000000; // moves the 3D point back to the actual position
intPoint.Y += 1000000;

Thanks,

Alberto

All depends on ur projection matrix. for objects far from ur eye position they will look smaller with a perspective projective but not distorded (as opengl doesnt simulate camera lens distortion).

Now if u are creating a custom perspective that doenst respect angles and/or distance maybe u will get the effect on ur second image.

with orthographic projection the object will not look smaller even if they are so far from the eye.

Abdallah,

You probably don’t know this old & famous issue, it is related to limited float precision.

Thanks,

Alberto

You are exactly in the limit of single floating-point precision (7 decimal digits).

“Single precision […] is a binary format that occupies 32 bits (4 bytes) and its significant has a precision of 24 bits (about 7 decimal digits).”
ref: wikipedia

Here is a nice blog post discussing this issue:
http://blogs.agi.com/insight3d/index.php/2008/09/03/precisions-precisions/

Hety guys, I know exactly what the problem is. My question was about find a trick to bypass it.

Thanks,

Alberto

Hety guys, I know exactly what the problem is. My question was about find a trick to bypass it.

The “trick” to bypass it is to change where the “world” space is and keep it near your objects.

Looks like nobody knows this issue here, I will try to post it again in the OpenGL coding: Advanced forum.

Thanks,

Alberto

It is a well known issue. Did you look at the link overlay have posted? There should be find some solution, but generally it depends on the problem you have to solve. Also, you have to take into account possibility to calculate all transformations using doubles instead of single precision floating point numbers. I have totally ceased to use standard transformations, even with fixed functionality. But still have to solve problem of coordinate system moving through large scene.

Aleksandar, you can use as much precision as you want, sooner or later you’ll always reach the limit.

Alberto

Sure, but it is unlikely that you need to express distances between electrons using light-years. :wink:
Everything has its context. What do you exactly want to achieve?

Aleksandar,

Loading certain AutoCAD DWG files you get the plan of a building with lines with coords like X=323,032.33; Y=908,099.32 and when you try to zoom close to the building plan you get all the entities dancing here and there because of precision limitations.

What we want to achieve is to get the same steady entities during zoom either for plans close to the world origin or for those very far from it.

Thanks,

Alberto

As I said: change your world coordinates based on what you’re trying to draw.

The coordinates relative to the natural world may be “X=323,032.33; Y=908,099.32”, but the coordinates relative to (300,000, 900,000) are much smaller.

It takes some effort, but it’s really not that hard. I would suggest changing your world coordinates based on the camera, in 1,000 unit increments (that gives you 4 digits before the decimal, with 3 digits after).

a simple solution to your problem is to make the position of every object relative to the camera. So, in your application you may store an objects position using double precision floats, but when you go to render it, and you’re about to upload the matrix to opengl, just subtract the cameras position from the translation part of the matrix. You also need to ensure that you’ve set your initial modelview matrix translation to zero. Most implementations of OpenGL (nvidia/amd) downcast doubles to floats even when you use the GLdouble entry points of the API, so you need to get your numbers smaller to maintain precision. If you think about it, you really don’t need double precision if you render stuff relative to the camera.
When doing your selection (or “screen to client” as you’re wrongly calling it), just add on the cameras position to your result.
If you don’t like the idea of subtracting from the translation, because it seems hacky, then by all means just multiply the objects matrix by the inverse of the camera matrix using your own double precision matrix function, then just upload this matrix directly (i.e. using glLoadMatrix, because you no longer need the camera matrix in the modelview). I use this method, but the first method is simpler to hack in to your existing code, I would imagine.
Some scenegraphs have a special double precision transform node for ‘zones’. It holds a double precision local matrix to hold a huge translation. This means you don’t need every position or object matrix to be double precision, just the root node of ‘zones’ that are very far from the world origin.

Thanks Peterfilm,

Yes I meant ‘screen to world’ sorry.

I don’t see any benefit in multiplying by an inverse matrix instead of doing a translation, at the end they are two 4x4 matrix multiplications, aren’t they?

Thanks,

Alberto

I have implemented GPU RTE, and … it works like magic!
Thank you overlay for the link!

Devdep, if you don’t like subtracting the origin of the scene from objects world coordinates (which is optimal for the scenes with diameter less than 100km with cm precision, or few km with sub-cm precision, which is enough for displaying buildings in an urban area (speaking about CAD application I think it is suitable)), than GPU RTE is an excellent choice.

Thanks Aleksandar, I will make some tests this week.

Alberto

Aleksandar,

We are trying to implement your suggestion:

… subtracting the origin of the scene from objects world coordinates…

Normally we have the model center at (1000000, 1000000, 0) and the camera location and target as well at (1000000, 1000000, 100) and (1000000, 1000000, 0) where is the best place to add the glTranslate(-1000000, -1000000, 0) call?

Using the code below the visual jitter is still present!

glMatrixMode(GL_MODELVIEW);
gluLookAt(location-modelCenter,
          target-modelCenter,
          0,0,1);
glTranslate(-modelCenter.X, -modelCenter.Y, -modelCenter.Y);
DrawModel();

Why?

Thanks,

Alberto

You didn’t understand me. I said to subtract center of the scene from all coordinates. Translating to (1000000, 1000000, 0) you still deal with extremely large numbers. The coordinates of your model should be less than 100000 in order to have 1m precision (in fact a little bit less, but it is not important at this point).

If you want to deal with so large numbers turn to GPU RTE, or similar technique.

Aleksandar,

At this point I am forced to use something else, subtracting those coords from each model vertices for us is not possible, users need to work on real coordinates.

I gave a look to the GPU RTE, it didn’t look so easy for me. Is this the easier to implement approach to this issue?

Thanks,

Alberto

The users will work with real coordinates. You will accept and display in the way expected. But it should be internally converted to smaller numbers before passing to GPU. I’m using custom functions Scene2World() and World2Scene() for that purpose.

I spent one day for implementing GPU RTE in my algorithm. It is, so far, the best method I have tried that enables working with double precision coordinates.