Wednesday, October 3, 2012

Three.js Retrograde Motion

‹prev | My Chain | next›

Up today I am going to make my Three.js space simulation a bit more space-like. I would also to add a few different cameras to the simulation, time permitting.

First up, I make my background color black by setting the clear color on the renderer:
This makes the dark side of planets blend completely into the blackness of space. Although this is more realistic, I add a bit of ambient color (it had been 0x000000):
  var surface = new THREE.MeshPhongMaterial({ambient: 0x1a1a1a, color: 0x0000cd});
  var planet = new THREE.SphereGeometry(20);
  var earth = new THREE.Mesh(planet, surface);
  earth.position.set(250, 0, 0);
That works fairly well:

Next, I add some stars. I figured out how do do that with Three.js particle systems a few days ago. This time, I need to distribute the stars all around the Solar System. A plane far away in the Z direction will not suffice because I need to move the camera around and still see stars. I am unsure what the conceptually simplest way to accomplish this is going to be. For now, I go with the easiest way that I know to do it—trigonometry:
  var stars = new THREE.Geometry();
  while (stars.vertices.length < 1e5) {
    var lat = Math.PI * Math.random() - Math.PI/2;
    var lon = 2*Math.PI * Math.random();
    stars.vertices.push(new THREE.Vector3(
      1e5 * Math.cos(lon) * Math.cos(lat),
      1e5 * Math.sin(lon) * Math.cos(lat),
      1e5 * Math.sin(lat)
  var star_stuff = new THREE.ParticleBasicMaterial({size: 1});
  var star_system = new THREE.ParticleSystem(stars, star_stuff);
That gives me nice stars from "above" the Solar System:

And if I spin the camera around, I still see nicely distributed stars.

Figuring out how to position the "earth-cam" that always faces Mars (so that we can witness retrograde motion) is a solved problem. I re-implement in Three.js as:
    var y_diff = mars.position.y - earth.position.y
      , x_diff = mars.position.x - earth.position.x
      , angle = Math.atan2(x_diff, y_diff);
    earth_cam.rotation.set(Math.PI/2, -angle, 0)
    earth_cam.position.set(earth.position.x, earth.position.y, 22);
I end by adding a simple document listener that can switch between above-the-solar-system-cam and earth-cam by pressing "1" or "2":
  document.addEventListener("keydown", function(event) {
    var code = event.which || event.keyCode;

    if (code == 49) {
      camera = above_cam;
    if (code == 50) {
      camera = earth_cam; 
    else console.log(code);
    return false;
With that, I can easily switch back and forth between earth-cam:

And above-cam:

That is a fine stopping point for tonight. At this point, I think I need to rework a few things in Mr Doob's code editor to make it more suited to kids working through Gaming JavaScript, so I will pick up with that tomorrow.

Editable / runnable code

Day #528

No comments:

Post a Comment