WebXRManager.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /**
  2. * @author mrdoob / http://mrdoob.com/
  3. */
  4. import { EventDispatcher } from '../../core/EventDispatcher.js';
  5. import { Group } from '../../objects/Group.js';
  6. import { Matrix4 } from '../../math/Matrix4.js';
  7. import { Vector4 } from '../../math/Vector4.js';
  8. import { ArrayCamera } from '../../cameras/ArrayCamera.js';
  9. import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
  10. import { WebGLAnimation } from '../webgl/WebGLAnimation.js';
  11. import { setProjectionFromUnion } from './WebVRUtils.js';
  12. function WebXRManager( renderer, gl ) {
  13. var scope = this;
  14. var session = null;
  15. // var framebufferScaleFactor = 1.0;
  16. var referenceSpace = null;
  17. var referenceSpaceType = 'local-floor';
  18. var pose = null;
  19. var controllers = [];
  20. var sortedInputSources = [];
  21. function isPresenting() {
  22. return session !== null && referenceSpace !== null;
  23. }
  24. //
  25. var cameraL = new PerspectiveCamera();
  26. cameraL.layers.enable( 1 );
  27. cameraL.viewport = new Vector4();
  28. var cameraR = new PerspectiveCamera();
  29. cameraR.layers.enable( 2 );
  30. cameraR.viewport = new Vector4();
  31. var cameraVR = new ArrayCamera( [ cameraL, cameraR ] );
  32. cameraVR.layers.enable( 1 );
  33. cameraVR.layers.enable( 2 );
  34. //
  35. this.enabled = false;
  36. this.getController = function ( id ) {
  37. var controller = controllers[ id ];
  38. if ( controller === undefined ) {
  39. controller = new Group();
  40. controller.matrixAutoUpdate = false;
  41. controller.visible = false;
  42. controllers[ id ] = controller;
  43. }
  44. return controller;
  45. };
  46. //
  47. function onSessionEvent( event ) {
  48. for ( var i = 0; i < controllers.length; i ++ ) {
  49. if ( sortedInputSources[ i ] === event.inputSource ) {
  50. controllers[ i ].dispatchEvent( { type: event.type } );
  51. }
  52. }
  53. }
  54. function onSessionEnd() {
  55. renderer.setFramebuffer( null );
  56. renderer.setRenderTarget( renderer.getRenderTarget() ); // Hack #15830
  57. animation.stop();
  58. scope.dispatchEvent( { type: 'sessionend' } );
  59. }
  60. function onRequestReferenceSpace( value ) {
  61. referenceSpace = value;
  62. animation.setContext( session );
  63. animation.start();
  64. scope.dispatchEvent( { type: 'sessionstart' } );
  65. }
  66. this.setFramebufferScaleFactor = function ( /* value */ ) {
  67. // framebufferScaleFactor = value;
  68. };
  69. this.setReferenceSpaceType = function ( value ) {
  70. referenceSpaceType = value;
  71. };
  72. this.getSession = function () {
  73. return session;
  74. };
  75. this.setSession = function ( value ) {
  76. session = value;
  77. if ( session !== null ) {
  78. session.addEventListener( 'select', onSessionEvent );
  79. session.addEventListener( 'selectstart', onSessionEvent );
  80. session.addEventListener( 'selectend', onSessionEvent );
  81. session.addEventListener( 'squeeze', onSessionEvent );
  82. session.addEventListener( 'squeezestart', onSessionEvent );
  83. session.addEventListener( 'squeezeend', onSessionEvent );
  84. session.addEventListener( 'end', onSessionEnd );
  85. // eslint-disable-next-line no-undef
  86. session.updateRenderState( { baseLayer: new XRWebGLLayer( session, gl ) } );
  87. session.requestReferenceSpace( referenceSpaceType ).then( onRequestReferenceSpace );
  88. //
  89. session.addEventListener( 'inputsourceschange', updateInputSources );
  90. updateInputSources();
  91. }
  92. };
  93. function updateInputSources() {
  94. for ( var i = 0; i < controllers.length; i ++ ) {
  95. sortedInputSources[ i ] = findInputSource( i );
  96. }
  97. }
  98. function findInputSource( id ) {
  99. var inputSources = session.inputSources;
  100. for ( var i = 0; i < inputSources.length; i ++ ) {
  101. var inputSource = inputSources[ i ];
  102. var handedness = inputSource.handedness;
  103. if ( id === 0 && ( handedness === 'none' || handedness === 'right' ) ) return inputSource;
  104. if ( id === 1 && ( handedness === 'left' ) ) return inputSource;
  105. }
  106. }
  107. //
  108. function updateCamera( camera, parent ) {
  109. if ( parent === null ) {
  110. camera.matrixWorld.copy( camera.matrix );
  111. } else {
  112. camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
  113. }
  114. camera.matrixWorldInverse.getInverse( camera.matrixWorld );
  115. }
  116. this.getCamera = function ( camera ) {
  117. if ( isPresenting() ) {
  118. var parent = camera.parent;
  119. var cameras = cameraVR.cameras;
  120. updateCamera( cameraVR, parent );
  121. for ( var i = 0; i < cameras.length; i ++ ) {
  122. updateCamera( cameras[ i ], parent );
  123. }
  124. // update camera and its children
  125. camera.matrixWorld.copy( cameraVR.matrixWorld );
  126. var children = camera.children;
  127. for ( var i = 0, l = children.length; i < l; i ++ ) {
  128. children[ i ].updateMatrixWorld( true );
  129. }
  130. setProjectionFromUnion( cameraVR, cameraL, cameraR );
  131. return cameraVR;
  132. }
  133. return camera;
  134. };
  135. this.isPresenting = isPresenting;
  136. // Animation Loop
  137. var onAnimationFrameCallback = null;
  138. function onAnimationFrame( time, frame ) {
  139. pose = frame.getViewerPose( referenceSpace );
  140. if ( pose !== null ) {
  141. var views = pose.views;
  142. var baseLayer = session.renderState.baseLayer;
  143. renderer.setFramebuffer( baseLayer.framebuffer );
  144. for ( var i = 0; i < views.length; i ++ ) {
  145. var view = views[ i ];
  146. var viewport = baseLayer.getViewport( view );
  147. var viewMatrix = view.transform.inverse.matrix;
  148. var camera = cameraVR.cameras[ i ];
  149. camera.matrix.fromArray( viewMatrix ).getInverse( camera.matrix );
  150. camera.projectionMatrix.fromArray( view.projectionMatrix );
  151. camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
  152. if ( i === 0 ) {
  153. cameraVR.matrix.copy( camera.matrix );
  154. }
  155. }
  156. }
  157. //
  158. for ( var i = 0; i < controllers.length; i ++ ) {
  159. var controller = controllers[ i ];
  160. var inputSource = sortedInputSources[ i ];
  161. if ( inputSource ) {
  162. var inputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );
  163. if ( inputPose !== null ) {
  164. controller.matrix.fromArray( inputPose.transform.matrix );
  165. controller.matrix.decompose( controller.position, controller.rotation, controller.scale );
  166. controller.visible = true;
  167. continue;
  168. }
  169. }
  170. controller.visible = false;
  171. }
  172. if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );
  173. }
  174. var animation = new WebGLAnimation();
  175. animation.setAnimationLoop( onAnimationFrame );
  176. this.setAnimationLoop = function ( callback ) {
  177. onAnimationFrameCallback = callback;
  178. };
  179. this.dispose = function () {};
  180. // DEPRECATED
  181. this.getStandingMatrix = function () {
  182. console.warn( 'THREE.WebXRManager: getStandingMatrix() is no longer needed.' );
  183. return new Matrix4();
  184. };
  185. this.getDevice = function () {
  186. console.warn( 'THREE.WebXRManager: getDevice() has been deprecated.' );
  187. };
  188. this.setDevice = function () {
  189. console.warn( 'THREE.WebXRManager: setDevice() has been deprecated.' );
  190. };
  191. this.setFrameOfReferenceType = function () {
  192. console.warn( 'THREE.WebXRManager: setFrameOfReferenceType() has been deprecated.' );
  193. };
  194. this.submitFrame = function () {};
  195. }
  196. Object.assign( WebXRManager.prototype, EventDispatcher.prototype );
  197. export { WebXRManager };