3D render order

Constellations should always be behind the stars

Here is the link to the 3D tool: https://sternenhimmel-der-menschheit.de/explore

The scene contains a lot of elements. To make sure they all display properly, it is necessary to manage the order in which they are rendered. This problem appeared very quickly with the stars overlapping the constellations. I first solved this by changing the blending mode of the constellations so that the stars could always be seen through them. This ended up not properly working out because the constellations became white where they overlap each other.

I then found out that Three.js gives the option to specify the renderOrder property, to decide which element gets rendered on top of which (much like the z-index in CSS). I therefore put the renderOrder settings for the constellation to -1000 so that everything else gets rendered on top of them.

The star labels are on top of the entire scene, but this was not difficult to achieve, since, as regular HTML elements, they are rendered in a different layer.

Later, the constellation’s renderOrder property had to become more precise to decide which one gets rendered on top. Indeed, there was some constellation overlapping each other from the start, but it never mattered much, since the texture is a transparent PNG. So even if multiple constellations overlap, it’s always possible to see all of them. However, the new cultures had constellations where this was not desirable: some constellations’ parts should now be hidden under other ones.

One solution for this is to simply erase the part of the constellation which should be hidden. However, this technique has some major disadvantages, since it’s not possible to see how the constellations overlap before putting them together in the 3D scene. Going back and forth between the 3D scene and software (like Photoshop) to update the 2D texture would be very time-consuming and any mistake would be obvious to the user. To make it worse, the 3D mesh of the constellations sometimes needs an update because their placement relative to the stars is inaccurate. This can produce a domino effect, which means that when one constellation is updated, all of the ones it overlapped (and their texture) need to be updated.

The second solution I found is to add a black background to the constellations which is used to hide the ones underneath them. The constellations with this black background then get a higher number for their renderOrder property, and successfully hide the others. This proved to be the right decision later when the highlight feature was added. If the texture images had been cropped, it would have shown when they’re being highlighted.

This was also needed for hidden constellations which get highlighted only when they're clicked in the story. If the other textures had been cropped to leave space for them, it would have left a permanent hole in the sky, for no apparent reason.

The renderOrder also plays a role in deciding which constellation gets highlighted. Indeed, while moving the cursor around the 3D scene, a raycaster is used to know which 3D meshes are currently intersecting with the cursor position. Out of the list of intersecting objects, the constellations that should be hidden (which are special ones, only visible when the user clicks an interactive element mentioning them in the story) get filtered out, and the one with the highest renderOrder is selected. This is useful since some constellations are entirely covered by others. So the smallest constellations get a higher renderOrder to make sure that it’s easy to highlight them (or click on them to center them).

Later, we added the Milky Way to the scene. This caused issues since the Milky Way should be displayed below everything else, but by doing so, the black background of the constellations became obvious. I ended up adding it on top of the constellations, but with a blending mode that makes it possible to see the constellations through it (THREE.AdditiveBlending).