PDA

View Full Version : Jumping lines during rotation



devdept
06-29-2008, 05:05 AM
Hi again Guys,


Here is today's issue, I am sure you know the reason.

First scenario:

2D drawing of lines only the, bounding rect (0,0, 400, 800) I can zoom / rotate without problems.

Second scenario:

Same 2D drawing of lines only, far from origin: bounding rect (490000, 500000, 400, 800). When I zoom / rotate I see the line ends jumping 2-3 pixel right/left/top/bottom at every frame.

Why?!? How can I improve this?


Thanks so much in advance.

Alberto

fldz
06-29-2008, 08:02 AM
It's a matter of precision.
If it were me, (a 100% guessing noob) and I really needed a half million units to be represented, I'd have like a Level Of Detail switch, but for scale.
Say it's a solar system, have a scaled down version whenever you reference that big a number, so the solar system model gets tiny but the bounding universe stays around 0,0,400,800

ie: scale down the solar system model instead of scaling up the universe?

ZbuffeR
06-29-2008, 08:13 AM
500000 Does not seem big enough to bring serious precision problems.
Can you post your code ?

MZIskandar
06-29-2008, 09:36 AM
Just for your info. I experienced this, with my 42Hz Interlaced CRT monitor during animation.

devdept
06-29-2008, 02:58 PM
ZbuffeR,

I don't know what to copy & paste, the relevant code is here and there. Please tell me what it is intersting to you, for example gluPerspective settings, near and far planes or what?

fldz,

Customers don't want scaled models, we were forced to switch to real scale coords.


Thanks,

Alberto

MZIskandar
06-29-2008, 03:41 PM
Whats the biggest and smallest number in the model coordinate? As far as I know, there are no scaled/real scale stuff in CG. I think it will be automatically adjusted. But, it will affect the object data size (higher precision, higher data - eg: a huge tower, and an ant), the coordinate precision will still be adjusted automatically.

I think codes within the OpenGL loop will help.

zbuffer, please correct me if I am wrong.

ZbuffeR
06-29-2008, 03:49 PM
Yes, my answer was a bit rushed, should have mentioned that it is not the absolute values that matters, but the relations between numbers. Unless you have flower to mountain ratios, it should be ok.
Interesting code will be the projection and modelview matrix manipulations, glviewport, how is translated and scaled geometry according to user input (or scripted sequences if done in a non-interactive way).

Z-Knight
07-01-2008, 08:28 AM
Hi, I believe I'm having the exact same problem in my scene...I'm using JOGL so the code is slightly different but the concepts are all the same.

Let me setup what I have...basically I have an Earth based system with a vehicle orbiting the Earth. I have made both the vehicles and the Earth the correct relative scale which means the vehicle itself is tiny and requires a very small near clipping plane so that I could zoom in to it. That said, I don't believe the clipping plane distance is the root of this problem as I'll explain later.

My problem is that when I zoom in close to the vehicle, around which I've drawn various lines and some shapes, I notice that I get very bad jitter (objects and shapes move relative to each other, etc) when I rotate my view - I'm not rotating or changing any coordinates, simply rotating my view around it...yes, effectively I am rotating the objects because I apply the glRotated() rotations but I think you know what I mean. To clarify, I'm rotating about the vehicle which is not at the center of the OPENGL scene, because the Earth is at the center - the vehicle is offset about 6000 kilometers/units away and I employ a centering technique so that I move to the vehicle and rotate around it as if it was in the center. The jitter happens when I do rotate about the vehicle but if I move the vehicle closer to the center of the opengl world - ie to 0,0,0 (inside the Earth) then the rotations are perfectly smooth and I don't see jitter.

What I do is basically the following (JOGL code snip):
I chose the body to focus on and translate that body to
the origin I then apply these rotations based on mouse
inputs:
gl.glRotated(rotX, 1.0, 0.0, 0.0);
gl.glRotated(rotZ, 0.0, 0.0, 1.0);
Then I translate the body back to its position

I did notice one thing...when I only rotate about one axis and keep the other axis at 0 degrees then I don't see jitter....but as soon as the other rotation is non-zero (ie rotZ is 1.0 degree for example) and I move my mouse to rotate rotX then I see jitter...and again, only if the object is not at the center. SO, it makes me think that there is more than just order of rotations that could be at fault, it seems like the distance of the object and the need to perform multiple translates is causing issues too.

