Faking Relativity

5 hours ago 2

Normally in space games, some kind of FTL method is needed for the players to get around quickly. Here, I present an alternative, based on a concept from Special Relativity.

A ship in a dark void Travelling at 0.99981 c in my hobby project. Click for full res.
The ship has slowed down Travelling at 0.9932 c
The ship has slowed down further Travelling at 0.84 c

# Motivation

# Why space games normally use FTL

If you’re making a game that takes place in multiple star systems, the player has to be able to get from place to place in less time than waiting one (or more) real life years for every lightyear of distance they need to travel. The same problem exists even on the interplanetary scale - the distance to the outer planets like Neptune is measured in light hours.

In linear media, like books, games, TV/movies, and story-driven games, FTL can be avoided by using timeskips instead. But for interactive, sandbox-based games, this isn’t really an option.

I wanted an alternative.

# FTL is time travel

This is described by the "Tachyonic Antitelephone" thought experiment.

https://en.wikipedia.org/wiki/Tachyonic_antitelephone#Numerical_example_with_two-way_communication

I always thought that maybe if you formulated it the right way, the causal reordering of relativity would just be a kind of "mirage" caused by the light lag. That if you were omniscient and omnipresent, with instantaneous knowledge of all reference frames, with knowledge of the "one true reference frame", you could reconstruct a canonical ordering of events that did not involve broken causality. This is not the case. The thought experiment shows why.

So any kind of FTL method in scifi kind of has to sweep this under the rug. Ignore the fact that your warp drive is also a literal time machine.

I know that you can just do this. It’s all fiction after all. But I want to have as much sci in my fi as possible.

# Ultra-relativistic travel just looks cool

Ultra-relativistic travel, close to the speed of light, causes all of the light you receive to be bunched up into the forward direction. It also causes light to be redshifted or blueshifted depending on the travel direction. There are a few different effects involved:

  • The position of stars will be bunched towards the forward travel direction.
  • Stars that are behind you will be redshifted - eventually into invisibility.
  • Stars that are in front of you will be blueshifted.

The effects are subtly noticeable at 0.05 c, fairly intense at about 0.9 c, and really intense at 0.999 c and beyond. They all depend on the Lorentz factor.

Redshift and blueshift cause an increase in the effective temperature of the star. The luminosity grows with the 4th power of the temperature. So the stars in front of you become incredibly bright, while those behind you get dimmed into invisibility.

There is also one additional effect once you get going fast enough. The Cosmic Microwave Background is normally around 2.2 kelvin in temperature, which produces very long wavelength (and very invisible) microwave energy. When this becomes sufficiently blueshifted though, it reaches into the visible range and becomes a "spotlight" visible in the travel direction.

Everything behind you will be a dark void, while in front of you is the primordial light of the universe, screaming white hot and causing the front of your ship to heat to incandescence. That is metal as hell.

# Realistic relativistic travel is too limiting

Imagine you go on your cool hero’s journey, only to return home at the end to find your home civilization as ancient ruins.

If you’re building a survival/civilization building game, imagine trying to get your simulation to run at a fast forward rate of 1000x.

Some settings manage to work with this (e.g. Exodus), but I imagine it’s not what you’re going for if you’re reading this.

# Explanation

In relativity, there is a concept called the "proper velocity" of an object. If you are on a spaceship, this is the speed that you will actually measure yourself travelling at.

The proper velocity w w is equal to the true velocity v v multiplied by the Lorentz factor γ \gamma . The Lorentz factor can be thought of as the "time slowdown factor" for your ship. If your Lorentz factor is 100, then the clocks on your ship are running at 1/100th the speed as a clock in the rest frame.

A table mapping true velocity to the corresponding Lorentz factor can be found on Wikipedia: https://en.wikipedia.org/wiki/Lorentz_factor#Numerical_values

