May 22, 2014

A Solar System Simulator in Javascript

Hacker School just ended, so I now have some time to blog about the things I made. This one is about space!

Pablo and I built a solar system simulator in Javascript with Three.js! It uses realistic physics modeling to figure out how the planets will orbit, and lets you specify custom masses, velocities, and positions for planets. You can check it out on Github. I recommend just using the “choose a solar system” drop down, and selecting “our solar system”.

Screenshot of Kepler, solar systems simulation

It totally works in 3d too, so you have have planets rotating at angles.

Screenshot of Kepler, with a planet orbiting at an inclination

Drawing Planets

Creating and drawing planets was relatively trivial. We just created spheres of various sizes:

var geometry = new THREE.SphereGeometry(r, 32, 16);
var texture = THREE.ImageUtils.loadTexture(textureUrl);
var material = new THREE.MeshBasicMaterial({ map: texture });
var sphere = new THREE.Mesh(geometry, material);

r is the radius of the planet. Rather than have this be a ridiculously large number, we decided on the scale 1 Three.js unit = 1,000,000,000 meters, or 1 gigameter. This made figuring out the radiuses really simple, since we could just type “radius of earth in gigameters” into Wolfram Alpha, and not have to deal with any conversions ourself.

To get the light highlighting when the planet is far away, we calculate the distance from the planet to the camera. If it’s far enough away, we draw a second, transparent sphere around the planet, with the size of the sphere scaled to the distance from the planet to the camera. That keeps the highlight circles the same size, no matter your distance from the planet.

Screenshot of an example of the highlight circles

The Physics

To simulate the physics of orbiting planets, we use the gravitational force equation.

G × msun × mplanet / r2

Where G is the gravitational constant, m is mass, and r is the distance between the planet and the sun. This tells us the force of these two objects attracting. Since the sun’s movement is negligible, we just care about the force applied to the planet, and since the planet’s acceleration is the force divided by mplanet, the masses cancel out, and we get this equation for the acceleration applied to the planet.

G × msun / r2

In Javascript, this looks like:

var G = 6.67384e-11; // m3 kg-1 s-2
function getAcceleration(distance, starMass) {
  return G * starMass / (Math.pow(distance, 2));
}

We get the vector pointing from the planet to the star, set its length to the delta velocity, and then add it to the existing velocity to get the new velocity.

var distance = getDistance(star.position, planet.position);
var acc = getAcceleration(distance * METERS_PER_UNIT, star.astro.mass);
var dvel = acc * SEC_PER_STEP;
vel.subVectors(star.position, planet.position).setLength(dvel / METERS_PER_UNIT);
planet.astro.vel.add(vel);

planet.position.x += planet.astro.vel.x * SEC_PER_STEP;
planet.position.y += planet.astro.vel.y * SEC_PER_STEP;
planet.position.z += planet.astro.vel.z * SEC_PER_STEP;

SEC_PER_STEP is the number of seconds in the simulation per step, in our case 8, and planet.astro is a custom object on the planet object that stores physics information, like velocity and mass. By default, we run 10000 steps per frame so that the planets move fast enough to see. If we wanted to optimize this, we could probably get a lot better performance if we used calculus to integrate this equation over time. Calculus would also make our calculations more accurate, but having a small time step seems good enough for our purposes.

With just a single equation and some vector math, we’re able to get a pretty accurate simulation of how planets orbit a star. Pretty cool, if you ask me.