Baby's First Planet Renderer

Published November 02, 2022
Advertisement

Something I've wanted to do for a very long time is to create an engine for rendering solar systems and planets of realistic scale. Over the past 3 months I built the technology required to make it happen. I had to completely overhaul my game engine to deal with the problem of massive scale.

Computers use 32-bit floating point numbers for most calculations, but those numbers can only represent about 16 million steps accurately, which means that for an earth-sized planet you only get about 1 meter precision (obviously not enough!). If you were to use floats for everything, it would jitter like crazy and physics would blow up. Double precision can help, but it is slower and there is already a lot of effort invested in single-precision code (e.g. physics).

To solve this, I have to use a hierarchy of local reference frames, where each object's position is relative to its reference frame, rather than to some world origin. This allows for scenes of any size, but makes everything a game engine does much more complicated.

Ice planet, aerial view

I had to rewrite the graphics renderer to deal with the precision by rendering the scene in "slices" at different depths, and by treating all object coordinates as a unit vector + distance offset from the camera. Far away objects are scaled down around the camera to a manageable size. This also requires scaling lighting calculations for everything to look right. Shadows are a nightmare that I haven't completely solved.

Simulated physics objects on an earth-sized planet with multiple reference frames

To do physics in such a situation is also difficult because the physics engine needs to be aware that every object is potentially in a different reference frame, yet still needs to handle collisions and contact properly between those objects. I had to deeply integrate the concept of reference frames into the physics engine for this to work. I don't think this would be possible with an off-the-shelf physics engine.

Illustration of quad sphere with level of detail subdivision. Not my picture, but very similar to my approach. From here:
https://gamedev.stackexchange.com/questions/149762/quad-sphere-subdivision-algorithm

Then I had to work on the planet generation itself, which is non-trivial. Planets are split into a hierarchy of quadrilateral tiles on each face of a cube that is projected onto the sphere. Tiles are recursively refined in detail in order to satisfy the requirements of observer(s) in the scene. Each tile is generated from its parent tile by a 2-step process: interpolate (upsample) a quarter of the parent tile, then add noise to increase the detail.

The noise itself must be generated coherently across the entire sphere in a deterministic way. This means that the noise for every tile is initialized with a random seed that is derived from the tile's address (location) on the cube-sphere. For continuity, the tile borders (edges and vertices) need to have the same noise as the neighbors, so there also needs to be a way to uniquely identify tile edges and vertices at any level of detail. There is also some overlap with adjacent tiles which is necessary for continuity during interpolation, and for calculation of correct surface normals.

Illustration of tile overlap handling and parent-child relationship. Green is tile interior, Gray is border, red are vertex regions, blue are edge regions. A unique ID is generated for each part, which controls random seed.

“Square-square” interpolation (ACM Siggraph, Miller 1986) is used to get smooth cubic? interpolation of the parent noise.

The resulting fractal noise is transformed using some functions to achieve a desired terrain appearance, and this is used as the elevation for the tiles. The elevation is converted to a triangle mesh, projected from cube to sphere, and then offset relative to the tile's local reference frame.

Texturing is done using a tri-planar texture mapping technique in the local space of the tile vertices. (I tried world space first but this was broken when changing reference frames). To avoid texture tiling artifacts, I use a "fractal" distance-based texture scaling that blends the texture at two different scales.

There's still a ton of stuff to do to make the fidelity better of the generation and rendering. I don't have any sky/atmosphere rendering, nor any stars, nor water, nor any objects (i.e. rocks) placed on the surface. Eventually, I want to do simulation of the planetary geology (tectonic simulation), and a hierarchical simulation of erosion. These will be used with a complex model of materials to achieve more realistic terrain than other systems (e.g. No Man's Sky), with rock strata of various types, and as many other geological features as I can model efficiently.

Zoom sequence from space to surface:

Human scale (light on camera)
2 likes 4 comments

Comments

JoeJ

Something I've wanted to do for a very long time is to create an engine for rendering solar systems and planets of realistic scale.

I always think that's what most of us have in common. :D

Nice results. I like the smooth / sand dunes alike flat ground vs. the rocky mountains.

Eventually, I want to do simulation of the planetary geology (tectonic simulation), and a hierarchical simulation of erosion.

That's what i've worked on for much too long already. Here's current results at some medium detail level:

Maybe that's the first large scale terrain simulation which is actually full 3D. : ) At least i've not found anything else, not even research papers.
Likely i have to work on forming caves or arches to demonstrate the true 3D advantages, but currently i'm happy it finally starts to look realistic.
For still unknown reasons, erosion in 3D is much harder than with height maps. I had to try dozens of methods until something worked well enough.
And it's orders of magnitudes slower than heightmaps. Doing all steps to make this image takes >30min i guess. To get down to ‘human scale’, i'll likely need days of over night processing. Assuming my HDD is big enough… ; )

But iirc, something like Gaea takes a second to make a high quality 1024^2 terrain on GPU. So maybe you could do this in the background while flying towards the planet. With procedural upscaling for close ups.
I did 2D sim as well, to learn how it works, and got nice results:

Few seconds on single threaded CPU. And you want lower frequencies first, then upscale and simulate again to add detail. So this process would match the requirements you have while getting closer to a planet.
I think it would be worth it, because purely procedural generation using noise alone always feels a bit boring and repetitive.
Just a bit of simulations might be able to give huge improvements… :D

November 02, 2022 12:23 PM
Aressera

