The Issue of Scale

Problem

One of the most challenging issues in the Solar Scope is the issue of scale. On one hand, we want PISES to represent the realistic scales and distances between celestial objects – but on the other hand, we need PISES’ views to be intuitive, tractable and visually appealing.

It turns out, unfortunately, that there is really no way to have all of these experiences in totality. It is certainly possible to render all of the objects in a solar system at true scale and at true distance, but this will unfortunately leave almost everything besides the solar system’s suns invisible. Much like our own night sky, when we gaze out with our naked eye across the plane of the solar system, only the nearest and largest worlds are visible – and at that, they are mere points of light in the sky, unrecognizable even as planets to most people.

At the same time, scaling up the radii of the planets and suns begins to pose challenges of its own. Simply scaling up all planets’ radii by the same uniform value, as it turns out, still won’t do the trick: in order to bring the smallest planetoids and moons into visibility, we would have to magnify them by a multiple of many thousands, which would cause large worlds like Gas Giants to grow preposterously, cartoonishly large.

The scaling approach in PISES is a work-in-progress, mostly because I’m not even sure what the best approach even is. Currently in place is a system that is a hybrid of true-scale and “symbolic-scaling.” However, the scales of the suns, planets and moons in the solar system view are all manually configurable, depending on what the user is looking for at the particular moment of use. Additionally, PISES employs an Autoscaling system, which quietly and subtly inflates or shrinks celestial bodies depending on how far the observer is from them. In this post, I’ll explain these stages of scaling and how they work.

Step 1: Initializing the Solar System at True Scale

From AU to UU

In PISES, for better or worse, the standard unit of distance in the Solar Scope is AU. When I started PISES in college, AU seemed as good a unit as any – now, later, I wonder if it would have been better to go with something more ubiquitous, such as kilometers, but converting between these units is easy enough.

A decision must be made about the relationship between AU to UU (“Unity Units”). As far as I can tell, a Unity Unit is equivalent to a meter (using Unity’s physics engines, objects will fall at 9.8 UU/s^2), but PISES does not employ any of Unity’s physics engines, so this doesn’t matter.

Creating scenes that are too small in Unity can cause very strange issues with movement. Initially, having set the scale at 1AU : 1UU, it was common to see erratic behavior in the propagation of planets that, for all intents and purposes, should not have been there. I eventually settled on a scale of 1AU : 10UU, and these issues seem to have gone away.

As of right now, I am not quite sure what the “best” size is to render solar systems. For this reason, PISES contains a “Conversions” class, which has a static constant, AU_TO_UU, which all other classes reference. So, if one day I discover that an optimal scaling is something more like 1AU = 100UU, it should be as simple as changing this constant. Eventually, it will be worth the time to do some performance profiling and analysis to see if there is a best AU:UU ratio.

Determination of Radius and Position

Much like the relationship between the SolarSystemFrame and the Solar System objects, a WorldSystem extends the WorldSystemFrame, which is an object that contains just enough information about the world as is required to render it in the Solar System Scope. When descending to the surface of the world, we build out its fully described WorldSystemFrame.

What the WorldSystemFrame does contain includes both a world’s radius and its OrbitalSystem. To determine the world’s radius in UU, we must convert its radius to AU and then from AU to UU. This is straightforward enough.

Determining a starting position for the world is a little bit more arbitrary. Remember, the OrbitalSystem does not actually contain a planet’s explicit position; only the Keplerian elements which describe its orbital ellipse. Remember also that after we select a starting position for a planet or a star, it’s going to start moving (propagating). So, all we really need to do here is pick some arbitrary, random mean anomaly (angle) at which the planet or star should begin. Then, using our orbital elements, we can mathematically work out where, in AU, that position is in the solar system. We then convert to UU and instantiate the star or planet.

Caveat: any bodies in a binary orbit must have opposing anomalies. See ‘Generating Opposing Binary Orbits’ in this previous post.

After choosing this starting position, the worlds will begin propagating: see the related post on the propagator.

Aside: The Interaction of Orbits Without Knowledge of Anomaly

This random, arbitrary determination of starting anomaly poses an important question. If PISES is a simulator, and simulates the development of solar systems, beginning with their primordial state and continuing throughout their lifespan, shouldn’t PISES be modeling the interaction of orbits? Surely, as worlds migrate in their orbits, over time planets in similar orbital regimes might interact with one another, resulting in collisions, expulsions, moon systems, rings, or even binary planet systems. By selecting a random starting anomaly when a user enters a solar system, aren’t we basically declaring that there is no propagation transpiring in this solar system at any point in history, until now?

The answer is, of course, yes: PISES does not work out any ‘orbital history’ for a solar system – propagating planets, even in a super idealized environment like PISES, is hard work. Rolling back and propagating all of the planets of a solar system for millions of years and simulating interactions between worlds would take, well, pretty much forever.

However, what we can do is compare the orbital elements of adjacent worlds in a solar system and find not their closest approach (because without an anomaly there is no such thing) but their Minimum Orbit Intersect Distance. This is the closest point between the two orbital ellipses where, hypothetically, if their starting anomalies provided for it, the two worlds might draw nearest to one another.

MOID calculations are often used to evaluate collision risks between the Earth and astronomical objects like comets, asteroids, and other NEOs (Near Earth Objects).

What PISES then does is, by using its knowledge of two planets’ MOIDs and their respective masses, come up with a probability of interaction which it can then impose on these two planets every epoch (which, at the solar scope, is about once per million years). Every MY, these two worlds will have a chance to interact. These interactions can include capture (eg. Jupiter capturing a planetesimal as a moon), collision (eg. the primordial impact between the earth and a Mars-sized object which created the moon), expulsion (eg. a rogue planet careening through the infinite lightless space in between stars for eternity), or a union (eg. a binary planet system, like pluto and charon).

How PISES determines the MOID, and uses it as well as the planetary masses to decide what the probability of interaction is and what the interaction should be if it takes place, is a detailed enough process that it deserves its own post. Keep an eye out in the future!

Step 2: Ranging of Planetary Radii

Minimum and Maximum Planetary Radii

Planets and Moons in PISES span in radius from .01 ER (Earth Radius) to 20 ER. This incredibly vast range makes it unhelpful to scale all worlds uniformly. That is, if a user wants to see all of the moons orbiting a gas giant, and scales them by x1000 in order to do so, we cannot also scale the gas giant x1000, because its expanded radius would literally envelop the moons in question.

Moreover, even if the user wanted to expand a world like Earth, with 1ER, x100 to get a better view, expanding a Jovian world of 20ER x100 would make it cartoonishly, obnoxiously large in the solar view.

For this reason, it seems helpful to apply an absolute maximum and minimum radius to all worlds of the solar system, so that no worlds exceed the max radius, even when the user ratchets up the scaling, and no worlds exceed the min radius (thus vanishing completely from view), even when the user sets the scaling to x1.

Of course, applying a maximum and minimum radius comes at a cost: we are taking a step away from ‘total realism.’ It will be possible now to set the scaling parameters such that we see worlds rendered in disproportionate sizes. In fact, almost always there will be some planet or moon in the solar system banging up against a minimum or maximum radius. Like mentioned in the problem statement above, this is the cost of an intuitive, tractable and visually appealing display. Essentially, we are trying to find the sweet medium between a child’s solar system mobile display – which lets the child know that Jupiter is, indeed, bigger than Saturn (by a little bit) and bigger than Earth (by a lot) – and a real astronomical representation.

The true radius of the world is of course always on display in the planetary data, available to the user.

Right now in PISES, the maximum and minimum radii for planets is set to 6 ER and .5 ER, respectively. The maximum and minimum radii for moons is set from .05ER – .5 ER. These are configurable values that I am playing with all the time – maybe they should even be exposed to the user eventually.

A Linear Range is Not Enough

A problem arises when imposing the absolute minimum and maximum radii. Should two large planets fall above the maximum radii, we still want to express that one is indeed larger than the other. If we cap them both at the maximum, they would appear to be the same size, even if one was vastly larger than the other.

Eventually, I’d like to create a system that ‘rolls off’ on scaling as a planet’s size approaches the minimum and maximum radii. That is, for planets near the median of this range, their scales are unchanged – but as a radius approaches the maximum, it is downscaled logarithmically instead of just getting capped at the maximum. This is a future endeavor.

Step 3: Manual Scaling

Now that we have instantiated worlds with their true radii, but with constrained minimums and maximums, we are ready to open up control of additional scaling to the user. The scaling panel currently exposes the following controls:

Solar Scaling multiplies the radius of stars.
Planetary Scaling multiplies the radius of all planetary bodies, including moons.
Lunar Scaling is an additional multiplier that is applied to only lunar bodies.

The minimum and maximum scalings shown here are all values that I am constantly changing and honing in on what feels good and looks good. These values feel okay and look okay, at the moment.

Step 4: Autoscaling in Unity

Lastly, after ranging our worlds, and after applying manual scaling, the final step is autoscaling.

The idea behind autoscaling is that the farther away the observer is from a world, the larger we want it to be (so that it maintains visibility). However, when the observer gets in close, we want the world to become closer to its true (manually scaled) size.

Ideally, the effect of autoscaling should be subtle to the point that the user doesn’t really notice it. Getting this level of subtlety took quite a bit of tweaking and experiment, but it actually worked out very gracefully in the end.

The practice of autoscaling can be used for all sorts of Unity games and applications outside of PISES.

The autoscaling process explains itself best in the form of code.

// This is the most we will ever upscale a planet during autoscaling.
private float PLANETARY_AUTOSCALING_MAXIMUM = 3.5f;

// This is the radius, in UU, at which and under which the autoscaling multiplier will be and remain 1. 
private float PLANETARY_AUTOSCALING_INNER_RADIUS_UU = 5;

