Interaction with the Icosphere; Live Software Demo

This post builds on the concepts contained in “Detecting the Observation Region: The Coupled Ring Adjacency Search.”

Tying it all together

At this point in our development of the Icosphere, we can render our Abstract Icosphere. We can recurse the Icosphere uniformly and non-uniformly. Additionally, we can detect an “observation region” of configurable radius.

However, despite all of this, our Icosphere is still not interactive. In order to make it interactive and dynamic, we need to do the following:

  1. Establish a set of proximity thresholds at which the observation region will recurse.
  2. Determine a way to evenly recurse an observation region of uneven detail.

The Boundary between PISES and Unity

It is important that we stop here and define a hard line between PISES and Unity.

The Abstract Icosphere (and all of PISES’ classes) do not employ any Unity libraries. As we have mentioned many times, this is to make our eventual, hypothetical breakup with Unity clean and easy.

All of these “data system” classes have an associated class, known as a Generator, which essentially harvests the data from the abstract class and creates GameObjects and Cameras in Unity.

For AbstractIcosphere, there exists the IcosphereGenerator class. For GalacticSystem, we have GalacticSystemGenerator. SolarSystem is tied to SolarSystemGenerator.

Ultimately, there will probably be no IcosphereGenerator class; this will probably be handled by the WorldSystemGenerator which is responsible for rendering planets. But this integration has not taken place yet, so we will simply create a stand-in IcosphereGenerator.

Proximity Thresholds and Search Radii

The Icosphere we are designing here is a “proof of concept” world model. When we actually integrate this world model into PISES, there will likely be many dozens of hours spent tweaking, configuring and playing with the proximity thresholds and search radii of the icosphere. The same can be said for the player camera, the relative distances and sizes of the Icosphere, and so forth.

For now, we will simply play with a starting recursive depth of 4 and a maximum recursive depth of 10.

Our camera begins with a height of 1300 whatever-the-fucks that Unity considers to be a unit.

Our Icosphere begins with a scale of 500 whatever-the-fucks.

This means that our starting “elevation” is 800 wtfs.

From here, let us establish our recursion thresholds in IcosphereGenerator.

public class IcosphereGenerator : MonoBehaviour
{
    // The Fifth Recursion Threshold
    private const float r5Threshold = 600;

    // The Sixth Recursion Threshold
    private const float r6Threshold = 300;

    // The Seventh Recursion Threshold
    private const float r7Threshold = 150;

    // The Eighth Recursion Threshold
    private const float r8Threshold = 100;

    // The Ninth Recursion Threshold
    private const float r9Threshold = 80;

    // The Tenth Recursion Threshold
    private const float r10Threshold = 50

Additionally, let’s manipulate the search radius of our coupled ring search at each recursive threshold. This is mostly just to prove that we can. We establish the constants:

    // R4 Adjacency Search Radius
    private const int r4AdjacencySearchRadius = 15;

    // R5 Adjacency Search Radius
    private const int r5AdjacencySearchRadius = 20;

    // R6 Adjacency Search Radius
    private const int r6AdjacencySearchRadius = 25;

    // R7 Adjacency Search Radius
    private const int r7AdjacencySearchRadius = 30;

    // R8 Adjacency Search Radius
    private const int r8AdjacencySearchRadius = 35;

    // R9 Adjacency Search Radius
    private const int r9AdjacencySearchRadius = 40;

