Skip to content

Instantly share code, notes, and snippets.

@next-marianmoldovan
Created January 8, 2015 11:15
Show Gist options
  • Save next-marianmoldovan/7793dabf14f13bf84824 to your computer and use it in GitHub Desktop.
Save next-marianmoldovan/7793dabf14f13bf84824 to your computer and use it in GitHub Desktop.
THREE VR Controller for mobiles with DeviceOrientationControls
/**
* @author richt / http://richt.me
* @author WestLangley / http://github.com/WestLangley
*
* W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
*/
THREE.DeviceOrientationControls = function ( object, controls ) {
var scope = this;
this.controls = controls;
this.object = object;
this.object.rotation.reorder( "YXZ" );
this.freeze = true;
this.deviceOrientation = {};
this.screenOrientation = -90;
var onDeviceOrientationChangeEvent = function ( event ) {
scope.deviceOrientation = event;
};
var onScreenOrientationChangeEvent = function () {
console.log(scope.screenOrientation);
scope.screenOrientation = window.orientation || 0;
};
// The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
var setObjectQuaternion = function () {
var zee = new THREE.Vector3( 0, 0, 1 );
var euler = new THREE.Euler();
var q0 = new THREE.Quaternion();
var q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis
return function ( quaternion, alpha, beta, gamma, orient ) {
euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us
quaternion.setFromEuler( euler ); // orient the device
quaternion.multiply( q1 ); // camera looks out the back of the device, not the top
quaternion.multiply( q0.setFromAxisAngle( zee, - orient ) ); // adjust for screen orientation
}
}();
this.setObjectQuaternionX = function (quaternion, alpha, beta, gamma, orient) {
var zee = new THREE.Vector3( 0, 0, 1 );
var euler = new THREE.Euler();
var q0 = new THREE.Quaternion();
var q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis
euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us
quaternion.setFromEuler( euler ); // orient the device
quaternion.multiply( q1 ); // camera looks out the back of the device, not the top
quaternion.multiply( q0.setFromAxisAngle( zee, - orient ) ); // adjust for screen orientation
return quaternion;
};
this.connect = function() {
scope.screenOrientation = 90;
window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
scope.freeze = false;
};
this.disconnect = function() {
scope.freeze = true;
window.removeEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
window.removeEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
};
this.update = function () {
if ( scope.freeze ) return;
var alpha = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.alpha ) : 0; // Z
var beta = scope.deviceOrientation.beta ? THREE.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X'
var gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y''
var orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O
scope.object.quaternion = scope.setObjectQuaternionX( scope.object.quaternion, alpha, beta, gamma, orient ); scope.object.setRotationFromQuaternion(scope.object.quaternion);
};
};
/* globals THREE */
/**
* 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)
*/
(function() {
var deviceOrientation = {};
var screenOrientation = window.orientation || 0;
function onDeviceOrientationChangeEvent(evt) {
deviceOrientation = evt;
}
window.addEventListener('deviceorientation', onDeviceOrientationChangeEvent, false);
function getOrientation() {
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;
}
function onScreenOrientationChangeEvent() {
screenOrientation = getOrientation();
}
window.addEventListener('orientationchange', onScreenOrientationChangeEvent, false);
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.update = (function(delta) {
return function(delta) {
if (this.freeze) return;
// should not need this
//var orientation = getOrientation();
//if (orientation !== this.screenOrientation) {
//this.screenOrientation = orientation;
//this.autoAlign = true;
//}
this.alpha = deviceOrientation.gamma ?
THREE.Math.degToRad(deviceOrientation.alpha) : 0; // Z
this.beta = deviceOrientation.beta ?
THREE.Math.degToRad(deviceOrientation.beta) : 0; // X'
this.gamma = deviceOrientation.gamma ?
THREE.Math.degToRad(deviceOrientation.gamma) : 0; // Y''
this.orient = screenOrientation ?
THREE.Math.degToRad(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() {
this.freeze = false;
};
this.disconnect = function() {
this.freeze = true;
};
};
})();
if (window.DeviceOrientationEvent && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
console.error("Oriented device");
deviceControls = new THREE.DeviceOrientationControls(camera);
deviceControls.connect();
}
//Update | animate or whatever
if(deviceControls)
deviceControls.update();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment