@onerjs/core 8.55.9 → 8.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/AudioV2/webAudio/webAudioEngine.d.ts +7 -0
  2. package/AudioV2/webAudio/webAudioEngine.js +6 -5
  3. package/AudioV2/webAudio/webAudioEngine.js.map +1 -1
  4. package/Culling/Helper/boundingInfoHelper.js +8 -4
  5. package/Culling/Helper/boundingInfoHelper.js.map +1 -1
  6. package/Engines/AbstractEngine/abstractEngine.textureLoaders.d.ts +5 -1
  7. package/Engines/AbstractEngine/abstractEngine.textureLoaders.js +7 -3
  8. package/Engines/AbstractEngine/abstractEngine.textureLoaders.js.map +1 -1
  9. package/Engines/AbstractEngine/abstractEngine.textureLoaders.pure.d.ts +6 -0
  10. package/Engines/AbstractEngine/abstractEngine.textureLoaders.pure.js +16 -0
  11. package/Engines/AbstractEngine/abstractEngine.textureLoaders.pure.js.map +1 -0
  12. package/Engines/AbstractEngine/pure.d.ts +1 -0
  13. package/Engines/AbstractEngine/pure.js +1 -0
  14. package/Engines/AbstractEngine/pure.js.map +1 -1
  15. package/Engines/IDrawContext.d.ts +2 -0
  16. package/Engines/IDrawContext.js.map +1 -1
  17. package/Engines/WebGPU/webgpuDrawContext.d.ts +8 -0
  18. package/Engines/WebGPU/webgpuDrawContext.js +15 -0
  19. package/Engines/WebGPU/webgpuDrawContext.js.map +1 -1
  20. package/Engines/abstractEngine.pure.js +2 -2
  21. package/Engines/abstractEngine.pure.js.map +1 -1
  22. package/Engines/engine.d.ts +11 -3
  23. package/Engines/webgpuEngine.d.ts +1 -0
  24. package/Engines/webgpuEngine.js +1 -0
  25. package/Engines/webgpuEngine.js.map +1 -1
  26. package/Engines/webgpuEngine.pure.d.ts +10 -0
  27. package/Engines/webgpuEngine.pure.js +15 -1
  28. package/Engines/webgpuEngine.pure.js.map +1 -1
  29. package/FrameGraph/Tasks/Rendering/iblShadowsRendererTask.pure.js +2 -5
  30. package/FrameGraph/Tasks/Rendering/iblShadowsRendererTask.pure.js.map +1 -1
  31. package/Materials/Node/Blocks/Fragment/imageProcessingBlock.pure.js +2 -0
  32. package/Materials/Node/Blocks/Fragment/imageProcessingBlock.pure.js.map +1 -1
  33. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js +1 -0
  34. package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.pure.js.map +1 -1
  35. package/Materials/Node/Blocks/powBlock.pure.js +2 -1
  36. package/Materials/Node/Blocks/powBlock.pure.js.map +1 -1
  37. package/Materials/Node/Blocks/triPlanarBlock.pure.js +14 -12
  38. package/Materials/Node/Blocks/triPlanarBlock.pure.js.map +1 -1
  39. package/Materials/Node/nodeMaterial.pure.d.ts +1 -0
  40. package/Materials/Node/nodeMaterialBuildState.d.ts +3 -3
  41. package/Materials/PBR/openpbrMaterial.pure.d.ts +1 -0
  42. package/Materials/PBR/pbrBaseMaterial.pure.d.ts +1 -0
  43. package/Materials/Textures/index.d.ts +1 -0
  44. package/Materials/Textures/index.js +1 -0
  45. package/Materials/Textures/index.js.map +1 -1
  46. package/Materials/drawWrapper.js +3 -0
  47. package/Materials/drawWrapper.js.map +1 -1
  48. package/Materials/imageProcessingConfiguration.defines.d.ts +3 -0
  49. package/Materials/imageProcessingConfiguration.defines.js +2 -0
  50. package/Materials/imageProcessingConfiguration.defines.js.map +1 -1
  51. package/Materials/imageProcessingConfiguration.functions.js +3 -0
  52. package/Materials/imageProcessingConfiguration.functions.js.map +1 -1
  53. package/Materials/imageProcessingConfiguration.pure.d.ts +58 -0
  54. package/Materials/imageProcessingConfiguration.pure.js +123 -2
  55. package/Materials/imageProcessingConfiguration.pure.js.map +1 -1
  56. package/Materials/standardMaterial.pure.d.ts +1 -0
  57. package/Materials/uniformBuffer.d.ts +29 -0
  58. package/Materials/uniformBuffer.js +146 -0
  59. package/Materials/uniformBuffer.js.map +1 -1
  60. package/Maths/colorTemperature.functions.d.ts +29 -0
  61. package/Maths/colorTemperature.functions.js +196 -0
  62. package/Maths/colorTemperature.functions.js.map +1 -0
  63. package/Maths/index.d.ts +1 -0
  64. package/Maths/index.js +1 -0
  65. package/Maths/index.js.map +1 -1
  66. package/Maths/pure.d.ts +1 -0
  67. package/Maths/pure.js +1 -0
  68. package/Maths/pure.js.map +1 -1
  69. package/Misc/observable.pure.js +1 -3
  70. package/Misc/observable.pure.js.map +1 -1
  71. package/Misc/tools.pure.js +1 -1
  72. package/Misc/tools.pure.js.map +1 -1
  73. package/PostProcesses/imageProcessingPostProcess.d.ts +41 -1
  74. package/PostProcesses/imageProcessingPostProcess.js +41 -1
  75. package/PostProcesses/imageProcessingPostProcess.js.map +1 -1
  76. package/PostProcesses/thinImageProcessingPostProcess.d.ts +50 -0
  77. package/PostProcesses/thinImageProcessingPostProcess.js +65 -0
  78. package/PostProcesses/thinImageProcessingPostProcess.js.map +1 -1
  79. package/Rendering/IBLShadows/iblShadowsMaterialCompatibility.pure.d.ts +12 -0
  80. package/Rendering/IBLShadows/iblShadowsMaterialCompatibility.pure.js +22 -0
  81. package/Rendering/IBLShadows/iblShadowsMaterialCompatibility.pure.js.map +1 -0
  82. package/Rendering/IBLShadows/iblShadowsPluginMaterial.pure.d.ts +1 -0
  83. package/Rendering/IBLShadows/iblShadowsPluginMaterial.pure.js +39 -0
  84. package/Rendering/IBLShadows/iblShadowsPluginMaterial.pure.js.map +1 -1
  85. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js +2 -4
  86. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js.map +1 -1
  87. package/Rendering/IBLShadows/pure.d.ts +1 -0
  88. package/Rendering/IBLShadows/pure.js +1 -0
  89. package/Rendering/IBLShadows/pure.js.map +1 -1
  90. package/Rendering/fluidRenderer/fluidRenderingObject.d.ts +11 -0
  91. package/Rendering/fluidRenderer/fluidRenderingObject.js +36 -14
  92. package/Rendering/fluidRenderer/fluidRenderingObject.js.map +1 -1
  93. package/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles.d.ts +5 -0
  94. package/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles.js +16 -3
  95. package/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles.js.map +1 -1
  96. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.d.ts +5 -0
  97. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.js +12 -0
  98. package/Rendering/fluidRenderer/fluidRenderingObjectParticleSystem.js.map +1 -1
  99. package/Rendering/iblCdfGenerator.js +10 -1
  100. package/Rendering/iblCdfGenerator.js.map +1 -1
  101. package/Shaders/ShadersInclude/hdrFilteringFunctions.js +1 -1
  102. package/Shaders/ShadersInclude/hdrFilteringFunctions.js.map +1 -1
  103. package/Shaders/ShadersInclude/helperFunctions.js +2 -2
  104. package/Shaders/ShadersInclude/helperFunctions.js.map +1 -1
  105. package/Shaders/ShadersInclude/imageProcessingDeclaration.js +3 -0
  106. package/Shaders/ShadersInclude/imageProcessingDeclaration.js.map +1 -1
  107. package/Shaders/ShadersInclude/imageProcessingFunctions.js +3 -0
  108. package/Shaders/ShadersInclude/imageProcessingFunctions.js.map +1 -1
  109. package/Shaders/ShadersInclude/openpbrDirectLighting.js +34 -4
  110. package/Shaders/ShadersInclude/openpbrDirectLighting.js.map +1 -1
  111. package/Shaders/ShadersInclude/openpbrIblFunctions.js +8 -2
  112. package/Shaders/ShadersInclude/openpbrIblFunctions.js.map +1 -1
  113. package/Shaders/ShadersInclude/pbrDirectLightingFunctions.js +5 -0
  114. package/Shaders/ShadersInclude/pbrDirectLightingFunctions.js.map +1 -1
  115. package/Shaders/fluidRenderingParticleDepth.vertex.js +7 -1
  116. package/Shaders/fluidRenderingParticleDepth.vertex.js.map +1 -1
  117. package/Shaders/fluidRenderingParticleDiffuse.vertex.js +7 -1
  118. package/Shaders/fluidRenderingParticleDiffuse.vertex.js.map +1 -1
  119. package/Shaders/fluidRenderingParticleThickness.vertex.js +7 -1
  120. package/Shaders/fluidRenderingParticleThickness.vertex.js.map +1 -1
  121. package/ShadersWGSL/ShadersInclude/imageProcessingDeclaration.js +3 -0
  122. package/ShadersWGSL/ShadersInclude/imageProcessingDeclaration.js.map +1 -1
  123. package/ShadersWGSL/ShadersInclude/imageProcessingFunctions.js +3 -0
  124. package/ShadersWGSL/ShadersInclude/imageProcessingFunctions.js.map +1 -1
  125. package/ShadersWGSL/ShadersInclude/openpbrDirectLighting.js +35 -5
  126. package/ShadersWGSL/ShadersInclude/openpbrDirectLighting.js.map +1 -1
  127. package/ShadersWGSL/ShadersInclude/openpbrDirectLightingInit.js +1 -1
  128. package/ShadersWGSL/ShadersInclude/openpbrDirectLightingInit.js.map +1 -1
  129. package/ShadersWGSL/ShadersInclude/openpbrIblFunctions.js +8 -2
  130. package/ShadersWGSL/ShadersInclude/openpbrIblFunctions.js.map +1 -1
  131. package/ShadersWGSL/ShadersInclude/pbrDirectLightingFunctions.js +5 -0
  132. package/ShadersWGSL/ShadersInclude/pbrDirectLightingFunctions.js.map +1 -1
  133. package/ShadersWGSL/fluidRenderingParticleDepth.vertex.js +16 -4
  134. package/ShadersWGSL/fluidRenderingParticleDepth.vertex.js.map +1 -1
  135. package/ShadersWGSL/fluidRenderingParticleDiffuse.vertex.js +15 -3
  136. package/ShadersWGSL/fluidRenderingParticleDiffuse.vertex.js.map +1 -1
  137. package/ShadersWGSL/fluidRenderingParticleThickness.vertex.js +15 -3
  138. package/ShadersWGSL/fluidRenderingParticleThickness.vertex.js.map +1 -1
  139. package/XR/features/Layers/WebXRCompositionLayer.d.ts +52 -0
  140. package/XR/features/Layers/WebXRCompositionLayer.js +80 -0
  141. package/XR/features/Layers/WebXRCompositionLayer.js.map +1 -1
  142. package/XR/features/WebXRControllerPointerSelection.pure.js +2 -1
  143. package/XR/features/WebXRControllerPointerSelection.pure.js.map +1 -1
  144. package/XR/features/WebXRControllerTeleportation.pure.js +2 -1
  145. package/XR/features/WebXRControllerTeleportation.pure.js.map +1 -1
  146. package/XR/features/WebXRDepthSensing.pure.d.ts +21 -0
  147. package/XR/features/WebXRDepthSensing.pure.js +42 -0
  148. package/XR/features/WebXRDepthSensing.pure.js.map +1 -1
  149. package/XR/features/WebXRHandTracking.pure.js +2 -0
  150. package/XR/features/WebXRHandTracking.pure.js.map +1 -1
  151. package/XR/features/WebXRLayers.pure.d.ts +12 -0
  152. package/XR/features/WebXRLayers.pure.js +31 -1
  153. package/XR/features/WebXRLayers.pure.js.map +1 -1
  154. package/XR/features/WebXRTrackedSources.d.ts +5 -0
  155. package/XR/features/WebXRTrackedSources.js +8 -0
  156. package/XR/features/WebXRTrackedSources.js.map +1 -0
  157. package/XR/features/WebXRTrackedSources.pure.d.ts +70 -0
  158. package/XR/features/WebXRTrackedSources.pure.js +153 -0
  159. package/XR/features/WebXRTrackedSources.pure.js.map +1 -0
  160. package/XR/features/index.d.ts +1 -0
  161. package/XR/features/index.js +1 -0
  162. package/XR/features/index.js.map +1 -1
  163. package/XR/features/pure.d.ts +1 -0
  164. package/XR/features/pure.js +1 -0
  165. package/XR/features/pure.js.map +1 -1
  166. package/XR/motionController/webXRAbstractMotionController.d.ts +53 -1
  167. package/XR/motionController/webXRAbstractMotionController.js +61 -0
  168. package/XR/motionController/webXRAbstractMotionController.js.map +1 -1
  169. package/XR/webXRDefaultExperience.js +8 -4
  170. package/XR/webXRDefaultExperience.js.map +1 -1
  171. package/XR/webXRExperienceHelper.js +86 -44
  172. package/XR/webXRExperienceHelper.js.map +1 -1
  173. package/XR/webXRFeaturesManager.d.ts +9 -0
  174. package/XR/webXRFeaturesManager.js +4 -0
  175. package/XR/webXRFeaturesManager.js.map +1 -1
  176. package/XR/webXRGraphicsBinding.d.ts +29 -0
  177. package/XR/webXRGraphicsBinding.js +40 -0
  178. package/XR/webXRGraphicsBinding.js.map +1 -1
  179. package/XR/webXRInputSource.js +1 -1
  180. package/XR/webXRInputSource.js.map +1 -1
  181. package/XR/webXRLayerWrapper.d.ts +7 -5
  182. package/XR/webXRLayerWrapper.js +10 -7
  183. package/XR/webXRLayerWrapper.js.map +1 -1
  184. package/XR/webXRSessionManager.d.ts +45 -0
  185. package/XR/webXRSessionManager.js +174 -29
  186. package/XR/webXRSessionManager.js.map +1 -1
  187. package/package.json +1 -1