    // R10 Adjacency Search Radius
    private const int r10AdjacencySearchRadius = 50;

Now, in our update method, we can keep track of what recursive “band” we’re in.

private bool updateMesh;
private int priorDepth;
private int currentDistanceToSurface;
private int observerRecursiveDepth;

void Update()
{
    updateMesh = false;

    // Check our depth.
    currentDistanceToSurface = camera.transform.position.magnitude - scale;

    // Depth 4
    if (currentDistanceToSurface >= r5Threshold)
    {
        observerRecursiveDepth = startingRecursiveDepth;
        adjacencySearchRadius = r4AdjacencySearchRadius;
    }
    // Depth 5
    else if (currentDistanceToSurface < r5Threshold && currentDistanceToSurface >= r6Threshold)
    {
        observerRecursiveDepth = 5;
        adjacencySearchRadius = r5AdjacencySearchRadius;
    }
    // Depth 6
    else if (currentDistanceToSurface < r6Threshold && currentDistanceToSurface >= r7Threshold)
    {
        observerRecursiveDepth = 6;
        adjacencySearchRadius = r6AdjacencySearchRadius;
    }
    // Depth 7
    else if (currentDistanceToSurface < r7Threshold && currentDistanceToSurface >= r8Threshold)
    {
        observerRecursiveDepth = 7;
        adjacencySearchRadius = r7AdjacencySearchRadius;
    }
    // Depth 8
    else if (currentDistanceToSurface < r8Threshold && currentDistanceToSurface >= r9Threshold)
    {
        observerRecursiveDepth = 8;
        adjacencySearchRadius = r8AdjacencySearchRadius;
    }
    // Depth 9
    else if (currentDistanceToSurface < r9Threshold && currentDistanceToSurface >= r10Threshold)
    {
        observerRecursiveDepth = 9;
        adjacencySearchRadius = r9AdjacencySearchRadius;
    }

Now that we know what recursive “band” we are in, we know how deeply we are going to need to recurse the observationGroup.

Recursion of an Uneven region

It is possible to maneuver the camera in such a way that we can generate a region of varying recursive depth. We can then pull the camera away, zoom back in on this region, and find ourselves in the situation that we need to recurse various triangles in this region differing amounts of times.

For example, if zoom the camera in from R4 to R6, creating a region of R6 triangles, and then zoom out (back to R4) and move the camera slightly, our observation region may cover some of the generated R6 triangles, but also some R5 and R4 triangles.

When we zoom back in on this new region (say from R4 to R5), our code needs to be able to determine that R4 triangles get recursed, but not R5 and R6 triangles.

To do this, we need to calculate the “differential” between the observer’s recursive band and each triangle’s recursive depth. In our update method of IcosphereGenerator,

// Scan observation group for recursions.
foreach (int index in observationGroup)
{
    // If the triangle is of a lesser depth than the observer,
    if (icosphere.faces[index].recursiveDepth < observerRecursiveDepth)
    {
        // Determine the differential
        int differential = observerRecursiveDepth - icosphere.faces[index].recursiveDepth;
        // Recurse the face and its descendants accordingly
        icosphere.recurseSingleFaceAndDescendants(index, differential);
        // The mesh needs to be updated
        updateMesh = true;
    }
}

You will notice that this method employs a new method on AbstractIcosphere: “RecurseSingleFaceAndDescendants.”

// Recurse a single face of the icosphere, and all of its descendants for N generations.
// For example, for N=1, we will recurse the face and all of its direct descendants.
// For N=2, we will recurse the face, its direct descendants, and its "grand-descendants."
public void recurseSingleFaceAndDescendants(int index, int targetGeneration)
{
    recurseSingleFaceAndDescendants(index, 0, targetGeneration);
}

private void recurseSingleFaceAndDescendants(int index, int currentGeneration, int targetGeneration)
{

    if (currentGeneration < targetGeneration)
    {
        // Recurse this face.
        recurseSingleFace(index);

        // Recurse descendants.
        recurseSingleFaceAndDescendants(faces[index].descendant1.uniqueIndex, currentGeneration + 1, targetGeneration);
        recurseSingleFaceAndDescendants(faces[index].descendant2.uniqueIndex, currentGeneration + 1, targetGeneration);
        recurseSingleFaceAndDescendants(faces[index].descendant3.uniqueIndex, currentGeneration + 1, targetGeneration);
        recurseSingleFaceAndDescendants(faces[index].descendant4.uniqueIndex, currentGeneration + 1, targetGeneration);
    }
}

Live Software Demo

With this, we have established our proof-of-concept, asymmetrical, procedural icosphere. In this video I will provide a “live” demonstration of the software.

This video is designed for somebody who does not read this blog, so there will be some review.

The next steps will be to begin integrating this abstract icosphere into PISES at large, and to determine how best to generate geometric planetary data from PISES’ abstract worlds.

2 thoughts on “Interaction with the Icosphere; Live Software Demo

    1. Hey Doug –

      In scientific or mathematical writings, using “we” and “our” instead of passive voice is very common.

      There is technically no “we” on this project right now, just me! But using “we” and “our” is something that was very reinforced for me in my technical writing courses throughout school. It was actually most strongly emphasized in my discrete mathematics courses, when writing proofs!

      In my day job as well, many of our white papers and documentation are written in this style. So it’s become a bit of a habit!

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s