There was recently a flood of Three.js books on Safari lately including Essential Three.js and Game Development with Three.js. Three.js is a JavaScript based 3D library using WebGL ( and not, if not available ). More importantly, it’s just really fun to play with! Something about working in full 3D in a scripting language is just really satisfying. I’ve only just been playing and really don’t have a clue what I’m doing, but I figured I would share my results. As I have been on a TypeScript kick lately, I’ve been writing in TypeScript instead of plain JavaScript, but frankly the differences are fairly minimal. You can get the TypeScript definitions on DefinatelyTyped.
I think I should make something perfectly clear… I have NO idea what I am doing, I am simply playing around. This isn’t a WebGL tutorial by any definition of the word, just me having skim read a couple of books and played around with a new technology, nothing more. So if you look at some code and thing “damn that looks hacky” or “isn’t that a really stupid thing to do?” the answer is probably yes! 🙂
So, disclaimer given, let’s jump right in.
Since this is a web app, we need a host HTML page. So, here is ours:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>ThreeJS Test</title> <script src="http://cdnjs.cloudflare.com/ajax/libs/three.js/r67/three.js"></script> <script src="app.js"></script> </head> <body> <h1>ThreeJS Test</h1> <div id="content" style="width:500px;height:500px"></div> </body> </html>
Nothing really shocking here. We include three.js using the cloudflare content delivery network. If you wanted of course you could download the library locally and deploy it from your own servers. I assume you don’t have servers situated around the world, so a CDN will generally thrash your own servers performance. Next we include app.js, the generated output from our typescript application. In the actual HTML we create a 500×500 DIV named content, for predictably enough, our content!
Now lets take a look at a super simple example app, app.ts:
///<reference path="./three.d.ts"/> class ThreeJSTest { renderer: THREE.WebGLRenderer; constructor(){ this.renderer = new THREE.WebGLRenderer({ alpha: true }); this.renderer.setSize(500,500); this.renderer.setClearColor(0xFF0000,1); document.getElementById('content').appendChild(this.renderer.domElement); } start() { this.renderer.clear(); } } window.onload = () => { var three = new ThreeJSTest(); three.start(); };
Here in the constructor we create a WebGLRenderer, size it, set the background color to red ( using HTML format hex color coding ) then wire the renderer to the content div.
When you run it you should see:
Cool, our first Three.js application. Now let’s do something 3D! Let’s start by creating a camera and rendering a built in 3D object in wireframe. It’s commented heavily, so I wont be explaining what is going on. If you are curious why I did something, leave a comment.
///<reference path="./three.d.ts"/> class ThreeJSTest { renderer: THREE.WebGLRenderer; scene: THREE.Scene; camera: THREE.Camera; constructor(){ // Create the renderer, in this case using WebGL, we want an alpha channel this.renderer = new THREE.WebGLRenderer({ alpha: true }); // Set dimensions to 500x500 and background color to white this.renderer.setSize(500,500); this.renderer.setClearColor(0xFFFFFF,1); // Bind the renderer to the HTML, parenting it to our 'content' DIV document.getElementById('content').appendChild(this.renderer.domElement); // Create a Scene this.scene = new THREE.Scene(); // And a camera. Set Field of View, Near and Far clipping planes this.camera = new THREE.PerspectiveCamera(45 , 1 , 0.1, 1000); // Position is -20 along the Z axis and look at the origin this.camera.position = new THREE.Vector3(0,0,-20); this.camera.lookAt(new THREE.Vector3(0,0,0)); // Createa the geometry for a sphere with a radius of 5 var sphereGeometry = new THREE.SphereGeometry(5); // Create a wireframe material that's blueish var sphereMaterial = new THREE.MeshBasicMaterial( {color: 0x7777ff, wireframe: true}); // Now make a THREE.Mesh using the geometry and a shader var sphere = new THREE.Mesh(sphereGeometry,sphereMaterial); // And put it at the origin sphere.position = new THREE.Vector3(0,0,0); // Add it to the scene and render the scene using the Scene and Camera objects this.scene.add(sphere); this.renderer.render(this.scene,this.camera); } start() { // Well, arent I a bit pointless? } } window.onload = () => { var three = new ThreeJSTest(); three.start(); };
And when run it we get:
Cool! Now time for some texturing ( and as a result, lighting ).
///<reference path="./three.d.ts"/> class ThreeJSTest { renderer:THREE.WebGLRenderer; scene:THREE.Scene; camera:THREE.Camera; constructor() { // Create the renderer, in this case using WebGL, we want an alpha channel this.renderer = new THREE.WebGLRenderer({ alpha: true }); // Set dimensions to 500x500 and background color to white this.renderer.setSize(500, 500); this.renderer.setClearColor(0xFFFFFF, 1); // Bind the renderer to the HTML, parenting it to our 'content' DIV document.getElementById('content').appendChild(this.renderer.domElement); // Create a Scene this.scene = new THREE.Scene(); // And a camera. Set Field of View, Near and Far clipping planes this.camera = new THREE.PerspectiveCamera(45 , 1 , 0.1, 1000); // Position is -20 along the Z axis and look at the origin this.camera.position = new THREE.Vector3(0, 0, -20); this.camera.lookAt(new THREE.Vector3(0, 0, 0)); // Createa the geometry for a sphere with a radius of 5 // This time we cranked up the number of sections horizontal and vertical to make a
higher resolution globe var sphereGeometry = new THREE.SphereGeometry(5, 20, 20); // This time we create a Phong shader material and provide a texture. var sphereMaterial = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture("earth_sphere.jpg") } ); // Now make a THREE.Mesh using the geometry and a shader var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // And put it at the origin sphere.position = new THREE.Vector3(0, 0, 0); // Add it to the scene and render the scene using the Scene and Camera objects this.scene.add(sphere); // We need some light so our texture will show, ad an ambient light to the scene this.scene.add(new THREE.AmbientLight(new THREE.Color(0.9,0.9,0.9).getHex())); this.renderer.render(this.scene, this.camera); } render() { // Each frame we want to render the scene again // Use typescript Arrow notation to retain the thisocity passing render to requestAnimationFrame // It's possible I invented the word thisocity. requestAnimationFrame(() => this.render()); this.renderer.render(this.scene, this.camera); } start() { // Not so pointless now! this.render(); } } window.onload = () => { var three = new ThreeJSTest(); three.start(); };
Bet you can’t guess what texture I went with!
So apparently textured 3D objects are nothing difficult.
This is getting pretty long, so I’ll cut it off here. Next up I’m going to look at getting a Blender object rendering in Three.JS.