After spending quite some time experimenting with noise, I found myself beginning to force solutions to a single problem: projection. Much of my experimentation with noise had been in 2 dimensions, and while I was getting some very nice results, it was not entirely practical for generating a “realistic” 3 dimensional planet, at least not one you could explore to my lofty satisfaction.
I needed to figure out how I could actually generate a model for a planet at various resolutions. If the goal is to fly from space to surface, then I’d need to do some sort of uniform system for generating geometry at various scales.
The problem here is two part: First, I need some data structure to store my data, and second I need an algorithm to generate density information for my planet. Previously I was using nothing but Perlin noise to generate height information, but for a realistic planet, you effectively need a system to determine whether any given point is ‘dense’ or not. Does any given point in 3D space contain solid matter or air?
Along with this, I wanted to be able to generate data on multiple Levels of Detail. Basically, I want to generate mesh data that is finer in resolution near the player and lower resolution further from the player. After some minimal research, an Octree was my solution. An octree is basically a tree (duh) that divides space into 8 equal chunks, and can do so recursively. This means that for any position a player might be, I can find the appropriate section of space to generate around them.
The goal with this is to be able to generate data at arbitrary resolution to then turn into polygons. If the player is in space, then we only need to render a low-resolution overview of the planet, with polygons representing many kilometers. If we are actually on the planet, we should be able to see mountains and valleys and have a resolution of some meters. Ultimately, we’d like to have multiple resolutions, so the further away from the player we are, the lower resolution will be shown
This is a small debug visualization of my octree. Basically, I have here a point arbitrarily wandering through space, polling the octree for chunk data each frame. If I’ve already visited a chunk, then get a finer resolution (half the size of previous chunk in each dimension.
With this in place, I moved onto a simple rendering system for the data. Since this is a highly iterative project, I opted for simplicity and incorporated an existing voxel render for the data. The main feature I have now by combining all the parts is a system I can tell to render a chunk of a 3D world into something tangible, at arbitrary resolution. Ultimately culminating in a very blocky planet.

Note in the above gif of the system rendering, in this initial version, the chunks loaded as such: First a very very low resolution render is passed, and as each chunk renders, a higher resolution render is called, until all chunks are at a given resolution. This tech will be handy for prioritizing high-resolution closer to the player, and streaming in higher detail further away.
There are still a few fixes I want to cover here. First, the world is still very blocky. The octree works great for dividing the world into space and generating our data, but it’s not very appealing. For now, I basically just applied a function to round the whole thing. Voxels here are not cubes anymore, but the planet on a whole is round. At very high resolution (say, if you were standing on the planet), the chunk would be so small that the voxels would be almost cubic anyway.

The final improvement is speed. Up until now, I had not taken advantage of a powerful set of Unity tools: Jobs system and Burst Compiler. After implementing Jobs and Burst, there was a massive increase in performance.

That’s all I’ve got for this post. Finally with a rudimentary data structure, it’s time to explore the data model.