@@ -0,0 +1,153 @@
1
+ /** This file must only contain pure code and pure imports */
2
+ import { Observable } from "../../Misc/observable.pure.js";
3
+ import { WebXRFeatureName, WebXRFeaturesManager } from "../webXRFeaturesManager.js";
4
+ import { WebXRAbstractFeature } from "./WebXRAbstractFeature.js";
5
+ function IsTrackedSourcesSession(session) {
6
+ return "trackedSources" in session;
7
+ }
8
+ /**
9
+ * Exposes input sources that the XR runtime continues tracking while they are not active input sources.
10
+ *
11
+ * Tracked sources are intentionally kept separate from `XRSession.inputSources` and Babylon's normal
12
+ * WebXR input/controller pipeline.
13
+ * @see https://immersive-web.github.io/webxr/#dom-xrsession-trackedsources
14
+ * @see https://playground.babylonjs.com/#JRBQVL#0
15
+ */
16
+ export class WebXRTrackedSources extends WebXRAbstractFeature {
17
+ /**
18
+ * Creates a WebXR tracked sources feature.
19
+ * @param _xrSessionManager The WebXR session manager.
20
+ */
21
+ constructor(_xrSessionManager) {
22
+ super(_xrSessionManager);
23
+ this._trackedSources = [];
24
+ this._trackedSourcesSession = null;
25
+ /**
26
+ * Notifies observers when a source enters the feature's current tracked source set.
27
+ */
28
+ this.onTrackedSourceAddedObservable = new Observable();
29
+ /**
30
+ * Notifies observers when a source leaves the feature's current tracked source set, including on detach.
31
+ */
32
+ this.onTrackedSourceRemovedObservable = new Observable();
33
+ this._onTrackedSourcesChanged = () => {
34
+ this._synchronizeTrackedSources();
35
+ };
36
+ this.xrNativeFeatureName = "tracked-sources";
37
+ }
38
+ /**
39
+ * Gets a copy of the sources currently reported by `XRSession.trackedSources`.
40
+ *
41
+ * These sources are not added to `XRSession.inputSources` or Babylon's controller collection.
42
+ */
43
+ get trackedSources() {
44
+ return this._trackedSources.slice();
45
+ }
46
+ /**
47
+ * Attaches the feature to the active XR session.
48
+ * @param force Whether to reattach when the feature is already attached.
49
+ * @returns `true` when attachment succeeds; otherwise `false`.
50
+ */
51
+ attach(force) {
52
+ const session = this._xrSessionManager.session;
53
+ if (!session || !IsTrackedSourcesSession(session)) {
54
+ return this._disableAutoAttach("XRSession.trackedSources is not supported by this XR runtime.");
55
+ }
56
+ if (!super.attach(force)) {
57
+ return false;
58
+ }
59
+ this._trackedSourcesSession = session;
60
+ session.addEventListener("trackedsourceschange", this._onTrackedSourcesChanged);
61
+ this._synchronizeTrackedSources();
62
+ return true;
63
+ }
64
+ /**
65
+ * Detaches the feature and clears its tracked source state.
66
+ * @returns `true` when detachment succeeds; otherwise `false`.
67
+ */
68
+ detach() {
69
+ if (!super.detach()) {
70
+ return false;
71
+ }
72
+ this._trackedSourcesSession?.removeEventListener("trackedsourceschange", this._onTrackedSourcesChanged);
73
+ this._trackedSourcesSession = null;
74
+ this._clearTrackedSources();
75
+ return true;
76
+ }
77
+ /**
78
+ * Disposes the feature and clears its observables.
79
+ */
80
+ dispose() {
81
+ super.dispose();
82
+ this.onTrackedSourceAddedObservable.clear();
83
+ this.onTrackedSourceRemovedObservable.clear();
84
+ }
85
+ _onXRFrame() { }
86
+ _synchronizeTrackedSources() {
87
+ const session = this._trackedSourcesSession;
88
+ if (!this.attached || !session) {
89
+ return;
90
+ }
91
+ for (let index = 0; index < this._trackedSources.length;) {
92
+ const trackedSource = this._trackedSources[index];
93
+ let isStillTracked = false;
94
+ for (const nativeTrackedSource of session.trackedSources) {
95
+ if (nativeTrackedSource === trackedSource) {
96
+ isStillTracked = true;
97
+ break;
98
+ }
99
+ }
100
+ if (isStillTracked) {
101
+ index++;
102
+ }
103
+ else {
104
+ this._trackedSources.splice(index, 1);
105
+ this.onTrackedSourceRemovedObservable.notifyObservers(trackedSource);
106
+ }
107
+ }
108
+ for (const trackedSource of session.trackedSources) {
109
+ if (this._trackedSources.indexOf(trackedSource) === -1) {
110
+ this._trackedSources.push(trackedSource);
111
+ this.onTrackedSourceAddedObservable.notifyObservers(trackedSource);
112
+ }
113
+ }
114
+ let index = 0;
115
+ for (const trackedSource of session.trackedSources) {
116
+ this._trackedSources[index++] = trackedSource;
117
+ }
118
+ }
119
+ _clearTrackedSources() {
120
+ while (this._trackedSources.length > 0) {
121
+ const trackedSource = this._trackedSources.shift();
122
+ if (trackedSource) {
123
+ this.onTrackedSourceRemovedObservable.notifyObservers(trackedSource);
124
+ }
125
+ }
126
+ }
127
+ }
128
+ /**
129
+ * The module's name.
130
+ */
131
+ WebXRTrackedSources.Name = WebXRFeatureName.TRACKED_SOURCES;
132
+ /**
133
+ * The Babylon version of this module.
134
+ *
135
+ * This number does not correspond to the WebXR specification version.
136
+ */
137
+ WebXRTrackedSources.Version = 1;
138
+ let _Registered = false;
139
+ /**
140
+ * Registers the WebXR tracked sources feature.
141
+ *
142
+ * Safe to call multiple times; only the first call has an effect.
143
+ */
144
+ export function RegisterWebXRTrackedSources() {
145
+ if (_Registered) {
146
+ return;
147
+ }
148
+ _Registered = true;
149
+ WebXRFeaturesManager.AddWebXRFeature(WebXRTrackedSources.Name, (xrSessionManager) => {
150
+ return () => new WebXRTrackedSources(xrSessionManager);
151
+ }, WebXRTrackedSources.Version);
152
+ }
153
+ //# sourceMappingURL=WebXRTrackedSources.pure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebXRTrackedSources.pure.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/features/WebXRTrackedSources.pure.ts"],"names":[],"mappings":"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","sourcesContent":["/** This file must only contain pure code and pure imports */\n\nimport { Observable } from \"../../Misc/observable.pure\";\nimport { WebXRFeatureName, WebXRFeaturesManager } from \"../webXRFeaturesManager\";\nimport { type WebXRSessionManager } from \"../webXRSessionManager\";\nimport { WebXRAbstractFeature } from \"./WebXRAbstractFeature\";\n\ninterface IWebXRTrackedSourcesSession extends XRSession {\n readonly trackedSources: XRInputSourceArray;\n}\n\nfunction IsTrackedSourcesSession(session: XRSession): session is IWebXRTrackedSourcesSession {\n return \"trackedSources\" in session;\n}\n\n/**\n * Exposes input sources that the XR runtime continues tracking while they are not active input sources.\n *\n * Tracked sources are intentionally kept separate from `XRSession.inputSources` and Babylon's normal\n * WebXR input/controller pipeline.\n * @see https://immersive-web.github.io/webxr/#dom-xrsession-trackedsources\n * @see https://playground.babylonjs.com/#JRBQVL#0\n */\nexport class WebXRTrackedSources extends WebXRAbstractFeature {\n private readonly _trackedSources: XRInputSource[] = [];\n private _trackedSourcesSession: IWebXRTrackedSourcesSession | null = null;\n\n /**\n * The module's name.\n */\n public static readonly Name = WebXRFeatureName.TRACKED_SOURCES;\n\n /**\n * The Babylon version of this module.\n *\n * This number does not correspond to the WebXR specification version.\n */\n public static readonly Version = 1;\n\n /**\n * Notifies observers when a source enters the feature's current tracked source set.\n */\n public readonly onTrackedSourceAddedObservable: Observable<XRInputSource> = new Observable();\n\n /**\n * Notifies observers when a source leaves the feature's current tracked source set, including on detach.\n */\n public readonly onTrackedSourceRemovedObservable: Observable<XRInputSource> = new Observable();\n\n /**\n * Creates a WebXR tracked sources feature.\n * @param _xrSessionManager The WebXR session manager.\n */\n constructor(_xrSessionManager: WebXRSessionManager) {\n super(_xrSessionManager);\n this.xrNativeFeatureName = \"tracked-sources\";\n }\n\n /**\n * Gets a copy of the sources currently reported by `XRSession.trackedSources`.\n *\n * These sources are not added to `XRSession.inputSources` or Babylon's controller collection.\n */\n public get trackedSources(): ReadonlyArray<XRInputSource> {\n return this._trackedSources.slice();\n }\n\n /**\n * Attaches the feature to the active XR session.\n * @param force Whether to reattach when the feature is already attached.\n * @returns `true` when attachment succeeds; otherwise `false`.\n */\n public override attach(force?: boolean): boolean {\n const session = this._xrSessionManager.session;\n if (!session || !IsTrackedSourcesSession(session)) {\n return this._disableAutoAttach(\"XRSession.trackedSources is not supported by this XR runtime.\");\n }\n\n if (!super.attach(force)) {\n return false;\n }\n\n this._trackedSourcesSession = session;\n session.addEventListener(\"trackedsourceschange\", this._onTrackedSourcesChanged);\n this._synchronizeTrackedSources();\n return true;\n }\n\n /**\n * Detaches the feature and clears its tracked source state.\n * @returns `true` when detachment succeeds; otherwise `false`.\n */\n public override detach(): boolean {\n if (!super.detach()) {\n return false;\n }\n\n this._trackedSourcesSession?.removeEventListener(\"trackedsourceschange\", this._onTrackedSourcesChanged);\n this._trackedSourcesSession = null;\n this._clearTrackedSources();\n return true;\n }\n\n /**\n * Disposes the feature and clears its observables.\n */\n public override dispose(): void {\n super.dispose();\n this.onTrackedSourceAddedObservable.clear();\n this.onTrackedSourceRemovedObservable.clear();\n }\n\n protected override _onXRFrame(): void {}\n\n private _onTrackedSourcesChanged = (): void => {\n this._synchronizeTrackedSources();\n };\n\n private _synchronizeTrackedSources(): void {\n const session = this._trackedSourcesSession;\n if (!this.attached || !session) {\n return;\n }\n\n for (let index = 0; index < this._trackedSources.length;) {\n const trackedSource = this._trackedSources[index];\n let isStillTracked = false;\n for (const nativeTrackedSource of session.trackedSources) {\n if (nativeTrackedSource === trackedSource) {\n isStillTracked = true;\n break;\n }\n }\n\n if (isStillTracked) {\n index++;\n } else {\n this._trackedSources.splice(index, 1);\n this.onTrackedSourceRemovedObservable.notifyObservers(trackedSource);\n }\n }\n\n for (const trackedSource of session.trackedSources) {\n if (this._trackedSources.indexOf(trackedSource) === -1) {\n this._trackedSources.push(trackedSource);\n this.onTrackedSourceAddedObservable.notifyObservers(trackedSource);\n }\n }\n\n let index = 0;\n for (const trackedSource of session.trackedSources) {\n this._trackedSources[index++] = trackedSource;\n }\n }\n\n private _clearTrackedSources(): void {\n while (this._trackedSources.length > 0) {\n const trackedSource = this._trackedSources.shift();\n if (trackedSource) {\n this.onTrackedSourceRemovedObservable.notifyObservers(trackedSource);\n }\n }\n }\n}\n\nlet _Registered = false;\n\n/**\n * Registers the WebXR tracked sources feature.\n *\n * Safe to call multiple times; only the first call has an effect.\n */\nexport function RegisterWebXRTrackedSources(): void {\n if (_Registered) {\n return;\n }\n _Registered = true;\n\n WebXRFeaturesManager.AddWebXRFeature(\n WebXRTrackedSources.Name,\n (xrSessionManager) => {\n return () => new WebXRTrackedSources(xrSessionManager);\n },\n WebXRTrackedSources.Version\n );\n}\n"]}
@@ -22,3 +22,4 @@ export * from "./WebXRDepthSensing.js";
22
22
  export * from "./WebXRSpaceWarp.js";
23
23
  export * from "./WebXRRawCameraAccess.js";
24
24
  export * from "./WebXRBodyTracking.js";
25
+ export * from "./WebXRTrackedSources.js";
@@ -22,4 +22,5 @@ export * from "./WebXRDepthSensing.js";
22
22
  export * from "./WebXRSpaceWarp.js";
23
23
  export * from "./WebXRRawCameraAccess.js";
24
24
  export * from "./WebXRBodyTracking.js";
25
+ export * from "./WebXRTrackedSources.js";
25
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/features/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC","sourcesContent":["export * from \"./WebXRAbstractFeature\";\r\nexport * from \"./WebXRHitTestLegacy\";\r\nexport * from \"./WebXRAnchorSystem\";\r\nexport * from \"./WebXRPlaneDetector\";\r\nexport * from \"./WebXRBackgroundRemover\";\r\nexport * from \"./WebXRControllerTeleportation\";\r\nexport * from \"./WebXRControllerPointerSelection\";\r\nexport * from \"./WebXRControllerPhysics\";\r\nexport * from \"./WebXRHitTest\";\r\nexport * from \"./WebXRFeaturePointSystem\";\r\nexport * from \"./WebXRHandTracking\";\r\nexport * from \"./WebXRMeshDetector\";\r\nexport * from \"./WebXRImageTracking\";\r\nexport * from \"./WebXRNearInteraction\";\r\nexport * from \"./WebXRDOMOverlay\";\r\nexport * from \"./WebXRControllerMovement\";\r\nexport * from \"./WebXRLightEstimation\";\r\nexport * from \"./WebXREyeTracking\";\r\nexport * from \"./WebXRWalkingLocomotion\";\r\nexport * from \"./WebXRLayers\";\r\nexport * from \"./WebXRDepthSensing\";\r\nexport * from \"./WebXRSpaceWarp\";\r\nexport * from \"./WebXRRawCameraAccess\";\r\nexport * from \"./WebXRBodyTracking\";\r\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/features/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,mCAAmC,CAAC;AAClD,cAAc,0BAA0B,CAAC;AACzC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC","sourcesContent":["export * from \"./WebXRAbstractFeature\";\r\nexport * from \"./WebXRHitTestLegacy\";\r\nexport * from \"./WebXRAnchorSystem\";\r\nexport * from \"./WebXRPlaneDetector\";\r\nexport * from \"./WebXRBackgroundRemover\";\r\nexport * from \"./WebXRControllerTeleportation\";\r\nexport * from \"./WebXRControllerPointerSelection\";\r\nexport * from \"./WebXRControllerPhysics\";\r\nexport * from \"./WebXRHitTest\";\r\nexport * from \"./WebXRFeaturePointSystem\";\r\nexport * from \"./WebXRHandTracking\";\r\nexport * from \"./WebXRMeshDetector\";\r\nexport * from \"./WebXRImageTracking\";\r\nexport * from \"./WebXRNearInteraction\";\r\nexport * from \"./WebXRDOMOverlay\";\r\nexport * from \"./WebXRControllerMovement\";\r\nexport * from \"./WebXRLightEstimation\";\r\nexport * from \"./WebXREyeTracking\";\r\nexport * from \"./WebXRWalkingLocomotion\";\r\nexport * from \"./WebXRLayers\";\r\nexport * from \"./WebXRDepthSensing\";\r\nexport * from \"./WebXRSpaceWarp\";\r\nexport * from \"./WebXRRawCameraAccess\";\r\nexport * from \"./WebXRBodyTracking\";\r\nexport * from \"./WebXRTrackedSources\";\r\n"]}
@@ -23,4 +23,5 @@ export * from "./WebXRDepthSensing.pure.js";
23
23
  export * from "./WebXRSpaceWarp.pure.js";
24
24
  export * from "./WebXRRawCameraAccess.pure.js";
25
25
  export * from "./WebXRBodyTracking.pure.js";
26
+ export * from "./WebXRTrackedSources.pure.js";
26
27
  export * from "./WebXRLayersFallback.pure.js";
@@ -23,5 +23,6 @@ export * from "./WebXRDepthSensing.pure.js";
23
23
  export * from "./WebXRSpaceWarp.pure.js";
24
24
  export * from "./WebXRRawCameraAccess.pure.js";
25
25
  export * from "./WebXRBodyTracking.pure.js";
26
+ export * from "./WebXRTrackedSources.pure.js";
26
27
  export * from "./WebXRLayersFallback.pure.js";
27
28
  //# sourceMappingURL=pure.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pure.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/features/pure.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC","sourcesContent":["/** Pure barrel — re-exports only side-effect-free modules */\nexport * from \"./WebXRAbstractFeature\";\nexport * from \"./WebXRHitTestLegacy\";\nexport * from \"./WebXRAnchorSystem.pure\";\nexport * from \"./WebXRPlaneDetector.pure\";\nexport * from \"./WebXRBackgroundRemover.pure\";\nexport * from \"./WebXRControllerTeleportation.pure\";\nexport * from \"./WebXRControllerPointerSelection.pure\";\nexport * from \"./WebXRControllerPhysics.pure\";\nexport * from \"./WebXRHitTest.pure\";\nexport * from \"./WebXRFeaturePointSystem.pure\";\nexport * from \"./WebXRHandTracking.pure\";\nexport * from \"./WebXRMeshDetector.pure\";\nexport * from \"./WebXRImageTracking.pure\";\nexport * from \"./WebXRNearInteraction.pure\";\nexport * from \"./WebXRDOMOverlay.pure\";\nexport * from \"./WebXRControllerMovement.pure\";\nexport * from \"./WebXRLightEstimation.pure\";\nexport * from \"./WebXREyeTracking.pure\";\nexport * from \"./WebXRWalkingLocomotion.pure\";\nexport * from \"./WebXRLayers.pure\";\nexport * from \"./WebXRDepthSensing.pure\";\nexport * from \"./WebXRSpaceWarp.pure\";\nexport * from \"./WebXRRawCameraAccess.pure\";\nexport * from \"./WebXRBodyTracking.pure\";\nexport * from \"./WebXRLayersFallback.pure\";\n"]}
