I have been conducting research and some small scale experiments into the “Infinite Universe” aspects of my virtual world ideas. The main problem to solve here is the Floating point precision problem, or the “10k problem”. I have talked about this before, but in short, 32-bit floating point numbers lose precision after, approximately, 10,000 units. If 1 unit is equal to one meter, then a player can only travel about 10,000 meters from the origin in any direction before the 32-bit numbers used to store their position begin to lose precision. This results in “Jitter”, ie, the objects position is not properly fixed. The further from the origin that the player goes, the worse this problem gets, until eventually the position of the object will jump significant distances in space, resulting in a completely unplayable game. A longer description of this, with some excellent examples, can be found HERE. This article also explains why simply “scaling down the world” will not work.
I have considered several solutions to this problem.
Two solutions that I rejected outright were developing an entirely new engine using arbitrary-precision floats (A massive amount of work, and probably very slow, since I’d need to use external libraries to use the high precision floats that I would need for EVERY single object) and modifying Torque3D to use arbitrary precision floats (again, massive amount of work, and the result would likely be very slow). I also rejected the idea of using a conventional Zone-based system where the user would reach the edge of the playable area, and a new level would be loaded. I did not want to have any “load zones” at all in the project, the world should be completely seamless.
That leaves a few more options.
The first option, which I used very successfully in my Icarus Rocket Simulator project, is to “move the world, and not the player”. Basically, this means that the player is kept at the origin, and the world moves around them. This should not be noticeable to the player, since the player moving 10 units to the left, for example, has the same effect as the world moving 10 units to the right. This is the approach that I had intended to use with my current project as well, however I realised quickly that it wouldn’t be feasible. Icarus Rocket Simulator involved just a handful of objects, whereas my current project involves potentially hundreds of objects on the screen at once. Moving all of those objects each tick is not a good solution.
The other options that I considered all had some similar elements. One of these options was to create a seamless zone-based world. This would work in a similar way to the conventional zone-based system, where the player is permitted to travel to the edge of the playable area, at which point the next “zone” is loaded. But with a seamless system, the zone loading is done in the background, the game is not interrupted. This means that the player can traverse zones without realising it.
Similarly, I could use a kind of “global coordinate system” to store the position of the objects. This global coordinate system would take the form of a grid, with each sector of the grid encapsulating a single playable area. When the player reaches the edge of a grid, the entire grid sector is moved in the opposite direction to the one the player is moving in, and the next grid sector is loaded. This results in a seamless transition from one playable area to the next.
The best solution, I feel, is the “floating origin” idea. This is quite similar to the previous two ideas, and is commonly used in Unity games (Such as Kerbal Space Program) to solve this issue. Basically, the player is free to travel in any direction, until the hit a given threshold, say, 10,000 units. At that point, player is reset to the origin, and the entire world is moved to compensate, so, if the player moves 10,000 units to the right, they are reset to (0,0,0), and the world is moved 10,000 units to the left. I initially feared that moving many objects at the same time would be very slow, but in actual fact, this is not true.
Objects are drawn every frame anyway, and most games maintain 30 frames per second or more. By changing the transform of the object, I am just making the object draw in a different location, I am not actually forcing it to redraw when it wouldn’t have. I am not loading or unloading memory, just updating a variable on each of the objects, so speed shouldn’t be an issue.
Since I am going to store my objects on the server (or, more likely, seed values that can be used to generate the objects) I can simply do a distance based check to see which objects are within the players view, then translate them from the global world coordinates stored on the server (the database will easily handle high-precision floats) into the players local coordinate system. There may be some issues with multiplayer gaming or AI, but these should be solvable using a similar technique.
I have created a test level in T3D to demonstrate this, and it seems to work very well. There is a slight visible movement when the world is redrawn, but I suspect this is because I am moving the objects in script. I intend to move the code to c++ and do the tests again.
The next problem is in how to modify the spherical terrain to work with realistic sizes. If I scale the terrain to a realistic size, the distance from the surface of the terrain to the center will be significantly greater than 10,000 units. I will probably need to treat the terrain not as a single object, but as a collection of nodes, which is essentially what it is anyway. I can then just translate or adjust the visible nodes to be within the players local coordinates, and store the position of the terrain in absolute coordinates on the server.
Overall, I am quite encouraged by the research that I have done, I think this problem may not be as difficult to solve as I initially thought.
I may in fact solve this problem now, before moving on to the other aspects of the spherical terrain.