DeviceOrientationControls.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /**
  2. * DeviceOrientationControls - applies device orientation on object rotation
  3. *
  4. * @param {Object} object - instance of THREE.Object3D
  5. * @constructor
  6. *
  7. * @author richt / http://richt.me
  8. * @author WestLangley / http://github.com/WestLangley
  9. * @author jonobr1 / http://jonobr1.com
  10. * @author arodic / http://aleksandarrodic.com
  11. * @author doug / http://github.com/doug
  12. *
  13. * W3C Device Orientation control
  14. * (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
  15. */
  16. THREE.DeviceOrientationControls = function(object) {
  17. this.object = object;
  18. this.object.rotation.reorder('YXZ');
  19. this.freeze = true;
  20. this.movementSpeed = 1.0;
  21. this.rollSpeed = 0.005;
  22. this.autoAlign = true;
  23. this.autoForward = false;
  24. this.alpha = 0;
  25. this.beta = 0;
  26. this.gamma = 0;
  27. this.orient = 0;
  28. this.alignQuaternion = new THREE.Quaternion();
  29. this.orientationQuaternion = new THREE.Quaternion();
  30. var quaternion = new THREE.Quaternion();
  31. var quaternionLerp = new THREE.Quaternion();
  32. var tempVector3 = new THREE.Vector3();
  33. var tempMatrix4 = new THREE.Matrix4();
  34. var tempEuler = new THREE.Euler(0, 0, 0, 'YXZ');
  35. var tempQuaternion = new THREE.Quaternion();
  36. var zee = new THREE.Vector3(0, 0, 1);
  37. var up = new THREE.Vector3(0, 1, 0);
  38. var v0 = new THREE.Vector3(0, 0, 0);
  39. var euler = new THREE.Euler();
  40. var q0 = new THREE.Quaternion(); // - PI/2 around the x-axis
  41. var q1 = new THREE.Quaternion(- Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
  42. this.deviceOrientation = {};
  43. this.screenOrientation = window.orientation || 0;
  44. this.onDeviceOrientationChangeEvent = (function(rawEvtData) {
  45. this.deviceOrientation = rawEvtData;
  46. }).bind(this);
  47. var getOrientation = function() {
  48. switch (window.screen.orientation || window.screen.mozOrientation) {
  49. case 'landscape-primary':
  50. return 90;
  51. case 'landscape-secondary':
  52. return -90;
  53. case 'portrait-secondary':
  54. return 180;
  55. case 'portrait-primary':
  56. return 0;
  57. }
  58. // this returns 90 if width is greater then height
  59. // and window orientation is undefined OR 0
  60. // if (!window.orientation && window.innerWidth > window.innerHeight)
  61. // return 90;
  62. return window.orientation || 0;
  63. };
  64. this.onScreenOrientationChangeEvent = (function() {
  65. this.screenOrientation = getOrientation();
  66. }).bind(this);
  67. this.update = function(delta) {
  68. return function() {
  69. if (this.freeze) return;
  70. // should not need this
  71. var orientation = getOrientation();
  72. if (orientation !== this.screenOrientation) {
  73. this.screenOrientation = orientation;
  74. this.autoAlign = true;
  75. }
  76. this.alpha = this.deviceOrientation.gamma ?
  77. THREE.Math.degToRad(this.deviceOrientation.alpha) : 0; // Z
  78. this.beta = this.deviceOrientation.beta ?
  79. THREE.Math.degToRad(this.deviceOrientation.beta) : 0; // X'
  80. this.gamma = this.deviceOrientation.gamma ?
  81. THREE.Math.degToRad(this.deviceOrientation.gamma) : 0; // Y''
  82. this.orient = this.screenOrientation ?
  83. THREE.Math.degToRad(this.screenOrientation) : 0; // O
  84. // The angles alpha, beta and gamma
  85. // form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
  86. // 'ZXY' for the device, but 'YXZ' for us
  87. euler.set(this.beta, this.alpha, - this.gamma, 'YXZ');
  88. quaternion.setFromEuler(euler);
  89. quaternionLerp.slerp(quaternion, 0.5); // interpolate
  90. // orient the device
  91. if (this.autoAlign) this.orientationQuaternion.copy(quaternion); // interpolation breaks the auto alignment
  92. else this.orientationQuaternion.copy(quaternionLerp);
  93. // camera looks out the back of the device, not the top
  94. this.orientationQuaternion.multiply(q1);
  95. // adjust for screen orientation
  96. this.orientationQuaternion.multiply(q0.setFromAxisAngle(zee, - this.orient));
  97. this.object.quaternion.copy(this.alignQuaternion);
  98. this.object.quaternion.multiply(this.orientationQuaternion);
  99. if (this.autoForward) {
  100. tempVector3
  101. .set(0, 0, -1)
  102. .applyQuaternion(this.object.quaternion, 'ZXY')
  103. .setLength(this.movementSpeed / 50); // TODO: why 50 :S
  104. this.object.position.add(tempVector3);
  105. }
  106. if (this.autoAlign && this.alpha !== 0) {
  107. this.autoAlign = false;
  108. this.align();
  109. }
  110. };
  111. }();
  112. // //debug
  113. // window.addEventListener('click', (function(){
  114. // this.align();
  115. // }).bind(this));
  116. this.align = function() {
  117. tempVector3
  118. .set(0, 0, -1)
  119. .applyQuaternion( tempQuaternion.copy(this.orientationQuaternion).inverse(), 'ZXY' );
  120. tempEuler.setFromQuaternion(
  121. tempQuaternion.setFromRotationMatrix(
  122. tempMatrix4.lookAt(tempVector3, v0, up)
  123. )
  124. );
  125. tempEuler.set(0, tempEuler.y, 0);
  126. this.alignQuaternion.setFromEuler(tempEuler);
  127. };
  128. this.connect = function() {
  129. // run once on load
  130. this.onScreenOrientationChangeEvent();
  131. // window.addEventListener('orientationchange', this.onScreenOrientationChangeEvent, false);
  132. window.addEventListener('deviceorientation', this.onDeviceOrientationChangeEvent, false);
  133. this.freeze = false;
  134. return this;
  135. };
  136. this.disconnect = function() {
  137. this.freeze = true;
  138. // window.removeEventListener('orientationchange', this.onScreenOrientationChangeEvent, false);
  139. window.removeEventListener('deviceorientation', this.onDeviceOrientationChangeEvent, false);
  140. };
  141. };