Also, I do have a very near clipping plane because the object I have is a vehicle who I want to be able to zoom close too and yet I want to see the Earth background below it and so the far clipping plane is far as well and I wonder if the combination of these two and the other factors are combining for the jitter. Just as a test I reduced the far clipping plane significantly to see if maybe the ratio of the distances of far clipping plane to close clipping plane is a factor and it is not...the jitter still exists even though I have a low ratio.

devdept
07-01-2008, 03:08 PM
ZbuffeR,

Here are some values from our program. Do you see something wrong?


glViewport(0, 0, 344, 383);

gluPerspective(26.99, 0.89, 0.05, 287.96);

gluLookAt(
{491663, 475896, 14.4254},
{491658, 475907, -0.350002},
{-0.623493, 0.50244, 0.599008});


Z-Knight,

Yes we are doing the same thing: rotating around a center very far from the scene origin. Why don't you post the data I've just posted so we can compare them?


Thanks,

Alberto

Z-Knight
07-02-2008, 08:01 AM
I'm trying to put together a little JOGL online demo for you to load and see my exact problem and I hope to have that working sometime today...my demo consists of a 3D earth scaled to the correct size in kilometers and a teapot representing the International Space Station (or some other vehicle) that is scaled to the correct size (so it means it is quite tiny in comparison - 50 meter radius (0.050 km) and I notice that my horrible jitter happens when the vehicle is away from the center of the scene and I've minimized the number push/pops and translations/rotations/etc so as to eliminate any possible cummulative errors in calculations - though there still could be some.

Anyway, here is what I have for my settings:


glViewport(0, 0, 640, 480);

// I can vary the far plane distance from 100 to 100000000.0
// and I get the same jitter
gluPerspective(65.0, 1.333, 0.005, 100000000.0);

gluLookAt(
{10000.029588568046, 10000.004951428176, 10000.014084146884},
{10000.0, 10000.0, 10000.0},
{0, 1, 0));

The reason my gluLookAt eye point is so close to the lookat point is because I have a very small object so I want to be close to it to view it.

I have to believe that being so close is the cause of my problem but it also confuses me that I can be this close at 0,0,0 and not see the same jitter...for example my gluLookAt is this:


gluLookAt(
{0.029588568046, 0.004951428176, 0.014084146884},
{0.0, 0.0, 0.0},
{0, 1, 0));

Z-Knight
07-02-2008, 09:18 AM
I've created a quick demo of my problem and you can run it from here:

TestRotations.jnlp (http://www.zaczek.com/jogl/TestRotations.jnlp)

I implemented some rudimentary keyboard and mouse rotations but nothing real so don't be surprised if the rotations are not acting as you expect - just quick and dirty:

Mouse Inputs - use left mouse button to rotate around

Keyboard Inputs:
1 - Focus on "Earth" (Earth Size: 6000 unit radius)
2 - Focus on Teapot located at 0, 0, 0
3 - Focus on Teapot located at 1000, 1000, 1000
4 - Focus on Teapot located at 10000, 10000, 10000
5 - Focus on Teapot located at 30000, 30000, 30000
6 - Focus on Teapot located at 60000, 60000, 60000
7 - Focus on Teapot located at 100000, 100000, 100000

Q - Far Clipping Plane: 100
W - Far Clipping Plane: 1000
E - Far Clipping Plane: 10000
R - Far Clipping Plane: 100000
T - Far Clipping Plane: 1000000
Y - Far Clipping Plane: 10000000
U - Far Clipping Plane: 100000000

A - Near Clipping Plane: 5.0
S - Near Clipping Plane: 0.5
D - Near Clipping Plane: 0.05
F - Near Clipping Plane: 0.005
G - Near Clipping Plane: 0.0005
H - Near Clipping Plane: 0.00005
J - Near Clipping Plane: 0.000005


Note that when viewing at 10,000 away from the earth (key 4) changing the clipping plane distance has no effect on the jitter....I can have a small far to near clipping ratio and still have horrible jitter.

Here is my display() method...note, this code is in JOGL but it would be almost exactly the same in OPENGL:



public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();

if (reset) {
int width = getWidth();
int height = getHeight();
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
// Set the Field-of-View, Aspect Ratio, Near & Far clipping planes
glu.gluPerspective(65.0, (double) width / (double) height, nearPlane, farPlane);
gl.glMatrixMode(GL.GL_MODELVIEW);
reset = false;
}

// Clear Screen And Depth Buffer
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

// Reset/Clear matrix
gl.glLoadIdentity();

// Update light position
// 0 in the last component causes jagged terminator on planets, 1 results
// in a smooth terminator but the location of the sunlight is no longer
// correct...not sure why. Old code used a 0 (zero) very successfully,
// what changed?!
gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition, 0);

gl.glPushMatrix();
double posX = Math.cos(rotY * Math.PI / 180.0) * radiusOffset;
double posY = Math.sin(rotY * Math.PI / 180.0) * radiusOffset;

double zX = Math.cos(rotX * Math.PI / 180.0) * radiusOffset;
double zY = Math.sin(rotX * Math.PI / 180.0) * radiusOffset;


double eyeX = systemX + posX;
double eyeY = systemY + posY;
double eyeZ = systemZ + zY;

glu.gluLookAt(eyeX, eyeY, eyeZ,
systemX, systemY, systemZ,
0, 1, 0);

System.out.println("Eye: " + eyeX + ", " + eyeY + ", " + eyeZ);
System.out.println("View: " + systemX + ", " + systemY + ", " + systemZ);

// Draw stars
displayStars(gl);

// Draw Teapot
gl.glPushMatrix();
gl.glEnable(GL.GL_LIGHTING);
gl.glEnable(GL.GL_COLOR_MATERIAL);
gl.glDisable(GL.GL_CULL_FACE);
gl.glTranslated(teapotX, teapotY, teapotZ);
GLUT glut = new GLUT();
gl.glColor3f(1f, 1f, 0f);
glut.glutSolidTeapot(0.01);
gl.glDisable(GL.GL_LIGHTING);
gl.glColor3f(1f, 1f, 1f);
glut.glutWireTeapot(0.0101);

gl.glScaled(0.02, 0.02, 0.02);
displayAxes(gl);
gl.glPopMatrix();

// Draw Earth
displayEarth(gl);

gl.glPopMatrix();

// Flush The GL Rendering Pipeline
gl.glFlush();
}


