This post builds on the concepts outlined through out the previous Icospherical World Model posts.
Hello everyone! It’s been a while since my last post (four months)! Life has been pretty wild with the pandemic, and I have had a lot of music work going on. In addition to this, I’ve been applying to grad school for physics! However, I have been continuing work on PISES and also forking its icosphere for use on other projects.
Recursing the Observation Region
In the last technical post about the Icosphere, we designed and employed a Coupled Ring Search to detect the observation region. This is the region that we will break down into descendant triangles when the observer draws near enough – and eventually, pack back up into ancestor triangles when the observer retreats far enough.
Aside: Increasing Unity’s Vertex Limit
By default, Unity’s Mesh Index Buffer only supports 65,535 vertices. For almost all ostensible purposes, there is no reason to increase this buffer size. In fact, once we work out repacking (packing up descendant triangles into their ancestors), we will not need this limit increased. However, in the interim, to avoid weird behavior and drop-outs, I suggest increasing this Mesh Index Buffer to 32 bits, increasing our vertex limit to about 4 billion. This is easily achieved at program start:
When approaching and retreating from the icosphere, we will need to establish a set of altitudes at which to:
- On Descent, decompose the observation group into descendant triangles.
- On Ascent, recombine the observation group into their parent triangles.
Additionally, our adjacency search radius needs to adapt, shrinking and expanding based on altitude.
The following thresholds I have arrived at simply by experimentation – what “feels good” when I’m running the icosphere. They could be changed or tailored based on need.
It should also be noted that for PISES, these thresholds will need to be dynamically generated for planets of varying radius. That, or all planets can be transposed to 1 Earth-Radius for the sake of their icospherical exploration (this has some consequences, more on that later). In this example, these constants are based on an icosphere being used for an Earth-model, for a different project. In any case, whether they are statically determined or dynamically produced, we need a set of thresholds.
In our Update() method, we will need to continuously track the recursive depth of the observer.
Note that “scale” here has been set to EARTH_RADIUS_KM in the Awake() method.
Now that we know the observer’s depth, we can check to make sure that all observed Triangles are of the correct depth. If they’re not, we will call a new method on AbstractIcosphere : “recurseSingleFaceAndDescendants().”
If you are wondering how the Observation Group was determined, please refer to the post, “Detecting the Observation Region: The Coupled Ring Adjacency Search.”
Recursion of a Single Face and Descendants
Now that we know exactly which triangles need to be recursed, and by how much, we can get into the technical grit of breaking down the faces of our icosphere. This process we have actually already covered, in the post: “Recursion of the Icosphere and Maintaining Adjacency.” There are just two differences now:
- This time, we have an entire Observation Group to recurse.
- With the interest of being able to repack this icosphere, we now need to perform some checks before recursing to make sure that there aren’t already descendants. This could be possible if we start at recursive depth A, descend to depth B, triggering descendants, retreat to depth A, packing up those descendants, and then descending once again to depth B. If we don’t check for the presence of descendants, we could create duplicate Triangles and all hell would break loose.
With this being said, here is our updated “recurseSingleFace()” method, and its recursive caller, “recurseSingleFaceAndDescendants().“
At this point, we can descend the icosphere, recursing triangles as we go. Now, we need to be able to get back out and repack triangles in our wake.
Ascending the Icosphere
As it turns out, we have already done pretty much all of the work we need in order to cleanly ascend and repack the icosphere. All of our triangles have knowledge of their parents and descendants – and all of our triangles have a ‘visible’ flag, meaning we can simply switch them on and off. When it’s time to constitute our mesh for Unity, we can harvest only the visible triangles and neglect the invisible ones – they’ll remain in the Abstract Icosphere, simply not rendered.
First, we check for an ascension event.
Second, we scan all triangles in the icosphere for those that are below the current recursive depth. The reason we must scan the entire icosphere is because we may have triggered a recursion event in one region, and then panned to another, while remaining at the same depth, such that the first triangles we recursed are no longer in the observation group, but still need to be packed up on ascent.
A way to streamline this in the future would be to immediately repack anything not inside the observation region – but this has some complicated folds, and we’ll save it for another time.
For now, we scan the icosphere for triangles below the observer’s depth. We set them, and their adjacencies of matching depth, to invisible.
Then, we climb up the quad tree to find their parent triangle at the target depth. We set this to visible.
Updating the Mesh
Last, we must update the physical mesh in unity. Throughout this entire process, you will notice that for recursion or ascension events, we have been toggling a flag, ‘updateMesh.’ It simply activates this block at the end of the update() method:
The methods “HarvestMeshData()” and “CreateMesh()” are explained in detail in the post, “Rendering the Static Icosphere in Unity Gaming Engine.”
See the repacking icosphere in realtime action at the link below.