1
+ {"version":3,"file":"pure.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/features/pure.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,wCAAwC,CAAC;AACvD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AACxC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC","sourcesContent":["/** Pure barrel — re-exports only side-effect-free modules */\nexport * from \"./WebXRAbstractFeature\";\nexport * from \"./WebXRHitTestLegacy\";\nexport * from \"./WebXRAnchorSystem.pure\";\nexport * from \"./WebXRPlaneDetector.pure\";\nexport * from \"./WebXRBackgroundRemover.pure\";\nexport * from \"./WebXRControllerTeleportation.pure\";\nexport * from \"./WebXRControllerPointerSelection.pure\";\nexport * from \"./WebXRControllerPhysics.pure\";\nexport * from \"./WebXRHitTest.pure\";\nexport * from \"./WebXRFeaturePointSystem.pure\";\nexport * from \"./WebXRHandTracking.pure\";\nexport * from \"./WebXRMeshDetector.pure\";\nexport * from \"./WebXRImageTracking.pure\";\nexport * from \"./WebXRNearInteraction.pure\";\nexport * from \"./WebXRDOMOverlay.pure\";\nexport * from \"./WebXRControllerMovement.pure\";\nexport * from \"./WebXRLightEstimation.pure\";\nexport * from \"./WebXREyeTracking.pure\";\nexport * from \"./WebXRWalkingLocomotion.pure\";\nexport * from \"./WebXRLayers.pure\";\nexport * from \"./WebXRDepthSensing.pure\";\nexport * from \"./WebXRSpaceWarp.pure\";\nexport * from \"./WebXRRawCameraAccess.pure\";\nexport * from \"./WebXRBodyTracking.pure\";\nexport * from \"./WebXRTrackedSources.pure\";\nexport * from \"./WebXRLayersFallback.pure\";\n"]}
@@ -16,6 +16,23 @@ export type MotionControllerComponentType = "trigger" | "squeeze" | "touchpad" |
16
16
  * The state of a controller component
17
17
  */
18
18
  export type MotionControllerComponentStateType = "default" | "touched" | "pressed";
19
+ /**
20
+ * The haptic capabilities exposed by a WebXR motion controller actuator.
21
+ */
22
+ export interface IWebXRControllerHapticActuator {
23
+ /**
24
+ * The haptic effects reported as supported by this actuator.
25
+ */
26
+ readonly effects?: ReadonlyArray<GamepadHapticEffectType>;
27
+ /**
28
+ * Plays a haptic effect, when advanced haptic playback is supported.
29
+ */
30
+ playEffect?: GamepadHapticActuator["playEffect"];
31
+ /**
32
+ * Stops the active haptic effect, when reset is supported.
33
+ */
34
+ reset?: GamepadHapticActuator["reset"];
35
+ }
19
36
  /**
20
37
  * The schema of motion controller layout.
21
38
  * No object will be initialized using this interface
@@ -205,9 +222,16 @@ export interface IMinimalMotionControllerObject {
205
222
  /**
206
223
  * EXPERIMENTAL haptic support.
207
224
  */
208
- hapticActuators?: Array<{
225
+ hapticActuators?: Array<IWebXRControllerHapticActuator & {
226
+ /**
227
+ * Plays a legacy haptic pulse.
228
+ */
209
229
  pulse: (value: number, duration: number) => Promise<boolean>;
210
230
  }>;
231
+ /**
232
+ * The primary Gamepad vibration actuator used for advanced haptic effects.
233
+ */
234
+ vibrationActuator?: IWebXRControllerHapticActuator;
211
235
  }
212
236
  /**
213
237
  * An Abstract Motion controller
@@ -330,6 +354,33 @@ export declare abstract class WebXRAbstractMotionController implements IDisposab
330
354
  * Backwards compatibility due to a deeply-integrated typo
331
355
  */
332
356
  get handness(): MotionControllerHandedness;
357
+ /**
358
+ * Gets the haptic effects reported as supported by an actuator.
359
+ * See https://playground.babylonjs.com/#ULVR1X#0 for an interactive example.
360
+ *
361
+ * @param hapticActuatorIndex index of the actuator (usually 0)
362
+ * @returns the effects reported by the actuator, or an empty array when effect discovery is unavailable
363
+ * @throws a RangeError when the actuator index is invalid
364
+ */
365
+ getHapticEffects(hapticActuatorIndex?: number): ReadonlyArray<GamepadHapticEffectType>;
366
+ /**
367
+ * Plays an advanced haptic effect on this controller.
368
+ *
369
+ * @param effectType the standard Gamepad haptic effect to play
370
+ * @param parameters effect duration, delay, and motor magnitudes
371
+ * @param hapticActuatorIndex index of the actuator (usually 0)
372
+ * @returns the native completion result from the actuator
373
+ * @throws an Error when the actuator or requested effect is unsupported, or a RangeError when the actuator index is invalid
374
+ */
375
+ playHapticEffectAsync(effectType: GamepadHapticEffectType, parameters?: GamepadEffectParameters, hapticActuatorIndex?: number): Promise<GamepadHapticsResult>;
376
+ /**
377
+ * Stops the active haptic effect on an actuator.
378
+ *
379
+ * @param hapticActuatorIndex index of the actuator (usually 0)
380
+ * @returns the native completion result from the actuator
381
+ * @throws an Error when reset is unsupported, or a RangeError when the actuator index is invalid
382
+ */
383
+ resetHapticActuatorAsync(hapticActuatorIndex?: number): Promise<GamepadHapticsResult>;
333
384
  /**
334
385
  * Pulse (vibrate) this controller
335
386
  * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called
@@ -341,6 +392,7 @@ export declare abstract class WebXRAbstractMotionController implements IDisposab
341
392
  * @returns a promise that will send true when the pulse has ended and false if the device doesn't support pulse or an error accrued
342
393
  */
343
394
  pulse(value: number, duration: number, hapticActuatorIndex?: number): Promise<boolean>;
395
+ private _getHapticActuator;
344
396
  protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh | undefined;
345
397
  protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh | undefined;