This means that the proper velocity can be faster than the speed of light. If your true velocity is 0.99995 c, the Lorentz factor will be equal to 100, which means your ship’s proper velocity will be 99.995 times c. As in, from your perspective on the ship, you will travel 99.995 lightyears per subjective year. Obviously, for everyone else observing you from afar, your ship will only actually be going at the true velocity of 0.99995 c.

The proper velocity has other nice properties as well. It behaves almost identically to the velocity from classical mechanics: For constant acceleration, you can just add the acceleration times dt like normal. You can use calculations from high school physics like calculating how far you will travel over a given time period when accelerating at a constant rate. I use this for travel time estimations.

Here’s where the faking part comes in: Ignore the time dilation. Your ship actually goes 99.995 times c. When you display the ship’s velocity in the UI, divide it by the Lorentz factor to get the "true" velocity, and show this instead. The true velocity can also be used for rendering the cool relativistic effects I described above. Under the hood, the ship moves faster than light.

You can combine this with other aspects, like shrinking the distances between stars. In my setting, one lightyear is equal to 1/200,000th the real life value, but the value of c c is 1 to 1. This means that a trip at 100x lightspeed takes a few minutes instead of a few real-life days.

The main thing with faking it is that lore wise, your setting never uses FTL travel. In the lore, these trips really do take many years. But to make it work in a game context, you allow players to move at these extreme velocities, without suffering time dilation. It’s a neat illusion.

# Math

The normal formula for the Lorentz factor is expressed in terms of the true velocity, v v . The formula is:

γ = 1 1 − v 2 c 2 \gamma = \frac{1}{\sqrt{1 - \frac{v^2}{c^2}}}

In code, this can be written like so:

double lorentz_from_true_velocity(double velocity, double c) { double v_c = velocity / c; return 1.0 - 1.0 / sqrt(1.0 - v_c * v_c); }

But, you’re working with proper velocity, so you want to find the Lorentz factor from the proper velocity w w , not the true velocity v v . That can be done with this formula:

γ = 1 + w 2 c 2 \gamma = \sqrt{1 + \frac{w^2}{c^2}}

In code:

double lorentz_from_proper_velocity(double proper_velocity, double c) { double w_c = proper_velocity / c; return sqrt(1.0 + w_c * w_c); }

The true velocity can then be found by dividing the proper velocity by the Lorentz factor.

# Problems

# Acceleration

The biggest problem with this approach is that, accelerating to 0.99995 c at a rate of 1g (Earth gravity) would take about 100 subjective years. It takes just short of 1 subjective year for each additional c of proper velocity.

So you still need to have a magical scifi drive anyway. One that can let you accelerate at thousands or millions of g’s without pancaking your crew.

On the plus side, the magical scifi drive doesn’t have problems with time travel. :)

The magical drive can also take a few different forms. For example, you could have one that works like the Frame Shift Drive from Elite Dangerous, or you could have it work like the Warp Drive from Star Trek, or you could have it work like the Mass Relays from Mass Effect. Lots of options there.

# Kinetic energy

Objects moving this fast have a lot of kinetic energy. Kinetic energy can be found with the equation:

E k = ( γ − 1 ) m c 2 E_k = (\gamma - 1)mc^2

You can run the numbers using Rink. For a 1000-ton spaceship travelling at 0.99995 c ( γ \gamma = 100), you write (100 - 1) 1000tonne c^2 to gigaton tnt. In this case, I find that this spaceship would have a kinetic energy of around 2 million gigatons. If it crashed into a planet, it would release about 27 times the energy of the impact that killed the dinosaurs.

Sir Isaac Newton is the deadliest son-of-a-bitch in space! (Youtube, 1:23)

There are a few ways to nerf this, but most of them don’t really have a good explanation behind them.

# FTL Communication

This does not solve the communication aspect at all. If messages can be sent across across space, then they either arrive instantly (FTL), or the player can outrun the light lag.