@JoeJ
Maybe that's the first large scale terrain simulation which is actually full 3D. : ) At least i've not found anything else, not even research papers.

Have you seen this paper? I was planning on using a similar “layer map” type data structure to represent the 3D material distribution, stored as a 3D array of material ID + thickness. Voxels are too expensive and brute force to scale well. The layer map can be easily turned into a heightmap for erosion simulation by just summing the thicknesses in each columns, or maybe operated on directly. I don't think true 3D terrain is that useful in most cases. Those kinds of structures tend to fall down in real life. 2.5D may be enough for most cases. The layer map can still handle caves/overhangs by adding “air” layers.

The terrain tiles I use are very small, the tiles are just 34x34 vertices (including neighbor overlap), so it won't be that expensive to do the erosion simulation for each tile. With erosion, tiles would probably need to be 64x64, to allow for 50% overlap with the neighbors. The number of tiles is not that high either. Only about 300-500 tiles need to be generated (at all LOD) to display a human-scale view of planet surface with 5cm vertex resolution and triangles of ~8 pixels in size in screen space.

I think the key to doing a global-scale erosion is to do things hierarchically, and apply erosion multiple times at each LOD scale (there are ~22 power of 2 LODs on an earth-sized planet). Then, I think you probably don't have to take very many erosion time steps at each LOD, as long as the erosion is cumulative. Hierarchy also helps to avoid boundary effects and dependencies on neighboring tiles, because we can have dependencies on parent LOD tiles, which simulate erosion across the child tile boundaries. So I think we can get a global erosion simulation by doing it at many different scales with ~50% overlap between tiles. (this is uncertain, I haven't seen any papers try to do this)

How fast this erosion simulation is in practice remains to be seen, because I haven't implemented anything yet. Currently it takes 0.1ms to generate a tile (graphics+physics+acoustic geometry), and this is fast enough to fly across the planet at km/s without lag on a single thread. I think even with 64x64 tiles a CPU erosion implementation will be probably at least 100x slower than this, depending on the number of time steps that are necessary for good results. Given the speed of GPU erosion, it's likely that that can be fast enough to work in real time, if done asynchronously. But I'd prefer to do it all on the CPU if possible.

November 02, 2022 07:13 PM
Programmer71

Its incredible what UNITY can do

November 02, 2022 11:43 PM
JoeJ

Have you seen this paper? I was planning on using a similar “layer map” type data structure to represent the 3D material distribution, stored as a 3D array of material ID + thickness.

Yes i know it, but count layered height maps as 2.5 dimensions. Mine is all MPM and SPH particle simulations (which causes a hell of issues vs. the Euler grid fluid sim approach possible with height maps).

Tbh, i think going a layered approach to support caves would slow you down for maybe too little benefit. For example, making LOD work on sphere topology is almost as easy as with height maps, but with caves you get arbitrary topology which changes with detail (holes open and close), making this a hard problem. Surface parametrization becomes harder as well. And we can even say that general solutions to those problems are literally impossible, so you may end up trying lots of hacks just to find one which feels compromised but acceptable. Procedural generation, physics, AI, all this becomes harder too. But the final game may not be much different from what you can do now already.

So i would think twice before you decide to go there, making sure your plan addresses all potential problems, and effort is acceptable. I on my side have definitively failed with being smart enough up front to do so ; )

I don't think true 3D terrain is that useful in most cases.

I think that's simply a question of offline content generation at high quality (need detail also on vertical angles), and dynamic procedural generation at runtime (3D is just way too expensive).

I think the key to doing a global-scale erosion is to do things hierarchically, and apply erosion multiple times at each LOD scale

Exactly. This is not only to get better performance, but also to get natural results. Because in nature the same processes tend to happen at all frequencies.
Iirc, i did maybe 20-50 erosion steps for the greyish hight map image per frequency, and i have used 3 or 4 frequencies.

Hierarchy also helps to avoid boundary effects and dependencies on neighboring tiles, because we can have dependencies on parent LOD tiles, which simulate erosion across the child tile boundaries.

Yeah, that's what i do as well. Basically i simulate all tiles of a parent LOD first, then blend them across some overlap, only after that go to the child level. It works.
Maybe, while upscaling to the child level, you may add a small amount if the new, higher frequency details procedurally, so that's already present and the simulation can refine it.
Regarding overlap, i currently use 1 / 32 from the length of a tile. So much less than 50%. But i also have a postprocessing step to reduce noise for the particles by enforcing poisson disk distribution and a being more flat at the surface. This also resolves seams otherwise still noticeable from the overlap blend. I lack experience with tiled heightmap simulation, but the seams seem no such big problem in general. Professional terrain tools are all tiled too.

So, confirming your plans regarding erosion.

I do some other things too, e.g. shrinking effects to provoke propagation of cracks. That's something i have not seen yet in other terrain simulators. Not present in the screenshots i've shown above, but here an example of patterns this can give:

I also do the opposite with expansion, which generates bumps and folds, e.g. like this:

I use this to generate the initial shape of the mountains for example.

How fast this erosion simulation is in practice remains to be seen, because I haven't implemented anything yet.

I assume it's totally doable, but only down to some certain size. Can be 1m, or 10m, who knows.
Below that, you could use the various scalar and vector fields used in the simulation to drive procedural generation which you already have.
So no matter how slow it is, it will work no matter what, i'm sure.

Can't wait to see somebody finally doing this, because to me it seems the obvious next step towards the procedural universe dream.
So keep us updated! :D

November 03, 2022 10:27 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement