Three.js – Drawing Waves

http://mrdoob.github.io/three.js/

As part of the JavaScript study, I made some trials for 3D rendering using Three.js library.

In the beginning, I had some difficulty to understand the API usage, maybe due to the lack of its documentation. But, by looking through the examples and tutorials, I could build up some basic 3D shape drawings on the HTML canvas.

I’m a little surprised by the power of WebGL. Though I once had seen several graphical WebGL demos, it seemed to require very complex coding/processing. Three.js API seems simple enough to use even for novice user like myself. It may require more efforts to create complex objects and consider performance tuning, but I didn’t have to struggle too much at least for the basic one.

The following is some trials I made, and working example on jsdo.it.

Screenshot
threejswave

Working Example
http://jsdo.it/parroty/2Rix

Source Code

var stats, camera, scene, renderer;
var geometry, points = [];

var windowHalfX = window.innerWidth  / 2;
var windowHalfY = window.innerHeight / 2;

// parameters
var SEPARATION     = 25;
var AMOUNTX        = 50;
var AMOUNTY        = 50;
var INITIAL_FACTOR = 1.0;
var WAVE_HEIGHT    = 200;
var WAVE_SPEED     = 0.2;
var ROTATION_SPEED = 0.1;
var DAMP_SPEED     = 0.005;
var CAMERA_SPEED   = 0.05;

var rotation = 0;
var factor   = INITIAL_FACTOR;
var mouseX   = -300;
var mouseY   = -300;
var initial_camera_zpos = 500;
var initial_camera_ypos = 500;

init();
animate();

function init() {
  var container = document.createElement('div');
  document.body.appendChild(container);

  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
  camera.position.z = initial_camera_zpos;
  camera.position.y = initial_camera_ypos;

  scene = new THREE.Scene();

  var width  = SEPARATION * AMOUNTX;
  var height = SEPARATION * AMOUNTY;

  geometry = new THREE.PlaneGeometry(width, height, AMOUNTX, AMOUNTY);
  var ground = new THREE.Mesh(geometry);

  calculateInitialPoints();
  updatePoints();

  ground.rotation.x = Math.PI / -2;
  scene.add(ground);

  renderer = new THREE.CanvasRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  container.appendChild(renderer.domElement);

  stats = new Stats();
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.top = '0px';
  container.appendChild(stats.domElement);

  document.addEventListener('mousemove', onDocumentMouseMove, false);
  document.addEventListener('mousedown', onMouseDown, false);
  window.addEventListener('resize', onWindowResize, false);
}

function calculateInitialPoints() {
  for(var i = 0; i < geometry.vertices.length; i++) {
    var v = geometry.vertices[i];
    var x = (v.x / SEPARATION) * WAVE_SPEED;
    var y = (v.y / SEPARATION) * WAVE_SPEED;
    points[i] = WAVE_HEIGHT * (Math.cos(x*x + y*y) / Math.sqrt(x*x + y*y + 0.25));
  }
}

function updatePoints() {
  for(var i = 0; i < geometry.vertices.length; i++) {
    var v = geometry.vertices[i];
    v.z = points[i] * Math.cos(rotation) * factor;
  }
}

function calculateNextParameters() {
  rotation += ROTATION_SPEED;
  if(factor > 0) {
    factor -= DAMP_SPEED;
  }
}

function onWindowResize() {
  windowHalfX = window.innerWidth  / 2;
  windowHalfY = window.innerHeight / 2;

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
}

function onDocumentMouseMove(event) {
  mouseX = event.clientX - windowHalfX;
  mouseY = event.clientY - windowHalfY;
}

function onMouseDown(event) {
  factor = INITIAL_FACTOR;
}

function animate() {
  requestAnimationFrame(animate);
  render();
  stats.update();
}

function render() {
  camera.position.x += ( mouseX - camera.position.x) * CAMERA_SPEED;
  camera.position.y += (-mouseY - camera.position.y) * CAMERA_SPEED;
  camera.lookAt(scene.position);

  updatePoints();
  renderer.render(scene, camera);
  calculateNextParameters();
}
Advertisements

Posted on April 18, 2013, in JavaScript. Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: