Last active
December 5, 2015 01:08
-
-
Save blackslate/aae4f000d54083f55e0b to your computer and use it in GitHub Desktop.
Trackball inset to control a perspective camera
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- Demo: http://codepen.io/anon/pen/MKWrOr --> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r73/three.js"></script> | |
<style> | |
body { | |
margin: 0; | |
overflow: hidden; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="WebGL-output"></div> | |
<script> | |
function init() { | |
var scene = new THREE.Scene() | |
var renderer = new THREE.WebGLRenderer() | |
var camera | |
var cameras = [] | |
var WIDTH = window.innerWidth | |
var HEIGHT = window.innerHeight | |
;(function createPerspectiveCamera(){ | |
var FOV = 45 | |
var ASPECT = WIDTH / HEIGHT | |
var NEAR = 1 | |
var FAR = 360 | |
camera = new THREE.PerspectiveCamera(FOV, ASPECT, NEAR, FAR) | |
camera.position.x = 100 | |
camera.position.y = 100 | |
camera.position.z = 100 | |
camera.viewport = { x: 0, y: 0, width: WIDTH, height: HEIGHT } | |
camera.lookAt(scene.position) | |
cameras.push(camera) | |
})() | |
;(function initializeRenderer(){ | |
renderer.setClearColor(new THREE.Color(0xEEEEFF)) | |
renderer.setSize(WIDTH, HEIGHT) | |
renderer.autoClear = false; | |
document.getElementById("WebGL-output").appendChild(renderer.domElement) | |
;(function render() { | |
var viewport | |
renderer.setViewport( 0, 0, WIDTH, HEIGHT ); | |
renderer.clear(); | |
cameras.forEach(function (camera) { | |
viewport = camera.viewport // custom property | |
renderer.setViewport( | |
viewport.x | |
, viewport.y | |
, viewport.width | |
, viewport.height | |
) | |
renderer.render(scene, camera) | |
}) | |
requestAnimationFrame(render) | |
})() | |
})() | |
;(function createCameraController(){ | |
var viewport = { | |
x: WIDTH - 100 | |
, y: HEIGHT - 100 | |
, width: 100 | |
, height: 100 | |
} | |
var circle = { | |
x: WIDTH - 50 | |
, y: 50 | |
, radius: 50 | |
} | |
var settings = { | |
viewport: viewport | |
, circle: circle | |
} | |
addCameraController(scene, camera, cameras, settings) | |
})() | |
// Something to look at | |
scene.add(new THREE.AxisHelper(70)) | |
} | |
function addCameraController(scene, camera, cameras, settings) { | |
var controlCamera | |
var viewport = settings.viewport | |
// For mouse interactions | |
var centreX = settings.circle.x | |
var centreY = settings.circle.y | |
var radius = settings.circle.radius | |
var radius2 = radius * radius | |
var rotationMatrix = new THREE.Matrix4() | |
var pivotMatrix = new THREE.Matrix4() | |
var startMatrix = new THREE.Matrix4() | |
var start = new THREE.Vector3() | |
var end = new THREE.Vector3() | |
var angle | |
camera.matrixAutoUpdate = false /** takes control of main camera **/ | |
;(function createControlCameraCubeAndCircle(){ | |
var side = 1 | |
var radius = Math.sqrt(side/2 * side/2 * 3) | |
;(function createCamera(){ | |
controlCamera = new THREE.OrthographicCamera( | |
-radius, radius | |
, radius, -radius | |
, -radius, radius | |
); | |
controlCamera.viewport = viewport | |
controlCamera.rotation.copy(camera.rotation) | |
// If matrixAutoUpdate is set immediately, the camera rotation | |
// is not applied | |
setTimeout(function () { | |
controlCamera.matrixAutoUpdate = false | |
}, 1) | |
scene.add(controlCamera) | |
cameras.push( controlCamera ) | |
})() | |
;(function createCompanionCube(){ | |
var cube = new THREE.Object3D() | |
var cubeGeometry = new THREE.BoxGeometry( side, side, side ) | |
var lineMaterial = new THREE.LineBasicMaterial({ | |
color: 0xffffff | |
, transparent: true | |
, opacity: 0.5 | |
}) | |
var faceMaterial = new THREE.MeshPhongMaterial({ | |
color: 0x006699 | |
, emissive: 0x006699 | |
, shading: THREE.FlatShading | |
, transparent: true | |
, opacity: 0.2 | |
}) | |
cube.add( | |
new THREE.LineSegments( | |
new THREE.WireframeGeometry( cubeGeometry ) | |
, lineMaterial | |
) | |
) | |
cube.add( | |
new THREE.Mesh( | |
cubeGeometry | |
, faceMaterial | |
) | |
) | |
cube.add(new THREE.AxisHelper(radius)) | |
scene.add(cube); | |
})() | |
;(function createCircle(){ | |
var circleGeometry = new THREE.CircleGeometry( radius, 36 ); | |
var material = new THREE.MeshBasicMaterial( { | |
color: 0xccccff | |
} ); | |
var circle = new THREE.Mesh( circleGeometry, material ); | |
controlCamera.add( circle ); | |
circle.translateZ(-radius) | |
})() | |
})() | |
window.addEventListener("mousedown", startDrag, false) | |
function startDrag(event) { | |
controlCamera.matrixAutoUpdate = false | |
var x = event.clientX - centreX | |
var y = centreY - event.clientY | |
var delta2 = x * x + y * y | |
if (delta2 > radius2) { | |
return | |
} | |
var z = Math.sqrt(radius2 - delta2) | |
start.set(x, y, z) | |
window.addEventListener("mousemove", drag, false) | |
window.addEventListener("mouseup", stopDrag, false) | |
function drag(event) { | |
var delta | |
x = event.clientX - centreX | |
y = centreY - event.clientY | |
delta2 = x * x + y * y | |
if (delta2 > radius2) { | |
// constrain to adge of sphere | |
delta = Math.sqrt(delta2) | |
x = x / delta * radius | |
y = y / delta * radius | |
z = 0 | |
} else { | |
z = Math.sqrt(radius2 - delta2) | |
} | |
end.set(x, y, z) | |
angle = start.angleTo(end) | |
start.cross(end).normalize() | |
rotationMatrix.makeRotationAxis(start, -angle) | |
controlCamera.matrix.multiply(rotationMatrix) | |
controlCamera.matrixWorldNeedsUpdate = true | |
rotationMatrix.extractRotation(camera.matrixWorld) | |
start.applyMatrix4(rotationMatrix).normalize() | |
rotationMatrix.makeRotationAxis(start, -angle) | |
camera.applyMatrix(rotationMatrix) | |
camera.matrixWorldNeedsUpdate = true | |
start.copy(end) | |
} | |
function stopDrag(event) { | |
window.removeEventListener("mousemove", drag, false) | |
window.removeEventListener("mouseup", stopDrag, false) | |
} | |
} | |
} | |
window.onload = init | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment