Tuesday 7 January 2014

Creating wee planets with GDAL

In my last blog post, we projected an equirectangular photograph on a sphere using three.js. Today, we'll use the same panorama to create a wee (miniature) planet.

A wee planet is a panorama projected to look like small planets using a stereographic projection. There is a great collection of wee planets from Alexandre Duret-Lutz on Flickr.

There are image software you can use to create wee planets, but why not be a real map nerd and use GDAL instead? We already have a 360°x180° panorama in an equirectangular projection. The only difference from a world map is that the panorama is not georeferenced. Let's do it with gdal_translate:

gdal_translate -of GTiff -a_ullr -180 90 180 -90 -a_srs EPSG:4326 bergsjostolen.jpg bergsjostolen.tif

We pretend our new GeoTIFF to be the world, and use gdalwarp to create a wee planet using the stereographic projection:

gdalwarp -wo SOURCE_EXTRA=10000 -r bilinear -te -22500000 -22500000 22500000 22500000 -ts 1000 1000 -s_srs EPSG:4326 -t_srs EPSG:3031 bergsjostolen.tif bergsjostolen-planet.tif

I'm using the Antarctic Polar Stereographic projection. If we use the same projection on a world map it will look like this:

I wanted the house on the top, and copied the projection string and changed the longitude rotation to -160:

gdalwarp -wo SOURCE_EXTRA=10000 -r bilinear -te -22500000 -22500000 22500000 22500000 -ts 1000 1000 -s_srs EPSG:4326 -t_srs "+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=-160 +k=1 +x_0=0 +y_0=0 +ellps=WGS84 +datum=WGS84 +units=m +no_defs" bergsjostolen.tif bergsjostolen-planet.tif

There you go, a wee planet from a map nerd!

Snow kiters at Bergsjø.

Bergsjøstølen in the blue hour.

Monday 6 January 2014

Photo spheres with three.js

Ever wanted to create those fancy-looking 360° panoramas? If you mix a mobile phone with three.js and some knowledge about (map) projections, it's quite easy. 

I love travelling, especially to mountainous areas of our planet. Taking photos of vast landscapes can be challenging. This drew my interest in spherical panoramas, photographs that captures everything around you - up, down and all around - 360 x 180 degrees. 

Google calls it a photo sphere, and if you own a mobile phone with Android 4.2 or higher, you can easily create one yourself. I captured this winter scene with my phone a few days ago. But what if you want to get rid of the Google wrapping and show your panorama in your own viewer? Let's try to do it with three.js.

If you download the image from your phone it looks like this:

This is called an equirectangular photograph, which will be entirely seamless when wrapped around a sphere. It has the same projection as most of the world maps you download on the web. You'll find several funny-looking equirectangular photographs on Flickr.

Wrapping such images around a sphere is easy with three.js (read the details here):

var sphere = new THREE.Mesh(
  new THREE.SphereGeometry(100, 32, 32),
  new THREE.MeshBasicMaterial({
    map: THREE.ImageUtils.loadTexture('bergsjostolen.jpg')

You simply create a mesh of a geometric sphere and a material containing your image as a texture.

This will create a christmas ball effect your photo. Next we need to place the camera inside the sphere. You won't see much unless you invert the mesh "inside-out" by setting:

sphere.scale.x = -1;

I'm using the orbit controls to rotate the camera and allow the user to look around inside the sphere.

var controls = new THREE.OrbitControls(camera);
controls.noPan = true;
controls.noZoom = true; 
controls.autoRotate = true;
controls.autoRotateSpeed = 0.5;

Pan and zoom are disabled, as they're not fit for purpose. Instead I'm allowing the user to change the field of view (code from this three.js example):

function onMouseWheel(event) {
  if (event.wheelDeltaY) { // WebKit
    camera.fov -= event.wheelDeltaY * 0.05;
  } else if (event.wheelDelta) { // Opera / IE9
    camera.fov -= event.wheelDelta * 0.05;
  } else if (event.detail) { // Firefox
    camera.fov += event.detail * 1.0;

  camera.fov = Math.max(40, Math.min(100, camera.fov));

document.addEventListener('mousewheel', onMouseWheel, false);
document.addEventListener('DOMMouseScroll', onMouseWheel, false);

I'm also using the detector script to use the Canvas renderer when WebGL is not supported:

var renderer = Detector.webgl ? new THREE.WebGLRenderer() : new THREE.CanvasRenderer();

Now we have our own photo sphere viewer:

[ Fullscreen ]

Feel free to improve it on GitHub.

Bergsjøstølen at dawn.

Towards Reineskarvet.

Hesthovdstølen shielding at 1155 m.