The only solution here seems to be to sweep it under the rug, or to disallow wireless signals between star systems (messages travel by ship only - e.g. data couriers).

# Visuals

# Redshift

I mentioned this in my article about star rendering: https://tiffnix.com/star-rendering#appendix-a—​redshift

The redshift 1 + z 1 + z can be found with this formula:

1 + z = 1 + v c cos ⁡ θ r 1 − v 2 c 2 1 + z = \frac{1 + \frac{v}{c} \cos \theta_r}{\sqrt{1-\frac{v^2}{c^2}}}

Which can be done with this code:

double redshift(double vel_c, double cos_theta) { return (1.0 + vel_c * cos_theta) / sqrt(1.0 - vel_c * vel_c); }

The value cos_theta is the dot product between the velocity of the ship, and the direction of the star. vel_c is the true velocity divided by the speed of light.

Divide temperature by this 1 + z 1 + z (redshift) value. The temperature can then be converted to a color and an intensity value using a function (I won’t go into it here).

# Warping of light

For the way that light gets warped at high velocities, I found this article very helpful: https://oikofuge.com/celestial-view-from-relativistic-starship-1/

In code, shifting the position of stars looks like this:

Vector3 get_shifted_pos( Vector3 star_pos, Vector3 observer_pos, Vector3 observer_velocity, double c ) { float v_c = observer_velocity.length() / c; float v2_c2 = v_c * v_c; Vector3 star_dir = (star_pos - observer_pos).normalized(); float star_dist = (star_pos - observer_pos).length(); Vector3 travel_dir = observer_veloctiy.normalized(); double travel_dir_dist = (star_pos - observer_pos).dot(travel_dir); double cos_theta = star_dir.dot(-observer_velocity); double one_plus_z = redshift(v_c, cos_theta); double shift_forward = (travel_dir_dist + v_c * dist) / sqrt(1.0 - v2_c2); return star_pos + observer_vel_dir * (shift_forward - travel_dir_dist); }

# CMB spotlight effect

The black body temperature of the Cosmic Microwave Background can be found by dividing 2.2 (the temperature of the CMB) by the value 1 + z 1 + z from above.

# Skybox shader

Here’s the skybox shader I used in Godot for the milky way and the CMB (not the stars). Note that it doesn’t go for full photorealism.

shader_type sky; uniform sampler2D source_panorama : filter_linear, source_color, hint_default_black; uniform float exposure : hint_range(0, 128) = 1.0; uniform sampler2D cmb_texture : filter_linear, source_color, hint_default_black; uniform vec3 cmb_color_max; uniform vec3 cmb_color_min; uniform vec3 velocity; void sky() { float v2_c2 = dot(velocity, velocity); float v_c = sqrt(v2_c2); float cmb_strength = 1.0; vec3 energy = vec3(1.0); vec3 eyedir; if (v_c < 1e-4) { eyedir = EYEDIR; } else { vec3 travel_dir = velocity / v_c; float travel_dist = dot(travel_dir, EYEDIR); float shift = (travel_dist + v_c) / sqrt(1.0 - v2_c2); eyedir = normalize(EYEDIR + travel_dir * (shift - travel_dist)); float one_plus_z = (1.0 + v_c * travel_dist) / sqrt(1.0 - v2_c2); energy /= pow(vec3(one_plus_z), vec3(1.2, 1.0, 1.3)); cmb_strength /= one_plus_z; } vec2 panorama_coords = vec2(atan(-eyedir.x, eyedir.z), acos(eyedir.y)); if (panorama_coords.x < 0.0) { panorama_coords.x += PI * 2.0; } panorama_coords.x += PI; panorama_coords /= vec2(PI * 2.0, PI); vec3 color = texture(source_panorama, panorama_coords).rgb * exposure * energy; float cmb = texture(cmb_texture, panorama_coords).r; color += mix(cmb_color_min, cmb_color_max, cmb) * cmb_strength; COLOR = color; }
Read Entire Article