threex
Version:
Game Extensions for three.js http://www.threejsgames.com/extensions/
202 lines (141 loc) • 5.52 kB
JavaScript
/**
* DeviceOrientationControls - applies device orientation on object rotation
*
* @param {Object} object - instance of THREE.Object3D
* @constructor
*
* @author richt / http://richt.me
* @author WestLangley / http://github.com/WestLangley
* @author jonobr1 / http://jonobr1.com
* @author arodic / http://aleksandarrodic.com
* @author doug / http://github.com/doug
*
* W3C Device Orientation control
* (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
*/
THREE.DeviceOrientationControls = function(object) {
this.object = object;
this.object.rotation.reorder('YXZ');
this.freeze = true;
this.movementSpeed = 1.0;
this.rollSpeed = 0.005;
this.autoAlign = true;
this.autoForward = false;
this.alpha = 0;
this.beta = 0;
this.gamma = 0;
this.orient = 0;
this.alignQuaternion = new THREE.Quaternion();
this.orientationQuaternion = new THREE.Quaternion();
var quaternion = new THREE.Quaternion();
var quaternionLerp = new THREE.Quaternion();
var tempVector3 = new THREE.Vector3();
var tempMatrix4 = new THREE.Matrix4();
var tempEuler = new THREE.Euler(0, 0, 0, 'YXZ');
var tempQuaternion = new THREE.Quaternion();
var zee = new THREE.Vector3(0, 0, 1);
var up = new THREE.Vector3(0, 1, 0);
var v0 = new THREE.Vector3(0, 0, 0);
var euler = new THREE.Euler();
var q0 = new THREE.Quaternion(); // - PI/2 around the x-axis
var q1 = new THREE.Quaternion(- Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
this.deviceOrientation = {};
this.screenOrientation = window.orientation || 0;
this.onDeviceOrientationChangeEvent = (function(rawEvtData) {
this.deviceOrientation = rawEvtData;
}).bind(this);
var getOrientation = function() {
switch (window.screen.orientation || window.screen.mozOrientation) {
case 'landscape-primary':
return 90;
case 'landscape-secondary':
return -90;
case 'portrait-secondary':
return 180;
case 'portrait-primary':
return 0;
}
// this returns 90 if width is greater then height
// and window orientation is undefined OR 0
// if (!window.orientation && window.innerWidth > window.innerHeight)
// return 90;
return window.orientation || 0;
};
this.onScreenOrientationChangeEvent = (function() {
this.screenOrientation = getOrientation();
}).bind(this);
this.update = function(delta) {
return function() {
if (this.freeze) return;
// should not need this
var orientation = getOrientation();
if (orientation !== this.screenOrientation) {
this.screenOrientation = orientation;
this.autoAlign = true;
}
this.alpha = this.deviceOrientation.gamma ?
THREE.Math.degToRad(this.deviceOrientation.alpha) : 0; // Z
this.beta = this.deviceOrientation.beta ?
THREE.Math.degToRad(this.deviceOrientation.beta) : 0; // X'
this.gamma = this.deviceOrientation.gamma ?
THREE.Math.degToRad(this.deviceOrientation.gamma) : 0; // Y''
this.orient = this.screenOrientation ?
THREE.Math.degToRad(this.screenOrientation) : 0; // O
// The angles alpha, beta and gamma
// form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
// 'ZXY' for the device, but 'YXZ' for us
euler.set(this.beta, this.alpha, - this.gamma, 'YXZ');
quaternion.setFromEuler(euler);
quaternionLerp.slerp(quaternion, 0.5); // interpolate
// orient the device
if (this.autoAlign) this.orientationQuaternion.copy(quaternion); // interpolation breaks the auto alignment
else this.orientationQuaternion.copy(quaternionLerp);
// camera looks out the back of the device, not the top
this.orientationQuaternion.multiply(q1);
// adjust for screen orientation
this.orientationQuaternion.multiply(q0.setFromAxisAngle(zee, - this.orient));
this.object.quaternion.copy(this.alignQuaternion);
this.object.quaternion.multiply(this.orientationQuaternion);
if (this.autoForward) {
tempVector3
.set(0, 0, -1)
.applyQuaternion(this.object.quaternion, 'ZXY')
.setLength(this.movementSpeed / 50); // TODO: why 50 :S
this.object.position.add(tempVector3);
}
if (this.autoAlign && this.alpha !== 0) {
this.autoAlign = false;
this.align();
}
};
}();
// //debug
// window.addEventListener('click', (function(){
// this.align();
// }).bind(this));
this.align = function() {
tempVector3
.set(0, 0, -1)
.applyQuaternion( tempQuaternion.copy(this.orientationQuaternion).inverse(), 'ZXY' );
tempEuler.setFromQuaternion(
tempQuaternion.setFromRotationMatrix(
tempMatrix4.lookAt(tempVector3, v0, up)
)
);
tempEuler.set(0, tempEuler.y, 0);
this.alignQuaternion.setFromEuler(tempEuler);
};
this.connect = function() {
// run once on load
this.onScreenOrientationChangeEvent();
// window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent, false);
window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent, false);
this.freeze = false;
return this;
};
this.disconnect = function() {
this.freeze = true;
// window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent, false);
window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent, false);
};
};