// This is the radius, in UU, at which and over which the autoscaling multipler will be the PLANETARY_AUTOSCALING_MAXIMUM.
private float PLANETARY_AUTOSCALING_OUTER_RADIUS_UU = 250;

private void AutoscalePlanets()
{
    // planetObjectToUnitySize is a collection of the GameObjects representing WorldSystemFrames and their associated radii in UU, after 'ranging.'
    foreach (KeyValuePair<GameObject, float> entry in planetObjectToUnitySize)
    {
        // Determine distance to planet. 
        float distance = Vector3.Distance(camera.transform.position, entry.Key.transform.position);

        // Check to see if we are in autoscaling range.
        // If outside of range, continue.
        if (distance > PLANETARY_AUTOSCALING_OUTER_RADIUS_UU || distance < PLANETARY_AUTOSCALING_INNER_RADIUS_UU)
        {continue;}

        // Determine the distance between the inner and outer autoscaling radii
        float range = (distance - PLANETARY_AUTOSCALING_INNER_RADIUS_UU) 
            / (PLANETARY_AUTOSCALING_OUTER_RADIUS_UU - PLANETARY_AUTOSCALING_INNER_RADIUS_UU);

        // Apply the position on this range to the range [1, PLANETARY_AUTOSCALING_MAXIMUM]
        float multiplier = range * (PLANETARY_AUTOSCALING_MAXIMUM - 1) + 1; 

        // Calculate the radius. 
        float radius = entry.Value * multiplier;

        // change the local scale of the GameObject.
        entry.Key.transform.localScale = new Vector3(radius, radius, radius);
    }
}

Autoscaling is a feature that many people might prefer to go without – and for that reason, it can be toggled on the scaling control panel (see the screenshot above).

Keeping Track of Scale in Code

There are a lot of different ‘scales’ now associated with planets. In order for this all to work, we must always maintain track of:

  1. A planet’s actual radius, in AU. This can be found on the WorldSystemFrame.
  2. A mapping of representative GameObjects to their WorldSystemFrames:
    Dictionary<GameObject, WorldSystemFrame> gameObjectToWorldSystem;
  3. A mapping of Planet Objects to their ranged unity radii, to be used as a basis for phase 3 manual scaling.
    Dictionary<GameObject, float> planetObjectToUnityRadius;
  4. A mapping of Planet Objects to their scaled unity radii, to be used as a basis for phase 4 autoscaling.
    Dictionary<GameObject, float> planetObjectToScaledUnityRadius;

Scaling Examples

Let’s take a look at how this all turns out in the end.

First: A G-I gas giant with a super-inclined lunar plane, with the following scaling values:
> Solar Scaling: x17
> Planetary Scaling: x350
> Lunar Scaling: x350 x600

I think it looks pretty damn cool

Second: An A-type main sequence star with two very distant, lonely worlds. The nearest world bears a single moon.
> Solar Scaling: x100
> Planetary Scaling: x375
> Lunar Scaling: x375 x600

Note how drastically larger the solar scaling is in this image to get a grip on how much larger this solar system is than the last one.

Third: A G-type, M-type binary pair with seven worlds between the two of them. A point of special interest lies in the CHZ of the G-type.
> Solar Scaling: x30
> Planetary Scaling: x200
> Lunar Scaling: x200 x600

We’re not alone in this solar system.

Fourth: Zoomed in on the G-type of the previous system, we get a closer look at the Type III Gas Giant, Inside the CHZ with 59 moons! Holy cow! That means 60 very good opportunities for life to form independently all within .5 AU of one another! This is an extraordinary example of a good place to search for life in PISES.
> Solar Scaling: x15
> Planetary Scaling: x100
> Lunar Scaling: x100 x600

The stories practically write themselves.

Moving Forward

As PISES continues to grow and evolve, I’m sure that its scaling systems will also continue to change and mature with the software. As we’ve mentioned a few times: there is no one-size-fits-all solution to solar system scaling, and every option comes with its share of mess. There is a constant compromise taking place between intuitive, symbolic scaling and true-scaling. Hopefully, by allowing the user many different windows into the scaling configuration, it will be possible for them to tailor the scaling to their exact needs.

One thought on “The Issue of Scale

  1. Your approach to solar system scaling is very different from how I handle it in 3DWorld. I scale everything by sort of taking the square root of the real sizes and distances of planets, moons, and stars. This makes them all appear larger and closer together while keeping their relative sizes in the correct order. Rather than a planet being 100x smaller than the star, it’s only 10x, etc. This also helps to avoid problems with large scale differences.

    But I use other trickery to somewhat offset this and make them appear larger and more distant to the player when flying around. The player and AI ship speed is capped based on the distance to the closest solar system body. This means that your ship slows down when approaching a planet, making it appear larger than it really is. It’s all visual trickery. If I draw a background of landscape or buildings for reference, it’s comical how close together everything actually is!

    Liked by 1 person

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