SpaceEngine finally has volumetric planetary rings, with 3D rocks and a dust effect. I worked on volumetric rings with Duke for around half a year, with some breaks due to personal reasons. But now we are ready to release the first version of the system. Some work still needs to be done in the future to improve rings in SE, but I think the current result is good enough for public release (instructions for joining the public beta are linked at the end of this post). The method we chose – ray marching – took a long time to implement, because we encountered tons of problems. Ray marching means that there are no 3D models of rocks; they are not spawned/deleted as the camera moves through rings. Instead, the special shader on the graphics processor generates a virtual ray through each pixel of the image, and decides if there is a rock along the ray’s path on-the-fly by computing special equations. So it works like the 3D nebulae which SE already has: rocks are like opaque “clumps” of a nebula. There are no polygons, only math. Rocks are also combined with volumetric fog, can move, have textures and lighting, and receive shadows from the main planet and its satellites. Ray marching can render anything, you can see some great examples on shadertoy.com. But the main drawbacks of this method are bad performance (in many cases, and strongly dependent on image resolution), lack of hardware anti-aliasing (can be solved), and bad precision over large distances (not really a problem for most demos on Shadertoy, but is a significant problem in SE). I will describe the technical details later in this post. What does the 3D ring system in SE support for now?

Realistic scales

Rings can vary from a tiny stream of rocks around asteroids (like rings around Chariklo, and yes, SE now generates procedural rings for some cold asteroids) up to enormous ring systems several AU in diameter (like J1407 b planet, and yes, this will be used for protoplanetary rings in the future). Rocks may be as small as 1 cm in size and as large as few kilometers. The thickness of the ring system may vary from several rock sizes to hundreds of kilometers. There are some limitations though: precision may be not enough for 1 cm rocks in huge ring systems.

Differential rotation

Particles in rings rotate around their parent planet on circular orbits. According to Kepler’s third law, their linear movement speed is faster close to the planet and slower farther away. This is usually ignored in space sim games: rings are either stationary (particles do not revolve around the planet), or rotating as a solid body (all particles move at the same angular speed). In SE we tried to solve this by splitting the ring into a few thousand “subrings”, each rotating at is own rate according to Kepler’s laws. This feature reduces performance and causes visible gaps between the subrings, so we limited the number of such subrings for now. But this is much closer to reality than ring renderers seen in many other programs before now. This is important not only because SE claims to be a scientifically-accurate sim, but also important for gameplay. If you enter a ring system in a spaceship with circular orbital speed, the ring particles must be nearly stationary relative to the ship. Any other ship’s orbit will lead to a high velocity relative to ring particles, and will be deadly (when ship damage system will be implemented).

In every subring, the rocks themselves could slowly rotate around their axes and slowly drift relative to each other, but this is not implemented yet. This will certainly reduce performance, because in ray marching every calculation is repeated for every ray (pixel).

Note that if you enter rings in planetarium mode using the free camera and with time flowing, you will see rocks zip past by you very fast. This is because the free camera in SE is fixed relative to the planet’s center (in follow mode) or the planet’s surface (in rotation mode): it remains stationary, while the rings are rotating at orbital velocity. So rocks will fly past by you at many kilometers per second. You have to manually adjust your speed, or simply pause time. Another way to see (almost) static rocks or see relative motion of subrings is to spawn a ship and enter a circular orbit inside rings (quite an interesting challenge!), or go to an in-ring moon such as Daphnis or S/2009 S 1 and fly around near it. In the video below the camera is attached to S/2009 S 1 to demonstrate the differential rotation of subrings (in real time):

Lighting and texturing

Every rock has a PBR texture, normal and roughness map. These are the same textures which are used for terrain. In the future a texture set may be configured individually for every planet. PBR (physically based rendering) lighting supports up to 4 light sources and up to 8 shadow casters per light source. But this greatly affects performance, so rings have a stricter limitation on minimum light brightness than planets do. Usually the main light source is a sun (or several suns) and the parent planet itself. Some large satellites can also produce illumination. Lighting from the parent planet takes into account its phase visible from the rock’s position; this affects the view of rings near equinox a lot (look at the picture below). It also casts a shadow on the rings, which is more precise now even for the old 2D rings model as it takes into account the visible size of the sun. Shadows can be cast by the planet’s satellites and other planets in the system. Of course satellites themselves can have rings, and all this applies to their ring systems too. Shadows are volumetric, but in some cases precision issues can be visible. Lighting and shadows are not computed using emulated double-precision, because this will affect performance very badly. This is work for the future.

Dust effect and blending with 2D rings

