XRHandModelFactory.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. import {
  2. Object3D
  3. } from 'three';
  4. import {
  5. XRHandPrimitiveModel
  6. } from './XRHandPrimitiveModel.js';
  7. import {
  8. XRHandMeshModel
  9. } from './XRHandMeshModel.js';
  10. /**
  11. * Represents a XR hand model.
  12. *
  13. * @augments Object3D
  14. */
  15. class XRHandModel extends Object3D {
  16. /**
  17. * Constructs a new XR hand model.
  18. *
  19. * @param {Group} controller - The hand controller.
  20. */
  21. constructor( controller ) {
  22. super();
  23. /**
  24. * The hand controller.
  25. *
  26. * @type {Group}
  27. */
  28. this.controller = controller;
  29. /**
  30. * The motion controller.
  31. *
  32. * @type {?MotionController}
  33. * @default null
  34. */
  35. this.motionController = null;
  36. /**
  37. * The controller's environment map.
  38. *
  39. * @type {?Texture}
  40. * @default null
  41. */
  42. this.envMap = null;
  43. /**
  44. * The model mesh.
  45. *
  46. * @type {Mesh}
  47. * @default null
  48. */
  49. this.mesh = null;
  50. }
  51. /**
  52. * Overwritten with a custom implementation. Makes sure the motion controller updates the mesh.
  53. *
  54. * @param {boolean} [force=false] - When set to `true`, a recomputation of world matrices is forced even
  55. * when {@link Object3D#matrixWorldAutoUpdate} is set to `false`.
  56. */
  57. updateMatrixWorld( force ) {
  58. super.updateMatrixWorld( force );
  59. if ( this.motionController ) {
  60. this.motionController.updateMesh();
  61. }
  62. }
  63. }
  64. /**
  65. * Similar to {@link XRControllerModelFactory}, this class allows to create hand models
  66. * for WebXR controllers that can be added as a visual representation to your scene.
  67. *
  68. * ```js
  69. * const handModelFactory = new XRHandModelFactory();
  70. *
  71. * const hand = renderer.xr.getHand( 0 );
  72. * hand.add( handModelFactory.createHandModel( hand ) );
  73. * scene.add( hand );
  74. * ```
  75. */
  76. class XRHandModelFactory {
  77. /**
  78. * Constructs a new XR hand model factory.
  79. *
  80. * @param {?GLTFLoader} [gltfLoader=null] - A glTF loader that is used to load hand models.
  81. * @param {?Function} [onLoad=null] - A callback that is executed when a hand model has been loaded.
  82. */
  83. constructor( gltfLoader = null, onLoad = null ) {
  84. /**
  85. * A glTF loader that is used to load hand models.
  86. *
  87. * @type {?GLTFLoader}
  88. * @default null
  89. */
  90. this.gltfLoader = gltfLoader;
  91. /**
  92. * The path to the model repository.
  93. *
  94. * @type {?string}
  95. * @default null
  96. */
  97. this.path = null;
  98. /**
  99. * A callback that is executed when a hand model has been loaded.
  100. *
  101. * @type {?Function}
  102. * @default null
  103. */
  104. this.onLoad = onLoad;
  105. }
  106. /**
  107. * Sets the path to the hand model repository.
  108. *
  109. * @param {string} path - The path to set.
  110. * @return {XRHandModelFactory} A reference to this instance.
  111. */
  112. setPath( path ) {
  113. this.path = path;
  114. return this;
  115. }
  116. /**
  117. * Creates a controller model for the given WebXR hand controller.
  118. *
  119. * @param {Group} controller - The hand controller.
  120. * @param {('spheres'|'boxes'|'mesh')} [profile] - The model profile that defines the model type.
  121. * @return {XRHandModel} The XR hand model.
  122. */
  123. createHandModel( controller, profile ) {
  124. const handModel = new XRHandModel( controller );
  125. controller.addEventListener( 'connected', ( event ) => {
  126. const xrInputSource = event.data;
  127. if ( xrInputSource.hand && ! handModel.motionController ) {
  128. handModel.xrInputSource = xrInputSource;
  129. // @todo Detect profile if not provided
  130. if ( profile === undefined || profile === 'spheres' ) {
  131. handModel.motionController = new XRHandPrimitiveModel( handModel, controller, this.path, xrInputSource.handedness, { primitive: 'sphere' } );
  132. } else if ( profile === 'boxes' ) {
  133. handModel.motionController = new XRHandPrimitiveModel( handModel, controller, this.path, xrInputSource.handedness, { primitive: 'box' } );
  134. } else if ( profile === 'mesh' ) {
  135. handModel.motionController = new XRHandMeshModel( handModel, controller, this.path, xrInputSource.handedness, this.gltfLoader, this.onLoad );
  136. }
  137. }
  138. controller.visible = true;
  139. } );
  140. controller.addEventListener( 'disconnected', () => {
  141. controller.visible = false;
  142. // handModel.motionController = null;
  143. // handModel.remove( scene );
  144. // scene = null;
  145. } );
  146. return handModel;
  147. }
  148. }
  149. export { XRHandModelFactory };
粤ICP备19079148号