Here are the links to the source codes:
KeyHandler.java (http://www.zaczek.com/jogl/TestRotations/KeyHandler.java)
MouseHandler.java (http://www.zaczek.com/jogl/TestRotations/MouseHandler.java)
Renderer.java (http://www.zaczek.com/jogl/TestRotations/Renderer.java)
ResourceRetriever.java (http://www.zaczek.com/jogl/TestRotations/ResourceRetriever.java)
TestRotations.java (http://www.zaczek.com/jogl/TestRotations/TestRotations.java)
TextureReader.java (http://www.zaczek.com/jogl/TestRotations/TextureReader.java)
BitmapLoader.java (http://www.zaczek.com/jogl/TestRotations/BitmapLoader.java)
stars.jpg (http://www.zaczek.com/jogl/TestRotations/stars.jpg)
earth.jpg (http://www.zaczek.com/jogl/TestRotations/earth.jpg)

devdept
07-02-2008, 02:03 PM
Z-Knight,

I tested your program and the 'jumping' is very similar to what I see in our app.

Somebody should help us to spot where the problem is.

Thanks,

Alberto

Z-Knight
07-02-2008, 02:52 PM
gosh I hope so....I'm worried that for me is has to do with the small size and the fact that at large distances from center a rotation of 1.0 degree (for example) translates to a large translation while at near center the same angle rotation is only a small translation.

I should probably figure out with simple geometry how much a one degree rotation translates into a distance at 10000 units and see if the size of my object would be too small and fall outside the bounds of the double precision capabilities...I can't believe that my object size of 0.01 units compared to a distance of 10000 units away can be outside of the double precision limits - can it?

I figured that in your case, devdept, that might be the issue since you had such large eye and lookat position (ie 490000, etc) so you might be far out there but I have much smaller distance and I have this issue too.

sigh...I hope I'm stupid and I did something supremely stupid so I can easily fix this.

edit: correction, had said teapot was 0.05 but is 0.01 size.

Ilian Dinev
07-02-2008, 02:57 PM
I'm not sure, but Java's gluSphere maybe doesn't generate normals? As you rotate the view, the light seems to rotate, too - but in your code lightPosition[] is constant. This makes me think that generated normals are incorrect, or missing altogether.

Z-Knight
07-02-2008, 03:07 PM
I'm not sure, but Java's gluSphere maybe doesn't generate normals? As you rotate the view, the light seems to rotate, too - but in your code lightPosition[] is constant. This makes me think that generated normals are incorrect, or missing altogether.

the normals are ok, I just didn't put the light position in the display() method within the glPushMatrix() so it doesn't rotate with the view but the objects rotate - the normals are OK.

The Earth doesn't actually have anything to do with the issue of the jitter though...I could take out the earth and the jitter remains...I simply included the Earth for a reference so one could see something moving in the view.

-NiCo-
07-03-2008, 04:58 AM
Anyway, here is what I have for my settings:


gluLookAt(
{10000.029588568046, 10000.004951428176, 10000.014084146884},
{10000.0, 10000.0, 10000.0},
{0, 1, 0));



Looks like a precision issue to me. Here's some test code:



float tmpf = 10000.029588568046;
double tmpd = 10000.029588568046;
fprintf(stderr,"%5.12f\n%5.12f\n",tmpf,tmpd);


The output is

10000.029296875000 for float
10000.029588568046 for double

Z-Knight
07-03-2008, 05:23 AM
Nice test, thanks...I was afraid this would be a precision error. sigh.

I repeated this test in Java and have some similar disappointment:


float tmpf = 10000.029588568046f;
double tmpd = 10000.029588568046;

System.out.println(" float: " + tmpf + "\n"
+ "(cast): " + (double)tmpf + "\n"
+ "double: " + tmpd);


Resulted in:


float: 10000.029
(cast): 10000.029296875
double: 10000.029588568046

Z-Knight
07-03-2008, 12:54 PM
I updated my code and the demo and I think I figured out something...

here is the demo link: TestRotations.jnlp (http://www.zaczek.com/jogl/TestRotations.jnlp)

This time it defaults to the "non jitter" code....press 'L' to toggle between jitter and non-jitter code.

In the jitter code (original code) I created an Earth and a teapot and I set the gluLookAt() to move the view to the teapot location and to rotate around the teapot...because of the precision of floats I believe this caused the jitter as you moved the teapot farther from 0,0,0. To fix this I tried to apply a global glTranslated() and translate the entire system by the distance of the teapot...ie move everything back by this distance so that the teapot was at 0,0,0 and my view would be looking at 0,0,0 and I figured in this case the precision would not be a problem because I was using gluLookAt() around the 0,0,0 point instead of some far distance such as 10000, 10000, 10000. Well...this still caused jitter because (I believe) the glTranslated() would apply the 10000 distance translation which effectively is a matrix multiplication which still cause the precision problem.

SO...I did the following to change the display method to make the system not-jitter. I still translate the objects by the distance to the teapot...so the earth gets moved down and the teapot is moved to 0,0,0, etc....but the difference is that instead of a global glTranlated() I apply the differencing in position directly on each object and so now the jitter is not present.

Note, that updated the demo and the codes that are linked above...I also added a couple of things. I draw a white line from the Earth to the teapot (just because) and I have a wireframe blue/cyan sphere that is a fixed size and I use it see that when I press the various scale keys I could see things scale relative to something...you can turn of the wireframe sphere using the 'P' key.

To scale the system (earth, teapot scale) press the Z, X, C, V, B, N keys to scale from 1, 10, 100, 1000, 10000, 100000, respectively.

devdept
07-04-2008, 05:57 AM
Z-Knight,

Are you trying to say that:

gluLookAt(10000,10000,10000, 9999,9999,9999, 0,1,0);

behaves differently from:

gluLookAt(1,1,1, 0,0,0, 0,1,0);

Thanks,

Alberto

Xmas
07-04-2008, 06:23 AM
Given that single precision float can only accurately represent 7 significant decimal digits I think that is hardly surprising. At 10000 the resolution of single precision floats is just 1/1024.

devdept
07-04-2008, 06:49 AM
We work with doubles and at 500000 we experience the same issue.

Thanks.

Alberto

Xmas
07-04-2008, 10:18 AM
GPUs don't use double precision for OpenGL yet.

Z-Knight
07-04-2008, 07:20 PM
Z-Knight,

Are you trying to say that:

gluLookAt(10000,10000,10000, 9999,9999,9999, 0,1,0);

behaves differently from:

gluLookAt(1,1,1, 0,0,0, 0,1,0);

Thanks,

Alberto

Yes, I think so...at least that's what I've found in my code. I hope I did that right.

Z-Knight
07-04-2008, 07:22 PM
GPUs don't use double precision for OpenGL yet.

Yeah, I believe Xmas is right....I wish there was some flag to set that to true but I've not heard anyone mention it yet and I too was surprised that OpenGL converts to floats internally...especially since I've heard of people mention how the moved to doubles and improved their "worlds/scenes" - I need to get more info from them.

Z-Knight
07-04-2008, 07:31 PM
We work with doubles and at 500000 we experience the same issue.

Thanks.

Alberto

I would highly suggest you do what I did: basically translate every object in your scene by the 3D location of the object you want to focus on using gluLookAt. So for example, in my case I have an earth-teapot (or vehicle) system and in one case I want to focus on the Earth so I leave the Earth at 0,0,0 and the vehicle at 10000,10000,10000 - rotations are smooth. Then, I decide to focus on the vehicle and so I subtract the 10000,10000,10000 from the positions of the Earth and the position of the vehicle and so the vehicle itself will be at 0,0,0 and the Earth will be at -10000,-10000,-10000 and my gluLookAt might only change how far the eye is from the look point since the vehicle is smaller and so I want the eye to be closer but the look point will remain at 0,0,0 - in this case the rotations are also smooth.

If I don't do the above then I would have gluLookAt for the vehicle rotation case be something like gluLookAt(10001,10001,10001, 10000,10000,10000, 0,1,0) and that introduces jitter because (I believe) the view is essentially being rotated around the 0,0,0 point with gluLookAt - I mean the gluLookAt multiplies the view matrix and at 10000,10000,10000 the error is much greater than at 0,0,0 (or near it).

One word of caution...don't simply do a global glTranslate(-10000,-10000,-10000) on the entire scene thinking you can kill two birds with one command because this didn't seem to work for me...and I think this again is a result of a matrix multiplication that occurs internally via the glTranslate() command that brings in the same inaccuracy into play. So, make sure to subtract the distance internally for each object before you apply their individual glTranslate() commands and it should work...it did for me.

Also, one other thing to clear up...the both cases in the demo that I created use the gluLookAt() at 0,0,0...ie, the look point is at 0,0,0 and not at the location of the vehicle (say at 10000,10000,10000). The "non-jitter" case moves all objects by the offset distance so the teapot ends up at 0,0,0. The "jitter" case use a global glTranslated() call to move everything by the offset distance which effectively moves the teapot to 0,0,0 but because the glTranslated() call multiplies everything by -10000,-10000,-10000 translation then the precision loss is still there. This jitter case is exactly what happens if I didn't move any of the objects and simply did a gluLookAt() at the teapot while it was at 10000,10000,10000. I might add that to the demo just for completeness...give me some time.

I updated the demo: TestRotations.jnlp (http://www.zaczek.com/jogl/TestRotations.jnlp)

Now, pressing 'L' toggles through the 3 modes and the corresponding gluLookAt() values are displayed at bottom left.
0) No jitter - each object translated explicitly
1) Jitter - global glTranslate() call
2) Jitter - No translations, gluLookAt() points at object at the specified location

Z-Knight
07-06-2008, 03:10 PM
btw, if anyone can confirm I did things correctly I'd appreciate it...also this gives me a chance to bump this thread :)

devdept
07-08-2008, 05:01 AM
Z-Knight,

I was thinking to glTraslate() the model and to setup the camera with:

gluLookAt(1,1,1, 0,0,0, 0,1,0);

Do you think it won't work?

Thanks,

Alberto

Z-Knight
07-08-2008, 07:07 AM
I don't think so...I tried this and if you run my demo that is one of the cases...case (1). In this case I tried to use just a global glTranslated() that would translate the entire scene by the offset distance of the object that I want to focus on and I still had the jitter....it wasn't until I explicitly subtracted the offset distance from each object before translating it, that it finally worked: case (0).


Basically this case (1) did not work:


glTranslate( -offset )
glPushMatrix()
glTranslate( earthDistance )
DrawEarth()
glPopMatrix()

glPushMatrix()
glTranslate( teapotDistance )
DrawTeapot()
glPopMatrix()


So I had to do the following instead case (0) and the jitter went away:


glPushMatrix()
glTranslate( earthDistance - offset )
DrawEarth()
glPopMatrix()

glPushMatrix()
glTranslate( teapotDistance - offset )
DrawTeapot()
glPopMatrix()


where 'offset' is the distance to the object you want to view...for example, if you wanted to view the teapot then 'offset' would be equal to 'teapotDistance' and so the glTranslate() before DrawTeapot() would effectively be 0,0,0

Z-Knight
07-09-2008, 08:16 AM
I'd like to add some thoughts to my post above...I think the reason the second pseudocode is correct (case 0) is because in the first code (case 1) the global glTranlate(-offset) is essentially a matrix multiplication of the modelview matrix, and if you have a large offset distance then this means that you are doing a multiplication with large values that exceed the floating point precision and hence you lose some overall precision and thereby get the jitter that we see.

In the second case (case 0) the '-offset' is being applied directly to each object prior to the actual call by glTranslate() and hence the focused object (the object we want to be at 0,0,0 and be the thing we look at) is not translated by a large distance and hence the matrix multiplication on the modelview matrix doesn't cause a loss of precision....yes there will be a loss of precision on drawing the Earth because you would be applying a large value to the glTranslate() call that multiplies that modelview matrxi before the Earth is drawn, but the Earth is not the object we are focusing on and hence it gets moved far away and so we won't be seeing the effect of the loss of precision on its drawing.

those are just my $0.02....I could be completely wrong but this sort of makes sense to me.

Dark Photon
07-09-2008, 05:27 PM
I would highly suggest you do what I did: basically translate every object in your scene by the 3D location of the object you want to focus on using gluLookAt.
You could, but no, it's not that hard:

small numbers * Modeling = big numbers * Viewing = small numbers
small numbers * ModelView = small numbers

Small numbers = finer precision, big numbers = courser precision. You want to stay in small numbers anytime you're doing float math and want to maximize precision.

Solution: don't use OpenGL to do your matrix math. Do it yourself in double precision, then just toss OpenGL a matrix now and then (glLoadMatrix).

This is a simpler version of what you described. The key difference being instead of the object you want to focus "on" being the translate, it's the object you want to focus "with" (the eyepoint) is the translate (trace it through -- you'll see what I mean). Cheap and easy.

Z-Knight
07-10-2008, 08:19 AM
I would highly suggest you do what I did: basically translate every object in your scene by the 3D location of the object you want to focus on using gluLookAt.
You could, but no, it's not that hard:

small numbers * Modeling = big numbers * Viewing = small numbers
small numbers * ModelView = small numbers

Small numbers = finer precision, big numbers = courser precision. You want to stay in small numbers anytime you're doing float math and want to maximize precision.

Solution: don't use OpenGL to do your matrix math. Do it yourself in double precision, then just toss OpenGL a matrix now and then (glLoadMatrix).

This is a simpler version of what you described. The key difference being instead of the object you want to focus "on" being the translate, it's the object you want to focus "with" (the eyepoint) is the translate (trace it through -- you'll see what I mean). Cheap and easy.


Are you saying that I should replace any of my glTranslate(), glRotate() etc with my own code to the matrix multiplications, but of course using double precision? And then I won't have to translate things to the 0,0,0 position for viewing and instead they could remain at their far distances but because I used double precision to calculate their translations, etc then I won't have the jumping of the objects?

Or were you referring to using my own matrix calculations for setting the view matrix?

I think I follow your concept in general and I agree that it would possibly be simpler or at least a good alternative solution. Thanks.

Dark Photon
07-10-2008, 10:24 AM
Are you saying that I should replace any of my glTranslate(), glRotate() etc with my own code to the matrix multiplications, but of course using double precision?
Yes. All of them.


And then I won't have to translate things to the 0,0,0 position for viewing and instead they could remain at their far distances but because I used double precision to calculate their translations, etc then I won't have the jumping of the objects?
Yes, but let me make sure we're on the same page. You'll model them in OBJECT SPACE close to the origin (small numbers = finer precision), then use the MODELING matrix to translate them into WORLD SPACE where their coordinates would be large.

The GPU and the OpenGL driver never actually stop in WORLD SPACE with these objects though, so you don't much care that their world coordinates would be large, and would thus result in a loss of precision if you represented these world coordinates in 32-bit float in GL (either directly as vertex positions, or in a transform matrix).

Also, I'm not saying there'll be no jumping. But the "jumping" will be limited to the maximum size of your objects and "double"-precision, not the size of your objects and "float"-precision.


Or were you referring to using my own matrix calculations for setting the view matrix?
Not just the VIEWING matrix, the MODELVIEW matrix (both MODELING and VIEWING matrices, and their product).

Recall:

(object space) * MODELING = (world space)
(object space) * (MODELING * VIEWING) = (eye space)
(object space) * MODELVIEW = (eye space)

Compute MODELING and VIEWING in double precision, smoosh them together in double precision, then hand to OpenGL as the MODELVIEW matrix via glLoadMatrixd.

Because the "big numbers" only results from dropping into world space, tell the GPU to skip world space and never go there! Then you don't need to worry about big numbers truncated by dropping into float precision.

devdept
07-10-2008, 12:22 PM
I like this approach and it is probably the easiest to implement, I think.

glTranslate, gluLookAt, etc. source code is available somewhere on the internet (I can't remember where). It will be easy to add myTranslate, myLookAt that do exactly what OpenGL versions do.

Maybe, replacing the gluLookAt() function can even be enough, what do you think?

Thanks,

Alberto

Dark Photon
07-10-2008, 01:29 PM
Maybe, replacing the gluLookAt() function can even be enough, what do you think?
No, that's only the VIEWING transform side.

Let's think about where the problem occurs.

You model the object (a ball let's say) in object space. Say the coordinates are within 10 units (call them meters, for this example) of the origin. With float precision, you get ~7 digits of decimal precision, so you get maybe ~0.00001 meter or 1/100th of a millimeter precision worst case for those verts.

Then you build your MODELING matrix using OpenGL matrix functions (in float, of course) to shift this object into WORLD SPACE over at 100000, 100000. Again, 7 digits of precision so those values are only accurate to around .1 meters (10 centimeters). Oops.

And of course before this you stacked your VIEWING matrix on the MODELVIEW stack using OpenGL matrix functions (again, in float). Let's suppose you're eyepoint is over near that ball. So your viewing transform has a translate of about -100000, -100000. Again, 7 digits of precision so those values are only accurate to around 10 centimeters (oops).

Now in infinite precision, these big translates add to give you precisely the right answer. But given their large magnitudes and floating point round-off, the sum (because we used float to do this) is only accurate to about 10 centimeters. So MODELVIEW's transformation from object space to eye space is only accurate to about 10 centimeters. Man, that sucks!

So, compute MODELING and VIEWING in double precision (~15 digits of decimal precision), smoosh them together in double precision, and then thunk down to float precision only when you hand the matrix in OpenGL. As you might guess, your "big translate numbers" have to be a lot bigger (1e8 bigger) to generate the same inaccuracy in the results.

(Note that I oversimplified this example for clarify, glossing over epsilon, sqrt of machine precision, well-conditioned functions, etc. where you might actually only get 1e4 accuracy from float instead of 1e7 even if you used "nice math", but you get the idea.)

Z-Knight
07-10-2008, 07:06 PM
good info, really good info....I'm going to have to try this later on as for now I'll use my current solution for the time being (deadlines, etc). But I learned a lot...thank you very much for the comments.

devdept
07-12-2008, 07:15 AM
Here is the code of the glu.LookAt() func. As you can see there are many variables (and the matrix) declared as floats.

I will first change this to use doubles, than use the matrix with gl.LoadMatrix() as suggested above.

The full source code file can be found here (http://oss.sgi.com/cgi-bin/cvsweb.cgi/projects/ogl-sample/main/gfx/lib/glu/libutil/project.c?rev=1.4;content-type=text%2Fplain).


void GLAPIENTRY
gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
GLdouble upz)
{
int i;
float forward[3], side[3], up[3];
GLfloat m[4][4];

forward[0] = centerx - eyex;
forward[1] = centery - eyey;
forward[2] = centerz - eyez;

up[0] = upx;
up[1] = upy;
up[2] = upz;

normalize(forward);

/* Side = forward x up */
cross(forward, up, side);
normalize(side);

/* Recompute up as: up = side x forward */
cross(side, forward, up);

__gluMakeIdentityf(&m[0][0]);
m[0][0] = side[0];
m[1][0] = side[1];
m[2][0] = side[2];

m[0][1] = up[0];
m[1][1] = up[1];
m[2][1] = up[2];

m[0][2] = -forward[0];
m[1][2] = -forward[1];
m[2][2] = -forward[2];

glMultMatrixf(&m[0][0]);
glTranslated(-eyex, -eyey, -eyez);
}

devdept
07-16-2008, 12:34 AM
Dark,

Now I have the following code:


gl.MatrixMode(GL_PROJECTION);
gl.LoadIdentity();

gluPerspective(angleOfView, aspect, near, far);

glMatrixMode(GL_MODELVIEW);
gl.LoadIdentity();

myLookAt(location, target, upVector);

DrawEntities();

As you can see below, gluPerspective works on doubles and the myLookAt function is my version that works with doubles and load it using glLoadMatrixd().

The result is still the same, can you explain me why? :p

Thanks,

Alberto


void GLAPIENTRY
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
GLdouble m[4][4];
double sine, cotangent, deltaZ;
double radians = fovy / 2 * __glPi / 180;

deltaZ = zFar - zNear;
sine = sin(radians);
if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
return;
}
cotangent = COS(radians) / sine;

__gluMakeIdentityd(&m[0][0]);
m[0][0] = cotangent / aspect;
m[1][1] = cotangent;
m[2][2] = -(zFar + zNear) / deltaZ;
m[2][3] = -1;
m[3][2] = -2 * zNear * zFar / deltaZ;
m[3][3] = 0;
glMultMatrixd(&m[0][0]);
}

Dark Photon
07-16-2008, 05:06 AM
glMatrixMode(GL_MODELVIEW);
gl.LoadIdentity();
myLookAt(location, target, upVector);
DrawEntities();
As you can see below, gluPerspective works on doubles and the myLookAt function is my version that works with doubles and load it using glLoadMatrixd().

The result is still the same, can you explain me why?
You're loading your VIEWING transform into OpenGL via glLoadMatrixd. This will chop it down to float precision. Then in DrawEntities() I presume it appends your MODELING transform via glMultMatrix*, which also chops precision down to float and then does the multiply.

Stop. Don't use OpenGL for matrix math. Don't even use it to store intermediate matrices. That'll drop you down to float precision, which "we're assuming" is the root of your problem.

Instead, update your own double-precision MODELVIEW transform in your code. Then when you need to render a model, only then glLoadMatrixd your spiffy double-precision accurate matrix into OpenGL. That way, you wait until "after" the MODELING and VIEWING transforms have been combined to chop it down to float precision. That's the key.

devdept
07-16-2008, 05:14 AM
Hi Dark,


I don't have any MODELING transform I simply draw a figure using lines with coords like(500000, 500000, 500010, 500008) and the camera is looking pretty close that area.

Do you mean I have to:

1) Extract the gluPerspective source code
2) Save the PROJECTION matrix in my code
3) Compute myLookAt
4) Save the MODELVIEW matrix in my code
5) Combine the two (multiplication will be enough?) in my code
6) Do the gl.LoadMatrixd(combined)
7) Then to draw entities?


Thanks again.

Alberto

Dark Photon
07-16-2008, 05:47 AM
I don't have any MODELING transform I simply draw a figure using lines with coords like(500000, 500000, 500010, 500008) and the camera is looking pretty close that area.
There's your problem. OpenGL doesn't do doubles. So when you give it those vertex coordinates, thunk, they're chopped down to float precision, which means you only have maybe 0.1 unit accuracy.

Instead, model your object near the origin, use a MODELING transform to translate your object over 500000 (or wherever), and do your MODELVIEW matrix math in double precision all in your code.


Do you mean I have to:

1) Extract the gluPerspective source code
2) Save the PROJECTION matrix in my code
3) Compute myLookAt
4) Save the MODELVIEW matrix in my code
5) Combine the two (multiplication will be enough?) in my code
6) Do the gl.LoadMatrixd(combined)
7) Then to draw entities?
Close. First, your problem probably isn't in PROJECTION transform precision, so you can just use gluPerspective directly instead of #1 and #2.

Then do as I described above. You need to use a MODELING matrix, and stop positioning your objects at huge coordinates directly. Try to always model your objects around the origin, to maximize floating-point precision.

Just keep in mind you only get about 7 decimal digits with float. That's it! So you can have 0.1 precision at 500000, or you can have 0.000001 precision at around 1.

devdept
07-16-2008, 05:55 AM
Unfortuantely, it is not that easy.


We import an autocad file where for example the origin is Rome and contains the map of London. Then we take the London map extents and put the camera centered over it.

The map can have million of vertices, processing every time each one would be too slow.

On the other hands other CAD systems render this model correctly so a solution must exist.


Thanks,

Alberto

Dark Photon
07-17-2008, 05:04 AM
Unfortuantely, it is not that easy.

We import an autocad file where for example the origin is Rome and contains the map of London. Then we take the London map extents and put the camera centered over it....other CAD systems render this model correctly so a solution must exist.
Well this isn't an OpenGL question anymore. Sounds like you need to establish for certain what the problem is. If it is as I described (which it almost certainly is), you can solve it as I mentioned. How you group loaded CAD objects using a spatial acceleration data structure of some sort and map that to OpenGL is an application detail.

devdept
07-17-2008, 05:16 AM
You are right, we need to find a precise and fast way to move the moon to the center of the solar system without using glTranslated() and would be for sure more slow.

Thanks so much again for your help. I will print this post a read it again and again to find a solution.

Alberto