Skip to main content

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));
  camera.updateProjectionMatrix();
}

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. 

Comments

Mano Marks said…
Cool! How does it handle tiling?
Bjørn Sandvik said…
No tiling support yet! :-)
Sean de Basti said…
really awesome, thank you! now, I dont need the several plattforms to visualize my 360 panoramas
Jake Parker said…
Hi! I can't seem to get the github download to run. I'm pretty new to HTML5, but I come from a C# background and I am just beginning to understand how js hooks into HTML5 stuff. My steps were as follows:
1. Downloaded the github zip.
2. Opened index.html in Chrome (just a black screen)
3. Opened gaustatoppen.html in Chome with same black screen result.

There's probably some super simple step I'm missing just because of my own ignorance with these systems. Any help you can offer is very much appreciated, and I'm a great researcher so if you just want to point me in the right direction that's perfectly fine too!

Thanks!
Jake Parker said…
As and experiment, I just saved your fullscreen photosphere page and found it also gave me a black screen. Maybe these things cannot be run locally? I'm going to throw this up on a server and find out.
Unknown said…
It cannot be run locally because images cannot be loaded into the webGL scene (blocked by X-Origin policy / tainted canvas).

Locally different files act like they are from completely different domains, even if in same folder.
Stefan said…
Hi.

Nice tutorial.

It is a way to get the orientation of what I see? Something like north arrow.

Thank you,

Stefan
NN said…
Hi Bjørn, nice tool for panoramas,
i work years ago with pano 360 takes from iphone and js reel library (http://jquery.vostrel.cz/reel)
to leafletjs maps.

examples in http://www.mesenken.com/demos/demo06.html

Regards!
Anonymous said…
How do you reverse the controls?
Hi Bjørn,
I would like to kindly ask you for advice / code modification. On a small project for friends of the theater (http://indie2014foto.cebreus.eu/) have to displaying photos by Colorbox. I need your great feature to include in the Colorbox. Classic photo identification and a spherical can be done simply on the side of PHP by adding the required class.
Anonymous said…
how can I export a 360 degree frame from THREE.JS scene to be viewable as a photosphere texture?

http://stackoverflow.com/questions/29048161/how-to-export-a-three-js-scene-into-a-360-texture-for-photosphere
Kuan2001 said…
Can you step by step, how to post photosphere on the blogger?
Thanks.
I try to copy the js folder and html. but I couldn't make iframe to show the photo.
where should I host the js and photo and html?

Thanks.
kuan
Unknown said…
@GregGrissom :
To reverse the controls, edit the following line in js/OrbitControls.js
- thetaDelta -= angle;
- phiDelta -= angle;
to
- thetaDelta += angle;
- phiDelta += angle;
Jarodium said…
Is there any way to replace orbit controls with trackball controls?
This will allow pinch to zoom.

Regards
Karan Checker said…
Hey Bjørn

Great work.

Thanks for sharing this.
I'm trying to build a panoramic virtual tour and need to be able to create clickable areas within a panorama which would take me to a hyperlink.

Could you please tell me what is a good way to getting around that?

I'm guessing we'd use Rays and would need to create a plane for marking the selectable area and connect the plane transform to the sphere transform. But I'm really new to Threejs and would really appreciate your help.

Thanks,
Karan
skywalker said…
Hey Karan, just use threejs plane or objects as "links" (threejs objects can have click events on them!).

Popular posts from this blog

Creating a WebGL Earth with three.js

This blog post will show you how to create a WebGL Earth with three.js , a great JavaScript library which helps you to go 3D in the browser. I was surprised how easy it seemed when reading a blog post  by Jerome Etienne . So I decided to give it a try using earth textures  from one of my favourite cartographers, Tom Patterson . WebGL is a JavaScript API for rendering interactive 3D graphics in modern web browsers without the use of plug-ins. Three.js is built on top of WebGL, and allows you to create complex 3D scenes with a few lines of JavaScript. If your browser supports WebGL you should see a rotating Earth below: [ Fullscreen ] To be able to display something with three.js, you need three things: a scene, a camera and a renderer. var width  = window.innerWidth,     height = window.innerHeight; var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, width / height, 0.01, 1000); camera.position.z = 1.5; var rende...

Thematic Mapping Engine

It's time to introduce the Thematic Mapping Engine (TME). In my previous blog posts, I've shown various techniques of how geobrowsers can be used for thematic mapping. The goal has been to explore the possibilites and to make these techniques available to a wider audience. The Tematic Mapping Engine provides an easy-to-use web interface where you can create visually appealing maps on-the-fly. So far only prism maps are supported, but other thematic mapping techniques will be added in the upcoming weeks. The engine returns a KMZ file that you can open in Google Earth or download to your computer. My primary data source is UNdata . The above visualisation is generated by TME ( download KMZ ) and shows child mortaility in the world ( UNdata ). The Thematic Mapping Engine is also an example of what you can achieve with open source tools and datasets in the public domain: A world border dataset is loaded into a MySQL database . The same database contains tables with statistics ...

Creating 3D terrains with Cesium

Previously, I’ve used three.js to create 3D terrain maps in the browser ( 1 , 2 , 3 , 4 , 5 , 6 ). It worked great for smaller areas, but three.js doesn’t have built-in support for tiling and advanced LOD algorithms needed to render large terrains. So I decided to take Cesium for a spin. Cesium is a JavaScript library for creating 3D globes and 2D maps in the browser without a plugin. Like three.js, it uses WebGL for hardware-accelerated graphics. Cesium allows you to add your own terrain data, and this blog post will show you how. Impressed by the terrain rendering in @CesiumJS - with a 10m elevation model for Norway! Farewell Google Earth. pic.twitter.com/RQKvfu2hBb — Bjørn Sandvik (@thematicmapping) October 4, 2014 Compared to  the dying Google Earth plugin , it's quite complicated to get started with Cesium. The source code is well documented and the live coding Sandcastle is great, but there is a lack of tutorials  and my development slows down when ...