npm package: 3d-view
Description: 3D camera view controller
Author: Mikola Lysenko
Latest version: 2.0.1

3d-view
=======
This module is a generic interface which synchronizes several existing view interactions

* [turntable-camera-controller](https://github.com/mikolalysenko/turntable-camera-controller)
* [orbit-camera-controller](https://github.com/mikolalysenko/orbit-camera-controller)
* [matrix-camera-controller](https://github.com/mikolalysenko/orbit-camera-controller)

Each camera controller proceeds by appending events onto a log.  The current camera state is obtained by interpolating between these events.

# API

[Try a more complete demo here](https://mikolalysenko.github.io/3d-view)

```javascript
var now            = require('right-now')
var bunny          = require('bunny')
var perspective    = require('gl-mat4/perspective')
var fit            = require('canvas-fit')
var createContext  = require('gl-context')
var createAxes     = require('gl-axes')
var createMesh     = require('gl-simplicial-complex')
var createCamera   = require('3d-view')

//Set up WebGL
var canvas = document.createElement('canvas')
document.body.appendChild(canvas)
window.addEventListener('resize', fit(canvas), false)
var gl = createContext(canvas, {}, render)

//Create objects for rendering
var bounds = [[-10,-10,-10], [10,10,10]]
var mesh = createMesh(gl, {
    cells: bunny.cells,
    positions: bunny.positions,
    colormap: 'jet'
  })
var axes = createAxes(gl, {
    bounds: bounds,
    tickSpacing: [1,1,1],
    textSize: 0.05
  })

//Set up camera
var projectionMatrix = new Array(16)
var camera = createCamera({
  center:  [
    0.5*(bounds[0][0]+bounds[1][0]),
    0.5*(bounds[0][1]+bounds[1][1]),
    0.5*(bounds[0][2]+bounds[1][2]) ],
  eye: [0, 0, bounds[1][2]],
  distanceLimits: [1, 1000]
})

//Create mode drop down
var modeSelect = document.createElement('select')
camera.modes.forEach(function(mode) {
  modeSelect.add(new Option(mode, mode))
})
modeSelect.style.position = 'absolute'
modeSelect.style.left = '10px'
modeSelect.style.top = '10px'
modeSelect.style['z-index'] = 10
document.body.appendChild(modeSelect)


//Hook event listeners
var lastX = 0, lastY = 0

document.oncontextmenu = function(e) { 
  e.preventDefault()
  e.stopPropagation()
  return false 
}

modeSelect.addEventListener('change', function(ev) {
  camera.setMode(modeSelect.value)
})

canvas.addEventListener('mousemove', function(ev) {
  var dx =  (ev.clientX - lastX) / gl.drawingBufferWidth
  var dy = -(ev.clientY - lastY) / gl.drawingBufferHeight
  if(ev.which === 1) {
    if(ev.shiftKey) {
      //zoom
      camera.rotate(now(), 0, 0, dx)
    } else {
      //rotate
      camera.rotate(now(), dx, dy)
    }
  } else if(ev.which === 3) {
    //pan
    camera.pan(now(), dx, dy)
  }
  lastX = ev.clientX
  lastY = ev.clientY
})

canvas.addEventListener('wheel', function(e) {
  camera.pan(now(), 0, 0, e.deltaY)
})

//Redraw frame
function render() {

  //Update camera parameters
  var t = now()
  camera.idle(t - 20)
  camera.flush(t - 100)
  camera.recalcMatrix(t-25)
  
  //Compute parameters
  var cameraParams = {
    view: camera.computedMatrix,
    projection: perspective(
      [],
      Math.PI/4.0,
      gl.drawingBufferWidth/gl.drawingBufferHeight,
      0.1,
      1000.0)
  }

  //Draw everything
  gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)
  gl.enable(gl.DEPTH_TEST)
  axes.draw(cameraParams)
  mesh.draw(cameraParams)
}
```

## Constructor

#### `var camera = require('3d-view')([options])`

## Methods

#### `camera.idle(t)`
Idles the camera at time `t`

* `t` is the time to idle at

#### `camera.flush(t)`
Flush all events in camera state before time `t`

* `t` is the cut off time for the flush

#### `camera.modes`
An array of modes supported by the camera

#### `camera.setMode(mode)`
Sets the camera mode

* `mode` is the new mode.  Must be either `turntable`, `orbit` or `matrix`

#### `camera.getMode()`
Retrieves the current camera mode

#### `camera.lookAt(t, eye, center, up)`
Reset camera position to focus on a specified target

* `t` is the time of the event
* `eye` is the position of the camera
* `center` is the target of the camera
* `up` is a vector pointing up

#### `camera.rotate(t, yaw, pitch, roll)`
Rotates the camera incrementally by some amount

* `t` is the time of the input event
* `yaw` is the amount to rotate by along y-axis in radians
* `pitch` is the amount to rotate by along x-axis in radians
* `roll` is the amount to rotate by along z-axis in radians

#### `camera.pan(t, dx, dy, dz)`
Pans the camera in local (view relative) coordinates

* `t` is the time of the event
* `dx,dy,dz` is the amount to move

#### `camera.translate(t, dx, dy, dz)`
Translates the camera in world (absolute global) coordinates

* `t` is the time of the event
* `dx,dy,dz` is the amount to move

#### `camera.setMatrix(t, matrix)`
Sets the camera matrix to some fixed 4x4 matrix

* `t` is the time of the event
* `matrix` is the new camera matrix

#### `camera.setDistance(t, r)`
Sets camera distance at time `t`

* `t` is the time of the event
* `r` is the new camera distance

#### `camera.setDistanceLimits(lo, hi)`
Sets bounds on the camera distance

#### `camera.getDistanceLimits([out])`
Retrieves the camera limits

#### `camera.recalcMatrix(t)`
Recomputes all matrix properties at time `t`

#### `camera.computedMatrix`
The computed 4x4 matrix of the camera

#### `camera.computedEye`
The computed 3d eye vector for the camera

#### `camera.computedUp`
Computed up vector (initialized when calling recalcMatrix)

#### `camera.computedCenter`
Computed camera center point

#### `camera.computedRadius`
Computed log(radius)

# License
(c) 2015 Mikola Lysenko. MIT License