346
398
  /**
@@ -212,6 +212,53 @@ export class WebXRAbstractMotionController {
212
212
  get handness() {
213
213
  return this.handedness;
214
214
  }
215
+ /**
216
+ * Gets the haptic effects reported as supported by an actuator.
217
+ * See https://playground.babylonjs.com/#ULVR1X#0 for an interactive example.
218
+ *
219
+ * @param hapticActuatorIndex index of the actuator (usually 0)
220
+ * @returns the effects reported by the actuator, or an empty array when effect discovery is unavailable
221
+ * @throws a RangeError when the actuator index is invalid
222
+ */
223
+ getHapticEffects(hapticActuatorIndex = 0) {
224
+ return this._getHapticActuator(hapticActuatorIndex).effects ?? [];
225
+ }
226
+ /**
227
+ * Plays an advanced haptic effect on this controller.
228
+ *
229
+ * @param effectType the standard Gamepad haptic effect to play
230
+ * @param parameters effect duration, delay, and motor magnitudes
231
+ * @param hapticActuatorIndex index of the actuator (usually 0)
232
+ * @returns the native completion result from the actuator
233
+ * @throws an Error when the actuator or requested effect is unsupported, or a RangeError when the actuator index is invalid
234
+ */
235
+ async playHapticEffectAsync(effectType, parameters, hapticActuatorIndex = 0) {
236
+ const actuator = this._getHapticActuator(hapticActuatorIndex);
237
+ if (!actuator.effects) {
238
+ throw new Error(`Haptic actuator ${hapticActuatorIndex} does not support effect discovery.`);
239
+ }
240
+ if (actuator.effects.indexOf(effectType) === -1) {
241
+ throw new Error(`Haptic effect "${effectType}" is not supported by actuator ${hapticActuatorIndex}.`);
242
+ }
243
+ if (!actuator.playEffect) {
244
+ throw new Error(`Haptic actuator ${hapticActuatorIndex} does not support advanced effect playback.`);
245
+ }
246
+ return await actuator.playEffect(effectType, parameters);
247
+ }
248
+ /**
249
+ * Stops the active haptic effect on an actuator.
250
+ *
251
+ * @param hapticActuatorIndex index of the actuator (usually 0)
252
+ * @returns the native completion result from the actuator
253
+ * @throws an Error when reset is unsupported, or a RangeError when the actuator index is invalid
254
+ */
255
+ async resetHapticActuatorAsync(hapticActuatorIndex = 0) {
256
+ const actuator = this._getHapticActuator(hapticActuatorIndex);
257
+ if (!actuator.reset) {
258
+ throw new Error(`Haptic actuator ${hapticActuatorIndex} does not support reset.`);
259
+ }
260
+ return await actuator.reset();
261
+ }
215
262
  /**
216
263
  * Pulse (vibrate) this controller
217
264
  * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called
@@ -231,6 +278,20 @@ export class WebXRAbstractMotionController {
231
278
  return false;
232
279
  }
233
280
  }
281
+ _getHapticActuator(hapticActuatorIndex) {
282
+ if (!Number.isInteger(hapticActuatorIndex) || hapticActuatorIndex < 0) {
283
+ throw new RangeError(`Haptic actuator index ${hapticActuatorIndex} is out of range.`);
284
+ }
285
+ if (hapticActuatorIndex === 0 && this.gamepadObject.vibrationActuator) {
286
+ return this.gamepadObject.vibrationActuator;
287
+ }
288
+ const actuators = this.gamepadObject.hapticActuators;
289
+ const actuator = actuators?.[hapticActuatorIndex];
290
+ if (!actuator) {
291
+ throw new RangeError(`Haptic actuator index ${hapticActuatorIndex} is out of range.`);
292
+ }
293
+ return actuator;
294
+ }
234
295
  // Look through all children recursively. This will return null if no mesh exists with the given name.
235
296
  _getChildByName(node, name) {
236
297
  return node.getChildren((n) => n.name === name, false)[0];
@@ -1 +1 @@
1
- {"version":3,"file":"webXRAbstractMotionController.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/motionController/webXRAbstractMotionController.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IDisposable, type Scene } from \"../../scene\";\r\nimport { WebXRControllerComponent } from \"./webXRControllerComponent\";\r\nimport { Observable } from \"../../Misc/observable\";\r\nimport { Logger } from \"../../Misc/logger\";\r\nimport { SceneLoader } from \"../../Loading/sceneLoader\";\r\nimport { type AbstractMesh } from \"../../Meshes/abstractMesh\";\r\nimport { type Nullable } from \"../../types\";\r\nimport { Quaternion, Vector3 } from \"../../Maths/math.vector.pure\";\r\nimport { Mesh } from \"../../Meshes/mesh.pure\";\r\n\r\n/**\r\n * Handedness type in xrInput profiles. These can be used to define layouts in the Layout Map.\r\n */\r\nexport type MotionControllerHandedness = \"none\" | \"left\" | \"right\";\r\n/**\r\n * The type of components available in motion controllers.\r\n * This is not the name of the component.\r\n */\r\nexport type MotionControllerComponentType = \"trigger\" | \"squeeze\" | \"touchpad\" | \"thumbstick\" | \"button\";\r\n\r\n/**\r\n * The state of a controller component\r\n */\r\nexport type MotionControllerComponentStateType = \"default\" | \"touched\" | \"pressed\";\r\n\r\n/**\r\n * The schema of motion controller layout.\r\n * No object will be initialized using this interface\r\n * This is used just to define the profile.\r\n */\r\nexport interface IMotionControllerLayout {\r\n /**\r\n * Path to load the assets. Usually relative to the base path\r\n */\r\n assetPath: string;\r\n /**\r\n * Available components (unsorted)\r\n */\r\n components: {\r\n /**\r\n * A map of component Ids\r\n */\r\n [componentId: string]: {\r\n /**\r\n * The type of input the component outputs\r\n */\r\n type: MotionControllerComponentType;\r\n /**\r\n * The indices of this component in the gamepad object\r\n */\r\n gamepadIndices: {\r\n /**\r\n * Index of button\r\n */\r\n button?: number;\r\n /**\r\n * If available, index of x-axis\r\n */\r\n xAxis?: number;\r\n /**\r\n * If available, index of y-axis\r\n */\r\n yAxis?: number;\r\n };\r\n /**\r\n * The mesh's root node name\r\n */\r\n rootNodeName: string;\r\n /**\r\n * Animation definitions for this model\r\n */\r\n visualResponses: {\r\n [stateKey: string]: {\r\n /**\r\n * What property will be animated\r\n */\r\n componentProperty: \"xAxis\" | \"yAxis\" | \"button\" | \"state\";\r\n /**\r\n * What states influence this visual response\r\n */\r\n states: MotionControllerComponentStateType[];\r\n /**\r\n * Type of animation - movement or visibility\r\n */\r\n valueNodeProperty: \"transform\" | \"visibility\";\r\n /**\r\n * Base node name to move. Its position will be calculated according to the min and max nodes\r\n */\r\n valueNodeName?: string;\r\n /**\r\n * Minimum movement node\r\n */\r\n minNodeName?: string;\r\n /**\r\n * Max movement node\r\n */\r\n maxNodeName?: string;\r\n };\r\n };\r\n /**\r\n * If touch enabled, what is the name of node to display user feedback\r\n */\r\n touchPointNodeName?: string;\r\n };\r\n };\r\n /**\r\n * Is it xr standard mapping or not\r\n */\r\n gamepadMapping: \"\" | \"xr-standard\";\r\n /**\r\n * Base root node of this entire model\r\n */\r\n rootNodeName: string;\r\n /**\r\n * Defines the main button component id\r\n */\r\n selectComponentId: string;\r\n}\r\n\r\n/**\r\n * A definition for the layout map in the input profile\r\n */\r\nexport interface IMotionControllerLayoutMap {\r\n /**\r\n * Layouts with handedness type as a key\r\n */\r\n [handedness: string /* handedness */]: IMotionControllerLayout;\r\n}\r\n\r\n/**\r\n * The XR Input profile schema\r\n * Profiles can be found here:\r\n * https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/registry/profiles\r\n */\r\nexport interface IMotionControllerProfile {\r\n /**\r\n * fallback profiles for this profileId\r\n */\r\n fallbackProfileIds: string[];\r\n /**\r\n * The layout map, with handedness as key\r\n */\r\n layouts: IMotionControllerLayoutMap;\r\n /**\r\n * The id of this profile\r\n * correlates to the profile(s) in the xrInput.profiles array\r\n */\r\n profileId: string;\r\n}\r\n\r\n/**\r\n * A helper-interface for the 3 meshes needed for controller button animation\r\n * The meshes are provided to the _lerpButtonTransform function to calculate the current position of the value mesh\r\n */\r\nexport interface IMotionControllerButtonMeshMap {\r\n /**\r\n * the mesh that defines the pressed value mesh position.\r\n * This is used to find the max-position of this button\r\n */\r\n pressedMesh: AbstractMesh;\r\n /**\r\n * the mesh that defines the unpressed value mesh position.\r\n * This is used to find the min (or initial) position of this button\r\n */\r\n unpressedMesh: AbstractMesh;\r\n /**\r\n * The mesh that will be changed when value changes\r\n */\r\n valueMesh: AbstractMesh;\r\n}\r\n\r\n/**\r\n * A helper-interface for the 3 meshes needed for controller axis animation.\r\n * This will be expanded when touchpad animations are fully supported\r\n * The meshes are provided to the _lerpAxisTransform function to calculate the current position of the value mesh\r\n */\r\nexport interface IMotionControllerMeshMap {\r\n /**\r\n * the mesh that defines the maximum value mesh position.\r\n */\r\n maxMesh?: AbstractMesh;\r\n /**\r\n * the mesh that defines the minimum value mesh position.\r\n */\r\n minMesh?: AbstractMesh;\r\n /**\r\n * The mesh that will be changed when axis value changes\r\n */\r\n valueMesh?: AbstractMesh;\r\n}\r\n\r\n/**\r\n * The elements needed for change-detection of the gamepad objects in motion controllers\r\n */\r\nexport interface IMinimalMotionControllerObject {\r\n /**\r\n * Available axes of this controller\r\n */\r\n axes: number[];\r\n /**\r\n * An array of available buttons\r\n */\r\n buttons: Array<{\r\n /**\r\n * Value of the button/trigger\r\n */\r\n value: number;\r\n /**\r\n * If the button/trigger is currently touched\r\n */\r\n touched: boolean;\r\n /**\r\n * If the button/trigger is currently pressed\r\n */\r\n pressed: boolean;\r\n }>;\r\n\r\n /**\r\n * EXPERIMENTAL haptic support.\r\n */\r\n hapticActuators?: Array<{\r\n pulse: (value: number, duration: number) => Promise<boolean>;\r\n }>;\r\n}\r\n\r\n/**\r\n * An Abstract Motion controller\r\n * This class receives an xrInput and a profile layout and uses those to initialize the components\r\n * Each component has an observable to check for changes in value and state\r\n */\r\nexport abstract class WebXRAbstractMotionController implements IDisposable {\r\n private _initComponent = (id: string) => {\r\n if (!id) {\r\n return;\r\n }\r\n const componentDef = this.layout.components[id];\r\n const type = componentDef.type;\r\n const buttonIndex = componentDef.gamepadIndices.button;\r\n // search for axes\r\n const axes: number[] = [];\r\n if (componentDef.gamepadIndices.xAxis !== undefined && componentDef.gamepadIndices.yAxis !== undefined) {\r\n axes.push(componentDef.gamepadIndices.xAxis, componentDef.gamepadIndices.yAxis);\r\n }\r\n\r\n this.components[id] = new WebXRControllerComponent(id, type, buttonIndex, axes);\r\n };\r\n\r\n private _modelReady: boolean = false;\r\n\r\n /**\r\n * A map of components (WebXRControllerComponent) in this motion controller\r\n * Components have a ComponentType and can also have both button and axis definitions\r\n */\r\n public readonly components: {\r\n [id: string]: WebXRControllerComponent;\r\n } = {};\r\n\r\n /**\r\n * Disable the model's animation. Can be set at any time.\r\n */\r\n public disableAnimation: boolean = false;\r\n /**\r\n * Observers registered here will be triggered when the model of this controller is done loading\r\n */\r\n public onModelLoadedObservable: Observable<WebXRAbstractMotionController> = new Observable();\r\n /**\r\n * The profile id of this motion controller\r\n */\r\n public abstract profileId: string;\r\n /**\r\n * The root mesh of the model. It is null if the model was not yet initialized\r\n */\r\n public rootMesh: Nullable<AbstractMesh>;\r\n\r\n /**\r\n * constructs a new abstract motion controller\r\n * @param scene the scene to which the model of the controller will be added\r\n * @param layout The profile layout to load\r\n * @param gamepadObject The gamepad object correlating to this controller\r\n * @param handedness handedness (left/right/none) of this controller\r\n * @param _doNotLoadControllerMesh set this flag to ignore the mesh loading\r\n * @param _controllerCache a cache holding controller models already loaded in this session\r\n */\r\n constructor(\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n protected scene: Scene,\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n protected layout: IMotionControllerLayout,\r\n /**\r\n * The gamepad object correlating to this controller\r\n */\r\n public gamepadObject: IMinimalMotionControllerObject,\r\n /**\r\n * handedness (left/right/none) of this controller\r\n */\r\n public handedness: MotionControllerHandedness,\r\n /**\r\n * @internal\r\n * [false]\r\n */\r\n public _doNotLoadControllerMesh: boolean = false,\r\n private _controllerCache?: Array<{\r\n filename: string;\r\n path: string;\r\n meshes: AbstractMesh[];\r\n }>\r\n ) {\r\n // initialize the components\r\n if (layout.components) {\r\n const keys = Object.keys(layout.components);\r\n for (const key of keys) {\r\n this._initComponent(key);\r\n }\r\n }\r\n // Model is loaded in WebXRInput\r\n }\r\n\r\n /**\r\n * Dispose this controller, the model mesh and all its components\r\n */\r\n public dispose(): void {\r\n const ids = this.getComponentIds();\r\n for (const id of ids) {\r\n this.getComponent(id).dispose();\r\n }\r\n if (this.rootMesh) {\r\n const nodes = this.rootMesh.getChildren(undefined, true);\r\n for (const node of nodes) {\r\n node.setEnabled(false);\r\n }\r\n this.rootMesh.dispose(!!this._controllerCache, !this._controllerCache);\r\n }\r\n this.onModelLoadedObservable.clear();\r\n }\r\n\r\n /**\r\n * Returns all components of specific type\r\n * @param type the type to search for\r\n * @returns an array of components with this type\r\n */\r\n public getAllComponentsOfType(type: MotionControllerComponentType): WebXRControllerComponent[] {\r\n return this.getComponentIds()\r\n .map((id) => this.components[id])\r\n .filter((component) => component.type === type);\r\n }\r\n\r\n /**\r\n * get a component based an its component id as defined in layout.components\r\n * @param id the id of the component\r\n * @returns the component correlates to the id or undefined if not found\r\n */\r\n public getComponent(id: string): WebXRControllerComponent {\r\n return this.components[id];\r\n }\r\n\r\n /**\r\n * Get the list of components available in this motion controller\r\n * @returns an array of strings correlating to available components\r\n */\r\n public getComponentIds(): string[] {\r\n return Object.keys(this.components);\r\n }\r\n\r\n /**\r\n * Get the first component of specific type\r\n * @param type type of component to find\r\n * @returns a controller component or null if not found\r\n */\r\n public getComponentOfType(type: MotionControllerComponentType): Nullable<WebXRControllerComponent> {\r\n return this.getAllComponentsOfType(type)[0] || null;\r\n }\r\n\r\n /**\r\n * Get the main (Select) component of this controller as defined in the layout\r\n * @returns the main component of this controller\r\n */\r\n public getMainComponent(): WebXRControllerComponent {\r\n return this.getComponent(this.layout.selectComponentId);\r\n }\r\n\r\n /**\r\n * Loads the model correlating to this controller\r\n * When the mesh is loaded, the onModelLoadedObservable will be triggered\r\n * @returns A promise fulfilled with the result of the model loading\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n public async loadModel(): Promise<boolean> {\r\n const useGeneric = !this._getModelLoadingConstraints();\r\n let loadingParams = this._getGenericFilenameAndPath();\r\n // Checking if GLB loader is present\r\n if (useGeneric) {\r\n Logger.Warn(\"Falling back to generic models\");\r\n } else {\r\n loadingParams = this._getFilenameAndPath();\r\n }\r\n return await new Promise((resolve, reject) => {\r\n const meshesLoaded = (meshes: AbstractMesh[]) => {\r\n if (useGeneric) {\r\n this._getGenericParentMesh(meshes);\r\n } else {\r\n this._setRootMesh(meshes);\r\n }\r\n this._processLoadedModel(meshes);\r\n this._modelReady = true;\r\n this.onModelLoadedObservable.notifyObservers(this);\r\n resolve(true);\r\n };\r\n if (this._controllerCache) {\r\n // look for it in the cache\r\n const found = this._controllerCache.filter((c) => {\r\n return c.filename === loadingParams.filename && c.path === loadingParams.path;\r\n });\r\n if (found[0]) {\r\n for (const mesh of found[0].meshes) {\r\n mesh.setEnabled(true);\r\n }\r\n meshesLoaded(found[0].meshes);\r\n return;\r\n // found, don't continue to load\r\n }\r\n }\r\n SceneLoader.ImportMesh(\r\n \"\",\r\n loadingParams.path,\r\n loadingParams.filename,\r\n this.scene,\r\n (meshes) => {\r\n if (this._controllerCache) {\r\n this._controllerCache.push({\r\n ...loadingParams,\r\n meshes,\r\n });\r\n }\r\n meshesLoaded(meshes);\r\n },\r\n null,\r\n (_scene: Scene, message: string) => {\r\n Logger.Log(message);\r\n Logger.Warn(`Failed to retrieve controller model of type ${this.profileId} from the remote server: ${loadingParams.path}${loadingParams.filename}`);\r\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\r\n reject(message);\r\n }\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Update this model using the current XRFrame\r\n * @param xrFrame the current xr frame to use and update the model\r\n */\r\n public updateFromXRFrame(xrFrame: XRFrame): void {\r\n for (const id of this.getComponentIds()) {\r\n this.getComponent(id).update(this.gamepadObject);\r\n }\r\n this.updateModel(xrFrame);\r\n }\r\n\r\n /**\r\n * Backwards compatibility due to a deeply-integrated typo\r\n */\r\n public get handness() {\r\n return this.handedness;\r\n }\r\n\r\n /**\r\n * Pulse (vibrate) this controller\r\n * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called\r\n * Consecutive calls to this function will cancel the last pulse call\r\n *\r\n * @param value the strength of the pulse in 0.0...1.0 range\r\n * @param duration Duration of the pulse in milliseconds\r\n * @param hapticActuatorIndex optional index of actuator (will usually be 0)\r\n * @returns a promise that will send true when the pulse has ended and false if the device doesn't support pulse or an error accrued\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n public async pulse(value: number, duration: number, hapticActuatorIndex: number = 0): Promise<boolean> {\r\n if (this.gamepadObject.hapticActuators && this.gamepadObject.hapticActuators[hapticActuatorIndex]) {\r\n return await this.gamepadObject.hapticActuators[hapticActuatorIndex].pulse(value, duration);\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n // Look through all children recursively. This will return null if no mesh exists with the given name.\r\n protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh | undefined {\r\n return <AbstractMesh | undefined>node.getChildren((n) => n.name === name, false)[0];\r\n }\r\n\r\n // Look through only immediate children. This will return null if no mesh exists with the given name.\r\n protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh | undefined {\r\n return <AbstractMesh | undefined>node.getChildren((n) => n.name == name, true)[0];\r\n }\r\n\r\n /**\r\n * Moves the axis on the controller mesh based on its current state\r\n * @param axisMap\r\n * @param axisValue the value of the axis which determines the meshes new position\r\n * @internal\r\n */\r\n protected _lerpTransform(axisMap: IMotionControllerMeshMap, axisValue: number, fixValueCoordinates?: boolean): void {\r\n if (!axisMap.minMesh || !axisMap.maxMesh || !axisMap.valueMesh) {\r\n return;\r\n }\r\n\r\n if (!axisMap.minMesh.rotationQuaternion || !axisMap.maxMesh.rotationQuaternion || !axisMap.valueMesh.rotationQuaternion) {\r\n return;\r\n }\r\n\r\n // Convert from gamepad value range (-1 to +1) to lerp range (0 to 1)\r\n const lerpValue = fixValueCoordinates ? axisValue * 0.5 + 0.5 : axisValue;\r\n Quaternion.SlerpToRef(axisMap.minMesh.rotationQuaternion, axisMap.maxMesh.rotationQuaternion, lerpValue, axisMap.valueMesh.rotationQuaternion);\r\n Vector3.LerpToRef(axisMap.minMesh.position, axisMap.maxMesh.position, lerpValue, axisMap.valueMesh.position);\r\n }\r\n\r\n /**\r\n * Update the model itself with the current frame data\r\n * @param xrFrame the frame to use for updating the model mesh\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n protected updateModel(xrFrame: XRFrame): void {\r\n if (!this._modelReady) {\r\n return;\r\n }\r\n this._updateModel(xrFrame);\r\n }\r\n\r\n /**\r\n * Get the filename and path for this controller's model\r\n * @returns a map of filename and path\r\n */\r\n protected abstract _getFilenameAndPath(): { filename: string; path: string };\r\n /**\r\n * This function is called before the mesh is loaded. It checks for loading constraints.\r\n * For example, this function can check if the GLB loader is available\r\n * If this function returns false, the generic controller will be loaded instead\r\n * @returns Is the client ready to load the mesh\r\n */\r\n protected abstract _getModelLoadingConstraints(): boolean;\r\n /**\r\n * This function will be called after the model was successfully loaded and can be used\r\n * for mesh transformations before it is available for the user\r\n * @param meshes the loaded meshes\r\n */\r\n protected abstract _processLoadedModel(meshes: AbstractMesh[]): void;\r\n /**\r\n * Set the root mesh for this controller. Important for the WebXR controller class\r\n * @param meshes the loaded meshes\r\n */\r\n protected abstract _setRootMesh(meshes: AbstractMesh[]): void;\r\n /**\r\n * A function executed each frame that updates the mesh (if needed)\r\n * @param xrFrame the current xrFrame\r\n */\r\n protected abstract _updateModel(xrFrame: XRFrame): void;\r\n\r\n private _getGenericFilenameAndPath(): { filename: string; path: string } {\r\n return {\r\n filename: \"generic.babylon\",\r\n path: \"https://controllers.babylonjs.com/generic/\",\r\n };\r\n }\r\n\r\n private _getGenericParentMesh(meshes: AbstractMesh[]): void {\r\n this.rootMesh = new Mesh(this.profileId + \" \" + this.handedness, this.scene);\r\n\r\n for (const mesh of meshes) {\r\n if (!mesh.parent) {\r\n mesh.isPickable = false;\r\n mesh.setParent(this.rootMesh);\r\n }\r\n }\r\n\r\n this.rootMesh.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"webXRAbstractMotionController.js","sourceRoot":"","sources":["../../../../../dev/core/src/XR/motionController/webXRAbstractMotionController.ts"],"names":[],"mappings":"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","sourcesContent":["import { type IDisposable, type Scene } from \"../../scene\";\r\nimport { WebXRControllerComponent } from \"./webXRControllerComponent\";\r\nimport { Observable } from \"../../Misc/observable\";\r\nimport { Logger } from \"../../Misc/logger\";\r\nimport { SceneLoader } from \"../../Loading/sceneLoader\";\r\nimport { type AbstractMesh } from \"../../Meshes/abstractMesh\";\r\nimport { type Nullable } from \"../../types\";\r\nimport { Quaternion, Vector3 } from \"../../Maths/math.vector.pure\";\r\nimport { Mesh } from \"../../Meshes/mesh.pure\";\r\n\r\n/**\r\n * Handedness type in xrInput profiles. These can be used to define layouts in the Layout Map.\r\n */\r\nexport type MotionControllerHandedness = \"none\" | \"left\" | \"right\";\r\n/**\r\n * The type of components available in motion controllers.\r\n * This is not the name of the component.\r\n */\r\nexport type MotionControllerComponentType = \"trigger\" | \"squeeze\" | \"touchpad\" | \"thumbstick\" | \"button\";\r\n\r\n/**\r\n * The state of a controller component\r\n */\r\nexport type MotionControllerComponentStateType = \"default\" | \"touched\" | \"pressed\";\r\n\r\n/**\r\n * The haptic capabilities exposed by a WebXR motion controller actuator.\r\n */\r\nexport interface IWebXRControllerHapticActuator {\r\n /**\r\n * The haptic effects reported as supported by this actuator.\r\n */\r\n readonly effects?: ReadonlyArray<GamepadHapticEffectType>;\r\n /**\r\n * Plays a haptic effect, when advanced haptic playback is supported.\r\n */\r\n playEffect?: GamepadHapticActuator[\"playEffect\"];\r\n /**\r\n * Stops the active haptic effect, when reset is supported.\r\n */\r\n reset?: GamepadHapticActuator[\"reset\"];\r\n}\r\n\r\n/**\r\n * The schema of motion controller layout.\r\n * No object will be initialized using this interface\r\n * This is used just to define the profile.\r\n */\r\nexport interface IMotionControllerLayout {\r\n /**\r\n * Path to load the assets. Usually relative to the base path\r\n */\r\n assetPath: string;\r\n /**\r\n * Available components (unsorted)\r\n */\r\n components: {\r\n /**\r\n * A map of component Ids\r\n */\r\n [componentId: string]: {\r\n /**\r\n * The type of input the component outputs\r\n */\r\n type: MotionControllerComponentType;\r\n /**\r\n * The indices of this component in the gamepad object\r\n */\r\n gamepadIndices: {\r\n /**\r\n * Index of button\r\n */\r\n button?: number;\r\n /**\r\n * If available, index of x-axis\r\n */\r\n xAxis?: number;\r\n /**\r\n * If available, index of y-axis\r\n */\r\n yAxis?: number;\r\n };\r\n /**\r\n * The mesh's root node name\r\n */\r\n rootNodeName: string;\r\n /**\r\n * Animation definitions for this model\r\n */\r\n visualResponses: {\r\n [stateKey: string]: {\r\n /**\r\n * What property will be animated\r\n */\r\n componentProperty: \"xAxis\" | \"yAxis\" | \"button\" | \"state\";\r\n /**\r\n * What states influence this visual response\r\n */\r\n states: MotionControllerComponentStateType[];\r\n /**\r\n * Type of animation - movement or visibility\r\n */\r\n valueNodeProperty: \"transform\" | \"visibility\";\r\n /**\r\n * Base node name to move. Its position will be calculated according to the min and max nodes\r\n */\r\n valueNodeName?: string;\r\n /**\r\n * Minimum movement node\r\n */\r\n minNodeName?: string;\r\n /**\r\n * Max movement node\r\n */\r\n maxNodeName?: string;\r\n };\r\n };\r\n /**\r\n * If touch enabled, what is the name of node to display user feedback\r\n */\r\n touchPointNodeName?: string;\r\n };\r\n };\r\n /**\r\n * Is it xr standard mapping or not\r\n */\r\n gamepadMapping: \"\" | \"xr-standard\";\r\n /**\r\n * Base root node of this entire model\r\n */\r\n rootNodeName: string;\r\n /**\r\n * Defines the main button component id\r\n */\r\n selectComponentId: string;\r\n}\r\n\r\n/**\r\n * A definition for the layout map in the input profile\r\n */\r\nexport interface IMotionControllerLayoutMap {\r\n /**\r\n * Layouts with handedness type as a key\r\n */\r\n [handedness: string /* handedness */]: IMotionControllerLayout;\r\n}\r\n\r\n/**\r\n * The XR Input profile schema\r\n * Profiles can be found here:\r\n * https://github.com/immersive-web/webxr-input-profiles/tree/master/packages/registry/profiles\r\n */\r\nexport interface IMotionControllerProfile {\r\n /**\r\n * fallback profiles for this profileId\r\n */\r\n fallbackProfileIds: string[];\r\n /**\r\n * The layout map, with handedness as key\r\n */\r\n layouts: IMotionControllerLayoutMap;\r\n /**\r\n * The id of this profile\r\n * correlates to the profile(s) in the xrInput.profiles array\r\n */\r\n profileId: string;\r\n}\r\n\r\n/**\r\n * A helper-interface for the 3 meshes needed for controller button animation\r\n * The meshes are provided to the _lerpButtonTransform function to calculate the current position of the value mesh\r\n */\r\nexport interface IMotionControllerButtonMeshMap {\r\n /**\r\n * the mesh that defines the pressed value mesh position.\r\n * This is used to find the max-position of this button\r\n */\r\n pressedMesh: AbstractMesh;\r\n /**\r\n * the mesh that defines the unpressed value mesh position.\r\n * This is used to find the min (or initial) position of this button\r\n */\r\n unpressedMesh: AbstractMesh;\r\n /**\r\n * The mesh that will be changed when value changes\r\n */\r\n valueMesh: AbstractMesh;\r\n}\r\n\r\n/**\r\n * A helper-interface for the 3 meshes needed for controller axis animation.\r\n * This will be expanded when touchpad animations are fully supported\r\n * The meshes are provided to the _lerpAxisTransform function to calculate the current position of the value mesh\r\n */\r\nexport interface IMotionControllerMeshMap {\r\n /**\r\n * the mesh that defines the maximum value mesh position.\r\n */\r\n maxMesh?: AbstractMesh;\r\n /**\r\n * the mesh that defines the minimum value mesh position.\r\n */\r\n minMesh?: AbstractMesh;\r\n /**\r\n * The mesh that will be changed when axis value changes\r\n */\r\n valueMesh?: AbstractMesh;\r\n}\r\n\r\n/**\r\n * The elements needed for change-detection of the gamepad objects in motion controllers\r\n */\r\nexport interface IMinimalMotionControllerObject {\r\n /**\r\n * Available axes of this controller\r\n */\r\n axes: number[];\r\n /**\r\n * An array of available buttons\r\n */\r\n buttons: Array<{\r\n /**\r\n * Value of the button/trigger\r\n */\r\n value: number;\r\n /**\r\n * If the button/trigger is currently touched\r\n */\r\n touched: boolean;\r\n /**\r\n * If the button/trigger is currently pressed\r\n */\r\n pressed: boolean;\r\n }>;\r\n\r\n /**\r\n * EXPERIMENTAL haptic support.\r\n */\r\n hapticActuators?: Array<\r\n IWebXRControllerHapticActuator & {\r\n /**\r\n * Plays a legacy haptic pulse.\r\n */\r\n pulse: (value: number, duration: number) => Promise<boolean>;\r\n }\r\n >;\r\n\r\n /**\r\n * The primary Gamepad vibration actuator used for advanced haptic effects.\r\n */\r\n vibrationActuator?: IWebXRControllerHapticActuator;\r\n}\r\n\r\n/**\r\n * An Abstract Motion controller\r\n * This class receives an xrInput and a profile layout and uses those to initialize the components\r\n * Each component has an observable to check for changes in value and state\r\n */\r\nexport abstract class WebXRAbstractMotionController implements IDisposable {\r\n private _initComponent = (id: string) => {\r\n if (!id) {\r\n return;\r\n }\r\n const componentDef = this.layout.components[id];\r\n const type = componentDef.type;\r\n const buttonIndex = componentDef.gamepadIndices.button;\r\n // search for axes\r\n const axes: number[] = [];\r\n if (componentDef.gamepadIndices.xAxis !== undefined && componentDef.gamepadIndices.yAxis !== undefined) {\r\n axes.push(componentDef.gamepadIndices.xAxis, componentDef.gamepadIndices.yAxis);\r\n }\r\n\r\n this.components[id] = new WebXRControllerComponent(id, type, buttonIndex, axes);\r\n };\r\n\r\n private _modelReady: boolean = false;\r\n\r\n /**\r\n * A map of components (WebXRControllerComponent) in this motion controller\r\n * Components have a ComponentType and can also have both button and axis definitions\r\n */\r\n public readonly components: {\r\n [id: string]: WebXRControllerComponent;\r\n } = {};\r\n\r\n /**\r\n * Disable the model's animation. Can be set at any time.\r\n */\r\n public disableAnimation: boolean = false;\r\n /**\r\n * Observers registered here will be triggered when the model of this controller is done loading\r\n */\r\n public onModelLoadedObservable: Observable<WebXRAbstractMotionController> = new Observable();\r\n /**\r\n * The profile id of this motion controller\r\n */\r\n public abstract profileId: string;\r\n /**\r\n * The root mesh of the model. It is null if the model was not yet initialized\r\n */\r\n public rootMesh: Nullable<AbstractMesh>;\r\n\r\n /**\r\n * constructs a new abstract motion controller\r\n * @param scene the scene to which the model of the controller will be added\r\n * @param layout The profile layout to load\r\n * @param gamepadObject The gamepad object correlating to this controller\r\n * @param handedness handedness (left/right/none) of this controller\r\n * @param _doNotLoadControllerMesh set this flag to ignore the mesh loading\r\n * @param _controllerCache a cache holding controller models already loaded in this session\r\n */\r\n constructor(\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n protected scene: Scene,\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n protected layout: IMotionControllerLayout,\r\n /**\r\n * The gamepad object correlating to this controller\r\n */\r\n public gamepadObject: IMinimalMotionControllerObject,\r\n /**\r\n * handedness (left/right/none) of this controller\r\n */\r\n public handedness: MotionControllerHandedness,\r\n /**\r\n * @internal\r\n * [false]\r\n */\r\n public _doNotLoadControllerMesh: boolean = false,\r\n private _controllerCache?: Array<{\r\n filename: string;\r\n path: string;\r\n meshes: AbstractMesh[];\r\n }>\r\n ) {\r\n // initialize the components\r\n if (layout.components) {\r\n const keys = Object.keys(layout.components);\r\n for (const key of keys) {\r\n this._initComponent(key);\r\n }\r\n }\r\n // Model is loaded in WebXRInput\r\n }\r\n\r\n /**\r\n * Dispose this controller, the model mesh and all its components\r\n */\r\n public dispose(): void {\r\n const ids = this.getComponentIds();\r\n for (const id of ids) {\r\n this.getComponent(id).dispose();\r\n }\r\n if (this.rootMesh) {\r\n const nodes = this.rootMesh.getChildren(undefined, true);\r\n for (const node of nodes) {\r\n node.setEnabled(false);\r\n }\r\n this.rootMesh.dispose(!!this._controllerCache, !this._controllerCache);\r\n }\r\n this.onModelLoadedObservable.clear();\r\n }\r\n\r\n /**\r\n * Returns all components of specific type\r\n * @param type the type to search for\r\n * @returns an array of components with this type\r\n */\r\n public getAllComponentsOfType(type: MotionControllerComponentType): WebXRControllerComponent[] {\r\n return this.getComponentIds()\r\n .map((id) => this.components[id])\r\n .filter((component) => component.type === type);\r\n }\r\n\r\n /**\r\n * get a component based an its component id as defined in layout.components\r\n * @param id the id of the component\r\n * @returns the component correlates to the id or undefined if not found\r\n */\r\n public getComponent(id: string): WebXRControllerComponent {\r\n return this.components[id];\r\n }\r\n\r\n /**\r\n * Get the list of components available in this motion controller\r\n * @returns an array of strings correlating to available components\r\n */\r\n public getComponentIds(): string[] {\r\n return Object.keys(this.components);\r\n }\r\n\r\n /**\r\n * Get the first component of specific type\r\n * @param type type of component to find\r\n * @returns a controller component or null if not found\r\n */\r\n public getComponentOfType(type: MotionControllerComponentType): Nullable<WebXRControllerComponent> {\r\n return this.getAllComponentsOfType(type)[0] || null;\r\n }\r\n\r\n /**\r\n * Get the main (Select) component of this controller as defined in the layout\r\n * @returns the main component of this controller\r\n */\r\n public getMainComponent(): WebXRControllerComponent {\r\n return this.getComponent(this.layout.selectComponentId);\r\n }\r\n\r\n /**\r\n * Loads the model correlating to this controller\r\n * When the mesh is loaded, the onModelLoadedObservable will be triggered\r\n * @returns A promise fulfilled with the result of the model loading\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n public async loadModel(): Promise<boolean> {\r\n const useGeneric = !this._getModelLoadingConstraints();\r\n let loadingParams = this._getGenericFilenameAndPath();\r\n // Checking if GLB loader is present\r\n if (useGeneric) {\r\n Logger.Warn(\"Falling back to generic models\");\r\n } else {\r\n loadingParams = this._getFilenameAndPath();\r\n }\r\n return await new Promise((resolve, reject) => {\r\n const meshesLoaded = (meshes: AbstractMesh[]) => {\r\n if (useGeneric) {\r\n this._getGenericParentMesh(meshes);\r\n } else {\r\n this._setRootMesh(meshes);\r\n }\r\n this._processLoadedModel(meshes);\r\n this._modelReady = true;\r\n this.onModelLoadedObservable.notifyObservers(this);\r\n resolve(true);\r\n };\r\n if (this._controllerCache) {\r\n // look for it in the cache\r\n const found = this._controllerCache.filter((c) => {\r\n return c.filename === loadingParams.filename && c.path === loadingParams.path;\r\n });\r\n if (found[0]) {\r\n for (const mesh of found[0].meshes) {\r\n mesh.setEnabled(true);\r\n }\r\n meshesLoaded(found[0].meshes);\r\n return;\r\n // found, don't continue to load\r\n }\r\n }\r\n SceneLoader.ImportMesh(\r\n \"\",\r\n loadingParams.path,\r\n loadingParams.filename,\r\n this.scene,\r\n (meshes) => {\r\n if (this._controllerCache) {\r\n this._controllerCache.push({\r\n ...loadingParams,\r\n meshes,\r\n });\r\n }\r\n meshesLoaded(meshes);\r\n },\r\n null,\r\n (_scene: Scene, message: string) => {\r\n Logger.Log(message);\r\n Logger.Warn(`Failed to retrieve controller model of type ${this.profileId} from the remote server: ${loadingParams.path}${loadingParams.filename}`);\r\n // eslint-disable-next-line @typescript-eslint/prefer-promise-reject-errors\r\n reject(message);\r\n }\r\n );\r\n });\r\n }\r\n\r\n /**\r\n * Update this model using the current XRFrame\r\n * @param xrFrame the current xr frame to use and update the model\r\n */\r\n public updateFromXRFrame(xrFrame: XRFrame): void {\r\n for (const id of this.getComponentIds()) {\r\n this.getComponent(id).update(this.gamepadObject);\r\n }\r\n this.updateModel(xrFrame);\r\n }\r\n\r\n /**\r\n * Backwards compatibility due to a deeply-integrated typo\r\n */\r\n public get handness() {\r\n return this.handedness;\r\n }\r\n\r\n /**\r\n * Gets the haptic effects reported as supported by an actuator.\r\n * See https://playground.babylonjs.com/#ULVR1X#0 for an interactive example.\r\n *\r\n * @param hapticActuatorIndex index of the actuator (usually 0)\r\n * @returns the effects reported by the actuator, or an empty array when effect discovery is unavailable\r\n * @throws a RangeError when the actuator index is invalid\r\n */\r\n public getHapticEffects(hapticActuatorIndex: number = 0): ReadonlyArray<GamepadHapticEffectType> {\r\n return this._getHapticActuator(hapticActuatorIndex).effects ?? [];\r\n }\r\n\r\n /**\r\n * Plays an advanced haptic effect on this controller.\r\n *\r\n * @param effectType the standard Gamepad haptic effect to play\r\n * @param parameters effect duration, delay, and motor magnitudes\r\n * @param hapticActuatorIndex index of the actuator (usually 0)\r\n * @returns the native completion result from the actuator\r\n * @throws an Error when the actuator or requested effect is unsupported, or a RangeError when the actuator index is invalid\r\n */\r\n public async playHapticEffectAsync(effectType: GamepadHapticEffectType, parameters?: GamepadEffectParameters, hapticActuatorIndex: number = 0): Promise<GamepadHapticsResult> {\r\n const actuator = this._getHapticActuator(hapticActuatorIndex);\r\n if (!actuator.effects) {\r\n throw new Error(`Haptic actuator ${hapticActuatorIndex} does not support effect discovery.`);\r\n }\r\n if (actuator.effects.indexOf(effectType) === -1) {\r\n throw new Error(`Haptic effect \"${effectType}\" is not supported by actuator ${hapticActuatorIndex}.`);\r\n }\r\n if (!actuator.playEffect) {\r\n throw new Error(`Haptic actuator ${hapticActuatorIndex} does not support advanced effect playback.`);\r\n }\r\n\r\n return await actuator.playEffect(effectType, parameters);\r\n }\r\n\r\n /**\r\n * Stops the active haptic effect on an actuator.\r\n *\r\n * @param hapticActuatorIndex index of the actuator (usually 0)\r\n * @returns the native completion result from the actuator\r\n * @throws an Error when reset is unsupported, or a RangeError when the actuator index is invalid\r\n */\r\n public async resetHapticActuatorAsync(hapticActuatorIndex: number = 0): Promise<GamepadHapticsResult> {\r\n const actuator = this._getHapticActuator(hapticActuatorIndex);\r\n if (!actuator.reset) {\r\n throw new Error(`Haptic actuator ${hapticActuatorIndex} does not support reset.`);\r\n }\r\n\r\n return await actuator.reset();\r\n }\r\n\r\n /**\r\n * Pulse (vibrate) this controller\r\n * If the controller does not support pulses, this function will fail silently and return Promise<false> directly after called\r\n * Consecutive calls to this function will cancel the last pulse call\r\n *\r\n * @param value the strength of the pulse in 0.0...1.0 range\r\n * @param duration Duration of the pulse in milliseconds\r\n * @param hapticActuatorIndex optional index of actuator (will usually be 0)\r\n * @returns a promise that will send true when the pulse has ended and false if the device doesn't support pulse or an error accrued\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n public async pulse(value: number, duration: number, hapticActuatorIndex: number = 0): Promise<boolean> {\r\n if (this.gamepadObject.hapticActuators && this.gamepadObject.hapticActuators[hapticActuatorIndex]) {\r\n return await this.gamepadObject.hapticActuators[hapticActuatorIndex].pulse(value, duration);\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n private _getHapticActuator(hapticActuatorIndex: number): IWebXRControllerHapticActuator {\r\n if (!Number.isInteger(hapticActuatorIndex) || hapticActuatorIndex < 0) {\r\n throw new RangeError(`Haptic actuator index ${hapticActuatorIndex} is out of range.`);\r\n }\r\n\r\n if (hapticActuatorIndex === 0 && this.gamepadObject.vibrationActuator) {\r\n return this.gamepadObject.vibrationActuator;\r\n }\r\n\r\n const actuators = this.gamepadObject.hapticActuators;\r\n const actuator = actuators?.[hapticActuatorIndex];\r\n if (!actuator) {\r\n throw new RangeError(`Haptic actuator index ${hapticActuatorIndex} is out of range.`);\r\n }\r\n\r\n return actuator;\r\n }\r\n\r\n // Look through all children recursively. This will return null if no mesh exists with the given name.\r\n protected _getChildByName(node: AbstractMesh, name: string): AbstractMesh | undefined {\r\n return <AbstractMesh | undefined>node.getChildren((n) => n.name === name, false)[0];\r\n }\r\n\r\n // Look through only immediate children. This will return null if no mesh exists with the given name.\r\n protected _getImmediateChildByName(node: AbstractMesh, name: string): AbstractMesh | undefined {\r\n return <AbstractMesh | undefined>node.getChildren((n) => n.name == name, true)[0];\r\n }\r\n\r\n /**\r\n * Moves the axis on the controller mesh based on its current state\r\n * @param axisMap\r\n * @param axisValue the value of the axis which determines the meshes new position\r\n * @internal\r\n */\r\n protected _lerpTransform(axisMap: IMotionControllerMeshMap, axisValue: number, fixValueCoordinates?: boolean): void {\r\n if (!axisMap.minMesh || !axisMap.maxMesh || !axisMap.valueMesh) {\r\n return;\r\n }\r\n\r\n if (!axisMap.minMesh.rotationQuaternion || !axisMap.maxMesh.rotationQuaternion || !axisMap.valueMesh.rotationQuaternion) {\r\n return;\r\n }\r\n\r\n // Convert from gamepad value range (-1 to +1) to lerp range (0 to 1)\r\n const lerpValue = fixValueCoordinates ? axisValue * 0.5 + 0.5 : axisValue;\r\n Quaternion.SlerpToRef(axisMap.minMesh.rotationQuaternion, axisMap.maxMesh.rotationQuaternion, lerpValue, axisMap.valueMesh.rotationQuaternion);\r\n Vector3.LerpToRef(axisMap.minMesh.position, axisMap.maxMesh.position, lerpValue, axisMap.valueMesh.position);\r\n }\r\n\r\n /**\r\n * Update the model itself with the current frame data\r\n * @param xrFrame the frame to use for updating the model mesh\r\n */\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n protected updateModel(xrFrame: XRFrame): void {\r\n if (!this._modelReady) {\r\n return;\r\n }\r\n this._updateModel(xrFrame);\r\n }\r\n\r\n /**\r\n * Get the filename and path for this controller's model\r\n * @returns a map of filename and path\r\n */\r\n protected abstract _getFilenameAndPath(): { filename: string; path: string };\r\n /**\r\n * This function is called before the mesh is loaded. It checks for loading constraints.\r\n * For example, this function can check if the GLB loader is available\r\n * If this function returns false, the generic controller will be loaded instead\r\n * @returns Is the client ready to load the mesh\r\n */\r\n protected abstract _getModelLoadingConstraints(): boolean;\r\n /**\r\n * This function will be called after the model was successfully loaded and can be used\r\n * for mesh transformations before it is available for the user\r\n * @param meshes the loaded meshes\r\n */\r\n protected abstract _processLoadedModel(meshes: AbstractMesh[]): void;\r\n /**\r\n * Set the root mesh for this controller. Important for the WebXR controller class\r\n * @param meshes the loaded meshes\r\n */\r\n protected abstract _setRootMesh(meshes: AbstractMesh[]): void;\r\n /**\r\n * A function executed each frame that updates the mesh (if needed)\r\n * @param xrFrame the current xrFrame\r\n */\r\n protected abstract _updateModel(xrFrame: XRFrame): void;\r\n\r\n private _getGenericFilenameAndPath(): { filename: string; path: string } {\r\n return {\r\n filename: \"generic.babylon\",\r\n path: \"https://controllers.babylonjs.com/generic/\",\r\n };\r\n }\r\n\r\n private _getGenericParentMesh(meshes: AbstractMesh[]): void {\r\n this.rootMesh = new Mesh(this.profileId + \" \" + this.handedness, this.scene);\r\n\r\n for (const mesh of meshes) {\r\n if (!mesh.parent) {\r\n mesh.isPickable = false;\r\n mesh.setParent(this.rootMesh);\r\n }\r\n }\r\n\r\n this.rootMesh.rotationQuaternion = Quaternion.FromEulerAngles(0, Math.PI, 0);\r\n }\r\n}\r\n"]}
@@ -1,10 +1,10 @@
1
1
  import { WebXRExperienceHelper } from "./webXRExperienceHelper.js";
