Today I started experimenting with the Three.js framework that supports the creation of WebGL apps in most modern browsers. I started from the most basic example I saw demonstrated at a recent JavaScript Meetup in Baltimore. I then began to dig around to figure out how to add an modify things the way I wanted them. I first figured out how to display both the faces and the vertices of 3D shapes, and then I figured out how to make the camera fly around the correct axis to maintain the perspective I was going for. If x is left and right, y is up and down, and z is into the screen, then to make it look like you’re a helicopter flying around a landscape while always looking toward the same point you have to assume that the y-axis is the vertical about which you orbit (revolve) along or above the x-z plane. Now that I have that sorted out a lot of the rest of rendering the simulation in 3D should be fairly straightforward, if detailed and time-consuming.
Here’s the basic code so far.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>My first Three.js app</title> <style> body { margin: 0; } canvas { width: 100%; height: 100% </style> </head> <body> <script src="js/three.js"></script> <script> var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ); var light = new THREE.HemisphereLight( 0xeeeeee, 0x888888, 1 ); light.position.set( 0, 20, 0 ); scene.add( light ); var renderer = new THREE.WebGLRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 1, 0.2, 1 ); var material = new THREE.MeshPhongMaterial({ color: 0x00ff00, shading: THREE.FlatShading, polygonOffset: true, polygonOffsetFactor: 1, //positive value pushes polygon farther away polygonOffsetUnits: 1 }); var cube = new THREE.Mesh( geometry, material ); // wireframe var geo = new THREE.EdgesGeometry( cube.geometry ); var mat = new THREE.LineBasicMaterial( { color: 0x222222, linewidth: 2 } ); //linewidth defaults to 1 in Windows iirc var wireframe = new THREE.LineSegments( geo, mat ); cube.add( wireframe ); cube.position.set(0,0,0); scene.add( cube ); var cameraRadius = 6.0; var cameraRevolutionAngle = Math.PI * 0.5; var cameraRevolutionIncrement = -0.01; camera.position.x = cameraRadius * Math.cos(cameraRevolutionAngle); camera.position.z = cameraRadius * Math.sin(cameraRevolutionAngle); camera.position.y = 2; renderer.render( scene, camera ); function render() { cameraRevolutionAngle += cameraRevolutionIncrement; if (cameraRevolutionAngle > Math.PI * 2.0) { cameraRevolutionAngle -= Math.PI * 2.0; } camera.position.x = cameraRadius * Math.cos(cameraRevolutionAngle); camera.position.z = cameraRadius * Math.sin(cameraRevolutionAngle); camera.lookAt(scene.position); renderer.render( scene, camera ); requestAnimationFrame( render ); } render(); </script> </body> </html> |
I’m used to doing most of this sort of thing on my own by managing my own coordinates, transforms, perspecitives, and renderings, but I never fully studied hidden surface algorithms, shading, and so on. Learning this framework gives me a lot more leverage, and my existing experience helps me understand the whole thing easily enough.