This project was a try to generate a complete stellar system with voxels, cube shaped planets and asteroid fields. I have developed multiple editors to create presets for biome, planet and stellar system generation (you can see them above) but i will not talk about that in this showcase. I will talk about the systems i've created to solve some problematics relative to the size of the map and the creation of cubic planets.
This was the biggest problem in the project because as you know (or not) in unity you are limited in term of size for a map.
If we decide that 1m is 1 unit in unity, then after ~50km unity begin to loose in precision and the game begin to have little problems like GUI shake and other weirds things. Just for information, if you go further you will face serious Physic and lighting problem which make the game unplayable.
So right now i have ~100Km to create a complete stellar system, this could be enough if you plan to create "little" planets of ~1Km of diameter but for me it's far from enough.
I decided then to create a new Position system with a custom class called "StellarPosition" which store position with an integer and a float for each axis. The integer will be used to tell on which block of space (i called them StellarChunks) we are and the float is used to tell the position in this block. With this system we have 429496729500 km (2871 Astronomical unit) to create our stellar system (which is already 28 times the size of our solar system) and if it's not enough you can just decide to use a long to store the StellarChunk index so you can have 194982238 light years (more than 1083 times the size of our galaxy !) of space to place your objects.
So with this amazing position system we can place planets and other stellar objects anywhere we want but there is still a problem and this is about transforming StellarPosition in Vector3 because unity can't understand our positioning system. Here i choose to use a bounding box of the size of my StellarChunk placed at the origin and if the player cross a face of the box, it is teleported to the opposite face and the entire world too. Well i assume this is a bit harsh but unity support it very well, if you move just the parent of all your loaded objects there is no problem.
This conclude the first part and with a bit more of math you will be able to integrate this in your projects if you need a (very) big map.
Seamless cubic world ?
It was also a big issue, have you already tried to map a 2D noise on a cube ? well this is nearly impossible without getting some weird distortions that's why i decided to use 3D noise to generate my terrains !
Using 3D noise have also one more advantage: it can generate a more complex terrain adding cliffs, arches or floating blobs of terrain at the cost of some performances but i think it's worth.
So basically to generate a simple terrain over a 2D map with 3D noise you just need two things: a 3D noise function (i choose perlin noise) and a density curve to create a transition between the underground and the atmosphere. This curve is really important because it will shape your terrain and create different landscape and biomes to have more complexity on your planets. To generate this same terrain on a cube, this is exactly the same technique, you just have to apply the density curve in the direction of the face of the cube and amplify it on the edges if you want to avoid strange-looking mountains. With this base you can now start to create a more complex procedural generation with biomes using, for example temperature / wetness to create climatic zones.
Floating island and asteroid belts
Here come the fun part, it's time to play with noise functions and create some new objects to fill up our system !
First, to create floating islands like you can see in the first two pictures of this showcase i just used one 3D noise and a 3D mask function, this technique works pretty well and is fully explained here: codeflow. The process is pretty simple: first you have a 3D noise (perlin noise for example) which fill up your space and create random blob of terrain everywhere and then, to control the shape and the position of your islands, you apply a function that will generate a density for any given coordinate. For this project i used a spherical density function which return 1 when you are near of the center of the island and tends to 0 when you move away.
Once you have this system, you can play with the settings of you noise, for example the first picture of the showcase use the same noise than the second but with more lacunarity so the terrain looks more detailed. By adjusting you mask function, you can create any kind of floating island like square/torus shaped island, you can even affect the y coordinate of your mask function so it create higher island, the only limit here is your imagination :)
For asteroid fields and belts, it's nearly the same technique but instead of generate one island you generate a field of islands. The only thing to change is our mask function and there is several options for this, i will expose two of them:
The Worley noise, with good settings it can generate a mask, the size of each cell vary and the spacing can be configured furthermore it's fast to implement. But there is some problems with this noise: firstly this noise is heavy in terms of computing and can have a large impact on the speed of your generation and secondly you can't without tricking the algorithm generate random shapes on each points so all your masks gonna be spherical.
Handmade solution ! this require more code than the Worley noise but it's faster and more configurable. This implementation use blue noise to prevent your asteroids from overlapping each others and then apply a standard mask function like for the floating island. The only thing to do is pregenerate "random" points, store them cleverly (using an octree or an R-tree) and then generate your asteroids where they need to be. simple clear and efficient !
Here is a little bonus about how i rendered the map, i think it was interesting to add it because i've tried some things before to get this map working with this amount of stellar systems. In the galaxy map there is ~70000 system each represented by the icon of the pivot object (dwarf / giant / supergiant / sun like ...) which means ~70000 images to display at the screen without any lags / memory overhead.
The first thing i try is to render them using the unity's UI component Image but as you imagine unity does not like the 70k components on gameobjects in the UI and the game was unplayable even when the map was disabled.
The second try, i generate a mesh with the position of all stellar systems and placing the UVs of each icon (all my icons where stored in an atlas) on the good quad of my mesh. It took me 3 meshes of ~64k vertices to create the full map but it works really well, associated with a ScrollRect component to move around with the mouse and a custom script to zoom in, the map was completed !
There is another similar solution that i did not explore: use a custom shader to create a preview for each stellar systems of the mesh, the advantage of this technique is that if we continue to zoom in a stellar system icon, no ugly big pixels appears and the image is still clear. I think it could also be a good solution if you dont want to create icons :)
This is everything for the post, i hope you enjoyed it and learned some things about the creation of a stellar system in unity.
See you later on another post !