WebVRManager.js 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. */
  4. import { Group } from '../../objects/Group.js';
  5. import { Matrix4 } from '../../math/Matrix4.js';
  6. import { Vector3 } from '../../math/Vector3.js';
  7. import { Vector4 } from '../../math/Vector4.js';
  8. import { Quaternion } from '../../math/Quaternion.js';
  9. import { ArrayCamera } from '../../cameras/ArrayCamera.js';
  10. import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
  11. import { WebGLAnimation } from '../webgl/WebGLAnimation.js';
  12. function WebVRManager( renderer ) {
  13. var scope = this;
  14. var device = null;
  15. var frameData = null;
  16. var poseTarget = null;
  17. var controllers = [];
  18. var standingMatrix = new Matrix4();
  19. var standingMatrixInverse = new Matrix4();
  20. var options = { frameOfReferenceType: 'stage' };
  21. if ( typeof window !== 'undefined' && 'VRFrameData' in window ) {
  22. frameData = new window.VRFrameData();
  23. window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false );
  24. }
  25. var matrixWorldInverse = new Matrix4();
  26. var tempQuaternion = new Quaternion();
  27. var tempPosition = new Vector3();
  28. var cameraL = new PerspectiveCamera();
  29. cameraL.bounds = new Vector4( 0.0, 0.0, 0.5, 1.0 );
  30. cameraL.layers.enable( 1 );
  31. var cameraR = new PerspectiveCamera();
  32. cameraR.bounds = new Vector4( 0.5, 0.0, 0.5, 1.0 );
  33. cameraR.layers.enable( 2 );
  34. var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
  35. cameraVR.layers.enable( 1 );
  36. cameraVR.layers.enable( 2 );
  37. //
  38. function isPresenting() {
  39. return device !== null && device.isPresenting === true;
  40. }
  41. var currentSize, currentPixelRatio;
  42. function onVRDisplayPresentChange() {
  43. if ( isPresenting() ) {
  44. var eyeParameters = device.getEyeParameters( 'left' );
  45. var renderWidth = eyeParameters.renderWidth;
  46. var renderHeight = eyeParameters.renderHeight;
  47. currentPixelRatio = renderer.getPixelRatio();
  48. currentSize = renderer.getSize();
  49. renderer.setDrawingBufferSize( renderWidth * 2, renderHeight, 1 );
  50. animation.start();
  51. } else {
  52. if ( scope.enabled ) {
  53. renderer.setDrawingBufferSize( currentSize.width, currentSize.height, currentPixelRatio );
  54. }
  55. animation.stop();
  56. }
  57. }
  58. //
  59. var triggers = [];
  60. function findGamepad( id ) {
  61. var gamepads = navigator.getGamepads && navigator.getGamepads();
  62. for ( var i = 0, j = 0, l = gamepads.length; i < l; i ++ ) {
  63. var gamepad = gamepads[ i ];
  64. if ( gamepad && ( gamepad.id === 'Daydream Controller' ||
  65. gamepad.id === 'Gear VR Controller' || gamepad.id === 'Oculus Go Controller' ||
  66. gamepad.id === 'OpenVR Gamepad' || gamepad.id.startsWith( 'Oculus Touch' ) ||
  67. gamepad.id.startsWith( 'Spatial Controller' ) ) ) {
  68. if ( j === id ) return gamepad;
  69. j ++;
  70. }
  71. }
  72. }
  73. function updateControllers() {
  74. for ( var i = 0; i < controllers.length; i ++ ) {
  75. var controller = controllers[ i ];
  76. var gamepad = findGamepad( i );
  77. if ( gamepad !== undefined && gamepad.pose !== undefined ) {
  78. if ( gamepad.pose === null ) return;
  79. // Pose
  80. var pose = gamepad.pose;
  81. if ( pose.hasPosition === false ) controller.position.set( 0.2, - 0.6, - 0.05 );
  82. if ( pose.position !== null ) controller.position.fromArray( pose.position );
  83. if ( pose.orientation !== null ) controller.quaternion.fromArray( pose.orientation );
  84. controller.matrix.compose( controller.position, controller.quaternion, controller.scale );
  85. controller.matrix.premultiply( standingMatrix );
  86. controller.matrix.decompose( controller.position, controller.quaternion, controller.scale );
  87. controller.matrixWorldNeedsUpdate = true;
  88. controller.visible = true;
  89. // Trigger
  90. var buttonId = gamepad.id === 'Daydream Controller' ? 0 : 1;
  91. if ( triggers[ i ] !== gamepad.buttons[ buttonId ].pressed ) {
  92. triggers[ i ] = gamepad.buttons[ buttonId ].pressed;
  93. if ( triggers[ i ] === true ) {
  94. controller.dispatchEvent( { type: 'selectstart' } );
  95. } else {
  96. controller.dispatchEvent( { type: 'selectend' } );
  97. controller.dispatchEvent( { type: 'select' } );
  98. }
  99. }
  100. } else {
  101. controller.visible = false;
  102. }
  103. }
  104. }
  105. //
  106. this.enabled = false;
  107. this.getController = function ( id ) {
  108. var controller = controllers[ id ];
  109. if ( controller === undefined ) {
  110. controller = new Group();
  111. controller.matrixAutoUpdate = false;
  112. controller.visible = false;
  113. controllers[ id ] = controller;
  114. }
  115. return controller;
  116. };
  117. this.getDevice = function () {
  118. return device;
  119. };
  120. this.setDevice = function ( _device, _options ) {
  121. if ( _device !== undefined ) device = _device;
  122. if ( _options !== undefined ) options = _options;
  123. animation.setContext( _device );
  124. };
  125. this.setPoseTarget = function ( object ) {
  126. if ( object !== undefined ) poseTarget = object;
  127. };
  128. this.getCamera = function ( camera ) {
  129. if ( device === null ) {
  130. camera.position.set( 0, 1.6, 0 );
  131. return camera;
  132. }
  133. device.depthNear = camera.near;
  134. device.depthFar = camera.far;
  135. device.getFrameData( frameData );
  136. //
  137. if ( options.frameOfReferenceType === 'stage' ) {
  138. var stageParameters = device.stageParameters;
  139. if ( stageParameters ) {
  140. standingMatrix.fromArray( stageParameters.sittingToStandingTransform );
  141. } else {
  142. standingMatrix.makeTranslation( 0, 1.6, 0 );
  143. }
  144. }
  145. var pose = frameData.pose;
  146. var poseObject = poseTarget !== null ? poseTarget : camera;
  147. // We want to manipulate poseObject by its position and quaternion components since users may rely on them.
  148. poseObject.matrix.copy( standingMatrix );
  149. poseObject.matrix.decompose( poseObject.position, poseObject.quaternion, poseObject.scale );
  150. if ( pose.orientation !== null ) {
  151. tempQuaternion.fromArray( pose.orientation );
  152. poseObject.quaternion.multiply( tempQuaternion );
  153. }
  154. if ( pose.position !== null ) {
  155. tempQuaternion.setFromRotationMatrix( standingMatrix );
  156. tempPosition.fromArray( pose.position );
  157. tempPosition.applyQuaternion( tempQuaternion );
  158. poseObject.position.add( tempPosition );
  159. }
  160. poseObject.updateMatrixWorld();
  161. if ( device.isPresenting === false ) return camera;
  162. //
  163. cameraL.near = camera.near;
  164. cameraR.near = camera.near;
  165. cameraL.far = camera.far;
  166. cameraR.far = camera.far;
  167. cameraVR.matrixWorld.copy( camera.matrixWorld );
  168. cameraVR.matrixWorldInverse.copy( camera.matrixWorldInverse );
  169. cameraL.matrixWorldInverse.fromArray( frameData.leftViewMatrix );
  170. cameraR.matrixWorldInverse.fromArray( frameData.rightViewMatrix );
  171. // TODO (mrdoob) Double check this code
  172. standingMatrixInverse.getInverse( standingMatrix );
  173. if ( options.frameOfReferenceType === 'stage' ) {
  174. cameraL.matrixWorldInverse.multiply( standingMatrixInverse );
  175. cameraR.matrixWorldInverse.multiply( standingMatrixInverse );
  176. }
  177. var parent = poseObject.parent;
  178. if ( parent !== null ) {
  179. matrixWorldInverse.getInverse( parent.matrixWorld );
  180. cameraL.matrixWorldInverse.multiply( matrixWorldInverse );
  181. cameraR.matrixWorldInverse.multiply( matrixWorldInverse );
  182. }
  183. // envMap and Mirror needs camera.matrixWorld
  184. cameraL.matrixWorld.getInverse( cameraL.matrixWorldInverse );
  185. cameraR.matrixWorld.getInverse( cameraR.matrixWorldInverse );
  186. cameraL.projectionMatrix.fromArray( frameData.leftProjectionMatrix );
  187. cameraR.projectionMatrix.fromArray( frameData.rightProjectionMatrix );
  188. // HACK (mrdoob)
  189. // https://github.com/w3c/webvr/issues/203
  190. cameraVR.projectionMatrix.copy( cameraL.projectionMatrix );
  191. //
  192. var layers = device.getLayers();
  193. if ( layers.length ) {
  194. var layer = layers[ 0 ];
  195. if ( layer.leftBounds !== null && layer.leftBounds.length === 4 ) {
  196. cameraL.bounds.fromArray( layer.leftBounds );
  197. }
  198. if ( layer.rightBounds !== null && layer.rightBounds.length === 4 ) {
  199. cameraR.bounds.fromArray( layer.rightBounds );
  200. }
  201. }
  202. updateControllers();
  203. return cameraVR;
  204. };
  205. this.getStandingMatrix = function () {
  206. return standingMatrix;
  207. };
  208. this.isPresenting = isPresenting;
  209. // Animation Loop
  210. var animation = new WebGLAnimation();
  211. this.setAnimationLoop = function ( callback ) {
  212. animation.setAnimationLoop( callback );
  213. };
  214. this.submitFrame = function () {
  215. if ( isPresenting() ) device.submitFrame();
  216. };
  217. this.dispose = function () {
  218. if ( typeof window !== 'undefined' ) {
  219. window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange );
  220. }
  221. };
  222. }
  223. export { WebVRManager };
粤ICP备19079148号