Precision and value range

I’m trying to visualize procedurally generated stellar systems with OpenGL. Before I used a selfmade 3D module, and from those time I remember that “float” as datatype neither had the value range nor the required precision to represent the system and the body positions. Thus I was using doubles - at times the camera is only a few meters from a space station while some bodies in the system are billions of meters away from the camera.

Now I feel uncertain - all the OpenGL examples use floats for positions. Will using glTranslated (as in applying the camera position to the matrix) use the added precision of doubles, or will it internally convert to floats? If the maximum precision in the matrices is float, then I need to chamnge my approach to displaying the system.

AFAIK: A single float can go up to ~1 lightyear with one unit being a single meter (e.g.: Float.MAX_VALUE roughly equals 1 lightyear).
If you do things right, you can continue to use floats without trouble.

Before drawing any body (or system of bodies) calculate the offset from the body to the camera and translate by that instead of translating the whole scene for rendering (as it is usually done). This reduces the depthbuffer-artifacts and fixes the ‘jitter’ you get when you get to the edge of your solar-system.


Vec3f cPos = camera.getPosition();
Vec3f bPos = object.getPosition();
Vec3f offset = subtract(bPos, cPos);

// Using OpenGL 1.1 here for demonstration
GL11.glTranslate(offset.x,offset.y,offset.z);
GL11.glCallList(object.getModel());

Another thing to make use of is a ‘frame of reference’-system. Its quite simple: “If I am close to a stellar-body (planet/moon/asteroid/spacestation), that body will be the origin (0,0,0) of the scene for physics and rendering. Else, my ships position is given as total position”.

I would strongly recommend using fixed precision for position and velocity. You want uniform precision over the entire space of the game, and you also want uniform precision of the velocity. A satellite orbiting the moon which in turn orbits the Earth which in turn orbits the sun will always have a very high velocity, and with double precision you would get worse local precision. Using a 64-bit long, you get a precision of 0.000512856272 meters, or ~0.5mm precision, way better than your 1m precision you would get with doubles at the edge of the universe.

@Longor1996: I remember a case when my camera position didn’t change anymore, because the offset I was adding was too small and eluded the precision possible at that position. But maybe I had done other things wrong there. My systems are definitely smaller than 1 ly. Largest position in my testing system was: x=2.3324265266315236E9 y=0.0 z=-2.0764744541120262E9. The smallest detauils that I’m currntly using is less than 1m though, in case of space vessels. But I don’t need to use that.

The suggestion, to subtract camera position from obejct positions and display everything relative to the camera deems me a good one. This way I can have real high precision near the camera. At the moment I’m still struggling with OpenGl and the matrices, my math has become quite rusty …

@theagentd:

Fixed precision is a good hint. I didn’t think of that option yet.

Thanks to both of you, that gives me some new thoughzts to go on with.

Project info is over there: http://forum.freegamedev.net/viewtopic.php?f=22&t=6278

The original Solarex project has an old thread in JGO too. But it’s locked because the breaks between the updates were too long.

The problem with floats (and doubles) is that they have a limited number of significant digits that they can care about. So it’s not really a matter of “how big a number do you need” or “how small a number do you need” - it’s how many significant digits do you need?

It sounds like you want both worlds: both really small numbers, and really large numbers. And that’s going to be a problem.

You can work with really large numbers, but you start losing precision at around, uh, 9 digits- that’s not exact, and it’s not even how it really works, but it’s an okay estimation to use. Consider this:


public class Main{
	public static void main(String[] args){
		
		float x = 123456789;
		float y = x + 1;
		
		System.out.println(x == y); // prints out true!
	}
}

You can also work with really small numbers, but again, you only get about 9 digits of precision:


public class Main{
	public static void main(String[] args){
		
		float x = 1;
		float y = x + .00000001f;
		
		System.out.println(x == y); // prints out true!
	}
}

You might reconsider how much precision you really need- do you really need sub-meter precision as well as precision for things that are over a light year away? It sounds like it’s time to rethink how you’re organizing stuff, maybe by packing them into “neighborhoods” instead of trying to do the whole shebang at once. It really depends what you’re going for, but you can’t have the best of both worlds.

Like Kevin said, floats have a “precision” depending on their value, so they are fit for when you’re only interested in a limited number of significant digits. However, GPUs use floats. To draw something in fixed precision, just convert your objects to a position relative to the camera, e.g. objectPosition - cameraPosition and render them like that. If your positions are relative to the camera, then floats are suddenly perfect! If something is a lightyear away, it doesn’t matter if it’s rendered at 10km off since that’ll still be the same pixel. So in essence:


long objectX = ..., cameraX = ...;
...

float x = (float)(objectX - cameraX) * SCALE; //SCALE could be (1f/1024f) to achieve ~1mm precision
float y = ...;
float z = ...;

If you are okay with limiting yourself to half the range of a long, you don’t even need to worry about overflowing longs during the subtraction. If you DO need the full range of longs, you can handle overflows easily by checking the resulting value and modifying the final long if an overflow occurred.

Yes, that’s why I asked in my original posting if glTranslated will make use of the added precision of doubles compared to floats. My former test showed that doubles have a suitable range and precision for my needs, while floats didn’t.

But the suggestion of thegentd to have all coordinates relative to the camera already solves most of the problem, because inn the area which is actually visble there is plenty of precision. I’m going to use this approach till I see a need for centimeter precision at the other end of the system :wink:

In theory, the driver could be computing the matrices at double precision since it’s done on the CPU and then upload them to the GPU as float precision at best, but I seriously doubt there are any drivers that do that. When it comes to the actual GPU, you can safely assume the math will be done at 32-bit float precision. Only recent GPUs can handle double precision math at all, and it’s slow as hell, between 1/2x and 1/32x as fast as 32-bit floats.

I’ll design my system with the idea of floats being used in calculations. At the moment I’m a bit surprised, but everything seems to work alright even that I need to reduce the precision from doubles to floats for display. I guess the tricky parts like docking at a space station are just not part of the project yet, and I’ll see the problems soon enough … but it’s cool to have the systems show in 3D without too much hassle :slight_smile:

Hi, as it happens I’m right now going through my current project replacing all float positions with doubles.

My original reasoning for using floats was along the lines of (a) as pointed out above the graphics subsystem uses floats so what’s the point of me working with doubles, and (b) all my large data structures would be a little smaller by saving on 4 bytes per dimension. This was despite knowing that double calculations are pretty much as fast as float on a lot of hardware and that my data objects were already so stupidly large that the extra data was not hugely significant!

Floats worked for a while but my game world started experiencing rounding problems at a much lower level world size than I would have thought would happen. In some cases that was down to sloppy code (e.g. incorrect casting double<->float when using Math.xxx functions for example) but in others there are places where I can’t see how to perform certain calculations without steadily losing precision along the way.

No doubt there are tricks and a better programmer could do things accurately, but for me I’m switching to double as the lazy solution :slight_smile: I should also say working with floats has been a bit awkward all along anyway in terms of occasional surprising results and requiring more awkward code in some places, so in a way I’ve been looking for an excuse to switch anyway. Java expression syntax and Math.xxx library design kind of assume double is the default floating type so working with floats seems like it will always feel like sort of swimming against the tide?

Anyhow that’s my story. I advise going double for the game world unless there’s a good reason not to, and casting down to float only at the point of calling graphics routines. If nothing else for the peace of mind knowing you won’t have to pick through every line of code looking for that place you’ve accidentally trashed half your precision without the compiler or JVM saying anything :slight_smile:

(Edit: On reflection this doesn’t answer the original question but I’ll leave it anyway…!)

My old stellar system generator used doubles and it works fine. I’m currently just converting those to relative positions in repsect to the camera, and then had those as float to OpenGL. Works fine so far. Doubles are easy to use and I can support the examination of “it’s good enough” for the purpose.