2
2
  import { WebXRInput } from "./webXRInput.js";
3
- import { WebXRControllerPointerSelection } from "./features/WebXRControllerPointerSelection.pure.js";
4
- import { WebXRNearInteraction } from "./features/WebXRNearInteraction.pure.js";
3
+ import { RegisterWebXRControllerPointerSelection, WebXRControllerPointerSelection, } from "./features/WebXRControllerPointerSelection.pure.js";
4
+ import { RegisterWebXRNearInteraction, WebXRNearInteraction } from "./features/WebXRNearInteraction.pure.js";
5
5
  import { WebXREnterExitUI } from "./webXREnterExitUI.js";
6
- import { WebXRMotionControllerTeleportation } from "./features/WebXRControllerTeleportation.pure.js";
7
- import { WebXRHandTracking } from "./features/WebXRHandTracking.pure.js";
6
+ import { RegisterWebXRControllerTeleportation, WebXRMotionControllerTeleportation } from "./features/WebXRControllerTeleportation.pure.js";
7
+ import { RegisterWebXRHandTracking, WebXRHandTracking } from "./features/WebXRHandTracking.pure.js";
8
8
  import { Logger } from "../Misc/logger.js";
9
9
  /**
10
10
  * Options for the default xr helper
@@ -23,6 +23,10 @@ export class WebXRDefaultExperience {
23
23
  * @returns resulting WebXRDefaultExperience
24
24
  */
25
25
  static async CreateAsync(scene, options = {}) {
26
+ RegisterWebXRControllerPointerSelection();
27
+ RegisterWebXRControllerTeleportation();
28
+ RegisterWebXRNearInteraction();
29
+ RegisterWebXRHandTracking();
26
30
  const result = new WebXRDefaultExperience();
27
31
  scene.onDisposeObservable.addOnce(() => {
28
32
  result.dispose();