Particles which are far away slowly disappear and fade into “dust”, like distant snowflakes in a blizzard which you cannot resolve with eyes. This dust effect has illumination which corresponds to the integral (averaged) illumination of rocks. There is also real dust in rings, which can be seen for example in Saturn’s E ring, and it has a different illumination model. At an even greater distance, volumetric rings are blended into an upgraded 2D rings model. Why? Because 2D rings have almost no performance impact, which is obviously good for distant planets and preview images in the Wiki and Solar system browser. And 3D rings can’t really overlap with the parent planet correctly, because it may have transparent layers, so the rings rendering must be split into multiple stages. In reality ring particles are extremely tiny compared to the rings size and distance to the planet, so this approach is reasonable. Of course someone will push limits in the planet editor, but you have been warned! ๐Ÿ™‚ Currently there are limitations on the thickness of the ring system, so really thick dusty rings like like the E ring of Saturn or the rings of Jupiter are not simulated properly (they look too flat).

Scripts and editor

Additional parameters were introduced to the planetary scripts to describe the new rings (and added to the planet editor). As before, the color/density profile is defined by a 1D texture, but its format may be changed soon (still working on it). Since rings are physically-based now, simple opacity in the alpha channel of the texture must be turned into optical depth. It is possible to implement multiple rings per planet in scripts, which will help save memory or increase texture resolution, because for example the fuzzy E ring of Saturn takes significant part of the texture now.

Quality/performance settings

Using ray marching for the rings produces a very heavy load for the GPU (and doesn’t load the CPU at all), so we introduced various settings to trade quality for performance.

In reality, rings are a giant flat cluster of small solid bodies rotating around a planet in its equatorial plane. By “flat” I mean really flat – Saturn’s rings have a diameter of 280,000 km (174,000 miles) and a thickness of just 10 to 30 meters (30 to 100 feet)! Since SpaceEngine is a realistic space simulator, we had to reproduce this graphically. This immediately lead to many problems, the most serious of which is precision. For example, the rings of Saturn with their huge size have a typical particle size of about 10 cm, i.e. about 3ยท10-10 of the rings size. This is below the precision limit of 32-bit floating point numbers FP32 (IEEE 754 float) that graphics cards operate on. In practice this leads to a noticeable jitter and splitting of the rock image. This is because in ray marching you don’t place a rock model at certain coordinates, you “place” every pixel of its image with limited precision. So if you have a 1080p display and want to see artifact-free rocks, you must place every pixel of the rock with enough precision, which is at least 10,000 times better than FP32 can afford. There are only two solutions for this problem. The first one is making rocks 1,000-10,000 times larger. But this is not a choice for SE as a scientifically accurate sim. Saturn’s rings doe not have 100 meter size rocks (well, it has some, but they are rare; most rocks are smaller than 10 meters). Another solution is updating some parts of the shader code to 64-bit floating point numbers (IEEE 754 double). And it works, the precision is now enough for rocks as small as 10 cm. But FP64 is extremely slow on Nvidia and AMD GPU, thanks to market segmentation: full performance with FP64 is enabled only on “professional” cards like Quadro. So for consumer hardware, we implemented FP64 emulation using two FP32 numbers. Performance is still not great, but it’s much better than using hardware FP64.

To solve this problem with performance, we are forced to reduce image resolution (the “Rings resolution” slider in the graphics settings menu). This is a common approach in many games. SpaceEngine supports rings rendering at a certain percentage of a screen resolution (from 10 to 100%) and various methods to up-scale it back. On a 4k display, even 50% looks “okay”, but at smaller display resolutions the quality must be higher. But the performance problem is still not solved: even on an Nvidia RTX 2080, 4k display at 50% scale engine gives only 30 fps. Our goal is to have 60 fps on any hardware, optimistically ๐Ÿ™‚ So another hack is used: temporal rendering (the “Fast temporal rendering” checkbox in the graphics settings). During each frame the engine updates only one pixel in a 2×2 block, alternating which pixel to update every frame. In a static scene this works amazingly well, giving a 4x speedup in rendering speed, which enables increasing the quality or resolution while keeping 60 fps. But nobody needs a static picture at 60 fps:) When moving, this temporal rendering leads to “ghosting” – trails or motion-blur-like artifacts. Some games reduce this effect using various techniques, like re-projection, but in SE those are not implemented yet. Speaking for my own taste, a small amount of ghosting is not a problem, if you move slowly relative to the rocks and have a solid 60 fps (which is the point of temporal rendering). Moving at high speeds will break immersion anyway, because nearby rocks will appear and disappear randomly. At high speeds rocks look “transparent” with temporal rendering. Unfortunately, in VR temporal rendering can’t be used, because it breaks immersion completely. So in VR we are forced to use only resolution scaling, with a more severe resolution drop than when using temporal rendering.

