Sunday, January 4, 2015

Procedural Universe and Planet Generation and Rendering

It's time to introduce the "universe" mode of 3DWorld, which is quite a bit different from the other "terrain" modes. This mode doesn't share too much of the high-level classes, functions, and control flow with the rest of 3DWorld, but it does share a lot of the low-level infrastructure. It can also be used to draw a real, animated nighttime starfield (with planets, moons, rings, etc.) in the background of terrain mode.

Universe Objects
There are two classes of objects in universe mode: procedural, natural universe objects and dynamic, manufactured objects such as space ships, their projectiles, and their particles. The procedural universe objects are generated in a hierarchy of cell -> galaxy -> solar system (with star) -> planet -> moon. Each cell contains several galaxies and is identified by 32-bit integers for {x, y, z} grid positions, so the universe is effectively a 3D grid of 2^32 cells, and contains some 2^98 galaxies. I call that universe infinite - in fact any procedural world where you can move at max speed in the same direction for a lifetime without reaching the end is more of less infinite in size. The objects in the universe have compressed scales so that you're not flying for hours in empty space to get from one planet to another, or one star to another. Even with the compression, there are still issues with floating-point precision, so I had to use custom float + int coordinates in some places, and double precision in others.

The universe contains the following physical objects at various levels of the hierarchy:
  • Stars (one per system, up to 500 per galaxy)
  • Nebulae (one or more per galaxy) - volumetric with 3D ridged perlin noise
  • Asteroid fields (multiple per galaxy, either inside or outside of a system)
  • Asteroid belts (in some systems and around some planets)
  • Planets (up to 15 per system)
  • Moons (up to 8 per planet)
  • Comets (spawned near the player, out of view)
Everything is procedurally generated, more or less from scratch. Since the player can travel between star systems in a fraction of a second in hyperspeed, everything needs to be generated within a single frame. In the end I had to move almost all the generation and rendering into large shaders up to 600 lines of GLSL code. So far I haven't been able to find any other online tool/product/demo that draws an entire planet from scratch using a single shader in a single pass. Well, it's not exactly a single shader - I have a shader generation framework that takes bits and pieces of GLSL code and combines them together to create a shader customized for the particular class of planet, moon, etc. being rendered. So it's one shader/pass per planet, but different shaders for each type of planet or moon. The types of planet that 3DWorld supports consist of:
  • Terran/Earth-like: Procedural ground/vegetation color, normal map, water, snow/ice coverage, clouds with shadows, and atmosphere
  • Alien: Colorful terrain, toxic clouds and atmosphere with shadows
  • Ocean/Water: Clouds and atmosphere
  • Ice: Gas clouds/atmosphere
  • Rocky: Procedural height generation in vertex shader, normal maps at multiple octaves, shadows
  • Hot/Lava: Lava instead of water, possible toxic atmosphere, normal maps, colored
  • Gas Giants: Multiple layers of procedural clouds, perturbed 1D color bands, animated procedural cyclone storms, soft cloud shadows
  • Moon: with procedural heightmap and craters generated within the shader using normal maps
Each planet can also have rings that cast and receive proper analytical soft shadows, asteroid belts, and one or more moons that revolve around it. All objects rotate and revolve according to the laws of planetary physics. In addition, each object is given a unique generated name.

In addition to creation and rendering, 3DWorld provides a framework for physics simulation, collision detection, and modification of the universe. There are query functions for gravity, temperature, and lighting at any point in the universe. 3DWorld supports efficient object line intersection tests, sphere intersection tests, nearest object queries, future collision queries, and other functions necessary for interacting with the universe. Objects can be destroyed and renamed by the player, and modifications can be saved to disk and reloaded in future sessions.

Here are some screenshots of planets and other universe objects, all procedurally generated and rendered with custom shaders. There are no predefined textures used, all planets are unique, and I'm getting framerates of hundreds of FPS. Note that the planets are closer together than they would be in reality, to make the scene look more interesting with multiple planets in view at the same time.

Volumetric procedural nebula that the player can fly through, using 3D ridged perlin noise. Each one is unique.

Star with asteroid belt and nearby planets, with stars, galaxies, and nebulae in the background.

Closeup of system asteroid belt with 10K large rotating asteroids (perturbed spheres with hardware instancing and LOD) and 1M small asteroids (point sprites). All asteroids rotate around the star, and can be collided with, selected, and destroyed.

Gas giant with swirling animated clouds, animated storm cyclones, cloud shadows, lightning, rings with animated asteroids and particles, soft shadows to/from planet <=> rings, and indirect moon lighting.

Terran planet with procedural terrain (8 octave 3D ridged noise multifractal), normal mapping, snow covered mountains, ice at poles, animated swirly clouds with shadows, specular snow, ice, and water, and atmosphere.
Icy planet near the asteroid belt with some snowy peaks and green forested areas. Note the moon in the back left.

Planet with clouds, toxic atmosphere, and emissive lava glow (black body radiation). You can also see a distant comet in the upper right corner.

Rocky ice planet with nearby asteroids. The vertices are perturbed by evaluating noise in the vertex shader. All planets of this type use a constant/shared VBO of initial sphere vertices.

In the other category we have artificially created objects consisting of:
  • Space Ships
  • Starbases
  • Planetary Colonies
  • Projectiles (missiles, etc.)
  • Particles and Particle Effects
  • Explosions
This is the space gameplay part of universe mode, where the player engages in colonization and fleet combat with one or more AI-controlled sides. All of these objects are either initially placed in the config file, randomly spawned, created by the player, or created by an AI. We start with the ships, which can create other ships, colonies, projectiles, and particles. All of these objects can interact with universe objects (stars, planets, moons, etc.) and with each other. I'll make a later post with more ship details and screenshots.

Video Update

Here is a procedural universe fly-through recorded by 3DWorld. I fly my ship away from the battle, past a planet, into the asteroid belt, past the star, to a ringed gas giant, back and forth through a nebula, and back into a system to view a planet up close.

YouTube Video Link

At one point I fly my ship into an asteroid and bounce off, which shows how physics and collision detection work with every solid object in the universe. I also get too close to the star at one point and start taking damage, which is why the screen turns red and shakes. (I have the health bar and other UI elements turned off to reduce screen clutter.) The nebula is procedural, which allows the player ship to fly though it. All planets, including the gas giant and Terran planets in the video, are entirely generated and drawn on the GPU. I'm only sending a low-resolution, untextured sphere to the GPU for tessellation and rendering. Everything is generated seamlessly with no visible LOD transitions and no loading screens.


  1. Nice work! Do you happen to have a video of any of those? I would love to see how does it look like when player gets into the nebula

    1. There you go, I added a video. Back when I originally wrote this post I couldn't record videos longer than 10 seconds, but that problem has been resolved. Sorry, no sound. Thanks!