There are three up-scaling modes implemented: checkerboard, bi-cubic, and bi-cubic + sharpness + FXAA. This corresponds to the quality settings (the “Volumetric rings” drop-down menu in the graphics settings) of low, medium, and high respectively, which are selected automatically with the global quality/performance preset in SE (you can always switch the preset “custom” and tweak the rings settings).

The checkerboard method is a rendering technique where engine draws only two pixels in a 2×2 pattern. In SE we implemented a simple version of it; alternation in the temporal mode is done only between these two pixels. This mean that even at 100% resolution you can’t achieve a sharp image, there will always be interpolation present. But this also makes ghosting in temporal mode less noticeable than in the next two modes (because the temporal update cycle is two frames long rather than four). Anti-aliasing is also not supported, because the image is somewhat blurry even at 100% resolution.

The bi-cubic mode is the same which is used for galaxies and nebulae (yes they are also rendered at a reduced resolution – you can see the settings for them under “Volumetric objects resolution”). Image in the bi-cubic mode is sharp (per-pixel) at 100% resolution, but looks somewhat blurry at lower resolutions. The “bi-cubic + sharpness” mode solves this by applying a sharpening filer, but this emphasizes aliasing at the edges of rocks. To fix aliasing in this mode, FXAA is applied. This FXAA is independent from the global one used by SE for the full frame, it affects only ring particles.

I must explain the last option, the “Rings target resolution” drop-down menu. It was added to smoothly transit settings to high-resolution displays, and is somewhat similar to the “Landscape target resolution” option that SE already has (it was called “Landscape max resolution”, but I renamed it to make it easier to understand). For example, let’s say a user has an Nvidia RTX 2080, and has 150+ fps at 1080p screen resolution with the default “high” settings (85% resolution and temporal rendering on). But by moving on a 4k display the user will have only 45 fps. The rendering resolution must be reduced to 50% to get 60 fps. The “target resolution” feature limits the resolution not by a percentage of screen resolution, but by an absolute value. The value of “1080p” means that the rings will be rendered in 1080p resolution even if the screen screen resolution is higher. Actually, SE chooses the smaller of the two numbers – this setting and the physical screen resolution, so on smaller displays this setting is safe. The “Rings resolution” percentage is applied on top of this, so in the above example we would have 85% of 1080p, i.e. 918 lines. This is enough for 60 fps on an RTX 2080.

Known issues and limitations

There are a few issues and limitations with the new rings currently; they are still in beta, after all. Some of those issues/limitations were listed in the post above. A few additional issues to be aware of:

  • Moons orbiting inside the rings only sort correctly with the rings when looking away from the parent planet; when looking toward the planet, the moon will render in front of the rings.
  • Spacecraft do not sort with the rings at all, and always render in front of them.
  • The sunlit and unlit sides of the rings have the same brightness.
  • Transition to 2D rings may be noticeable.
  • Rocks look somewhat round, because performance limitations does not allow to use more complex shape for now.
  • By the same reason rocks does not form spindle-shaped clumps – “propellers”.
  • These issues will be improved in the future, either during the public beta or after the full release of this update.

    Spaceship thermal glow

    A much smaller but still cool-looking feature added in this update is support for blackbody thermal glow for spacecraft. This means that certain high-temperature elements of spacecraft like radiators and rocket nozzles can now be rendered with accurate color and brightness – especially in auto and manual exposure modes – rather than relying on a fake emissive color texture. This feature is a part of an upcoming ship’s thermal/energy balance simulation system.

    For instructions on how to join the beta branch of SpaceEngine, click here. Bug reports and feedback are very much appreciated!

    Full list of changes in this update:

  • Added volumetric 3D planetary rings
  • Updated exoplanet catalog (June 03, 2021)
  • Support for blackbody thermal glow and temperature maps for spaceships (accurate radiator glow appearance)
  • FXAA smooths alpha channel in screenshots and previews
  • Alpha channel is used in Solar system browser previews again
  • Separately configurable unit for star surface temperature in the interface
  • Opening the map mode while a star is selected will zoom to show its planetary system
  • Added support of DEG MIN SEC format for lat/lon in the Goto command
  • Fixed spin-orbital resonance display for hyperbolic orbits
  • Fixed bug with debris rings being very rare around gas giants
  • Fixed missing asteroid belts
  • Fixed molten comets bug
  • Fixed non-functional interpolation of variables if the duration is zero or negative
  • Discuss this post on the forum.