@onerjs/core 8.55.7 → 8.55.9

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 (261) hide show
  1. package/Animations/animation.pure.js +2 -2
  2. package/Animations/animation.pure.js.map +1 -1
  3. package/Animations/runtimeAnimation.js +4 -0
  4. package/Animations/runtimeAnimation.js.map +1 -1
  5. package/Behaviors/Cameras/autoRotationBehavior.js +1 -1
  6. package/Behaviors/Cameras/autoRotationBehavior.js.map +1 -1
  7. package/Behaviors/Meshes/followBehavior.js +1 -0
  8. package/Behaviors/Meshes/followBehavior.js.map +1 -1
  9. package/Behaviors/Meshes/surfaceMagnetismBehavior.js +1 -0
  10. package/Behaviors/Meshes/surfaceMagnetismBehavior.js.map +1 -1
  11. package/Cameras/Inputs/followCameraMouseWheelInput.js +2 -2
  12. package/Cameras/Inputs/followCameraMouseWheelInput.js.map +1 -1
  13. package/Cameras/Inputs/followCameraPointersInput.d.ts +15 -0
  14. package/Cameras/Inputs/followCameraPointersInput.js +18 -3
  15. package/Cameras/Inputs/followCameraPointersInput.js.map +1 -1
  16. package/Cameras/Stereoscopic/stereoscopicScreenUniversalCamera.js +1 -1
  17. package/Cameras/Stereoscopic/stereoscopicScreenUniversalCamera.js.map +1 -1
  18. package/Cameras/Stereoscopic/stereoscopicUniversalCamera.pure.js +1 -1
  19. package/Cameras/Stereoscopic/stereoscopicUniversalCamera.pure.js.map +1 -1
  20. package/Cameras/arcRotateCamera.pure.js +1 -1
  21. package/Cameras/arcRotateCamera.pure.js.map +1 -1
  22. package/Collisions/gpuPicker.d.ts +1 -0
  23. package/Collisions/gpuPicker.js +5 -4
  24. package/Collisions/gpuPicker.js.map +1 -1
  25. package/Culling/Helper/boundingInfoHelper.js +1 -1
  26. package/Culling/Helper/boundingInfoHelper.js.map +1 -1
  27. package/Culling/boundingSphere.js +7 -4
  28. package/Culling/boundingSphere.js.map +1 -1
  29. package/Engines/Extensions/engine.prefilteredCubeTexture.pure.js +1 -1
  30. package/Engines/Extensions/engine.prefilteredCubeTexture.pure.js.map +1 -1
  31. package/Engines/Native/Extensions/nativeEngine.cubeTexture.pure.js +48 -6
  32. package/Engines/Native/Extensions/nativeEngine.cubeTexture.pure.js.map +1 -1
  33. package/Engines/Native/nativeInterfaces.d.ts +1 -1
  34. package/Engines/Native/nativeInterfaces.js.map +1 -1
  35. package/Engines/abstractEngine.pure.js +2 -2
  36. package/Engines/abstractEngine.pure.js.map +1 -1
  37. package/Engines/engine.d.ts +10 -1
  38. package/Engines/thinNativeEngine.pure.d.ts +6 -1
  39. package/Engines/thinNativeEngine.pure.js +29 -2
  40. package/Engines/thinNativeEngine.pure.js.map +1 -1
  41. package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.d.ts +3 -63
  42. package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.js +5 -71
  43. package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.js.map +1 -1
  44. package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.pure.d.ts +71 -0
  45. package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.pure.js +86 -0
  46. package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.pure.js.map +1 -0
  47. package/FlowGraph/Blocks/Data/pure.d.ts +1 -0
  48. package/FlowGraph/Blocks/Data/pure.js +1 -0
  49. package/FlowGraph/Blocks/Data/pure.js.map +1 -1
  50. package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.d.ts +3 -37
  51. package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.js +5 -39
  52. package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.js.map +1 -1
  53. package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.pure.d.ts +45 -0
  54. package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.pure.js +54 -0
  55. package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.pure.js.map +1 -0
  56. package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.d.ts +3 -17
  57. package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.js +5 -22
  58. package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.js.map +1 -1
  59. package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.pure.d.ts +25 -0
  60. package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.pure.js +37 -0
  61. package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.pure.js.map +1 -0
  62. package/FlowGraph/Blocks/Event/pure.d.ts +2 -0
  63. package/FlowGraph/Blocks/Event/pure.js +2 -0
  64. package/FlowGraph/Blocks/Event/pure.js.map +1 -1
  65. package/FlowGraph/Blocks/flowGraphBlockFactory.d.ts +1 -1
  66. package/FlowGraph/Blocks/flowGraphBlockFactory.js +198 -172
  67. package/FlowGraph/Blocks/flowGraphBlockFactory.js.map +1 -1
  68. package/FrameGraph/frameGraph.js +10 -1
  69. package/FrameGraph/frameGraph.js.map +1 -1
  70. package/Gamepads/gamepadManager.d.ts +1 -0
  71. package/Gamepads/gamepadManager.js +5 -2
  72. package/Gamepads/gamepadManager.js.map +1 -1
  73. package/Gizmos/scaleGizmo.js +1 -0
  74. package/Gizmos/scaleGizmo.js.map +1 -1
  75. package/Lights/IES/iesLoader.js +6 -8
  76. package/Lights/IES/iesLoader.js.map +1 -1
  77. package/Lights/Shadows/cascadedShadowGenerator.pure.js +4 -6
  78. package/Lights/Shadows/cascadedShadowGenerator.pure.js.map +1 -1
  79. package/Lights/Shadows/shadowGenerator.js +2 -2
  80. package/Lights/Shadows/shadowGenerator.js.map +1 -1
  81. package/Lights/light.js +3 -5
  82. package/Lights/light.js.map +1 -1
  83. package/Lights/spotLight.pure.js +1 -1
  84. package/Lights/spotLight.pure.js.map +1 -1
  85. package/Materials/Background/backgroundMaterial.pure.d.ts +1 -1
  86. package/Materials/Background/backgroundMaterial.pure.js +3 -12
  87. package/Materials/Background/backgroundMaterial.pure.js.map +1 -1
  88. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js +2 -0
  89. package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js.map +1 -1
  90. package/Materials/Node/Blocks/Fragment/TBNBlock.pure.js +1 -1
  91. package/Materials/Node/Blocks/Fragment/TBNBlock.pure.js.map +1 -1
  92. package/Materials/PBR/openpbrMaterial.pure.d.ts +1 -1
  93. package/Materials/PBR/openpbrMaterial.pure.js +3 -12
  94. package/Materials/PBR/openpbrMaterial.pure.js.map +1 -1
  95. package/Materials/PBR/pbrBaseMaterial.pure.d.ts +1 -1
  96. package/Materials/PBR/pbrBaseMaterial.pure.js +3 -12
  97. package/Materials/PBR/pbrBaseMaterial.pure.js.map +1 -1
  98. package/Materials/Textures/renderTargetTexture.pure.js +1 -1
  99. package/Materials/Textures/renderTargetTexture.pure.js.map +1 -1
  100. package/Materials/material.pure.js +2 -2
  101. package/Materials/material.pure.js.map +1 -1
  102. package/Materials/standardMaterial.pure.d.ts +1 -1
  103. package/Materials/standardMaterial.pure.js +4 -13
  104. package/Materials/standardMaterial.pure.js.map +1 -1
  105. package/Maths/math.path.js +1 -1
  106. package/Maths/math.path.js.map +1 -1
  107. package/Maths/math.polar.js +1 -1
  108. package/Maths/math.polar.js.map +1 -1
  109. package/Maths/math.vector.pure.js +4 -3
  110. package/Maths/math.vector.pure.js.map +1 -1
  111. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.d.ts +72 -0
  112. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js +164 -1
  113. package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js.map +1 -1
  114. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.d.ts +2 -1
  115. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +36 -18
  116. package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
  117. package/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.pure.d.ts +5 -4
  118. package/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.pure.js +25 -8
  119. package/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.pure.js.map +1 -1
  120. package/Meshes/GreasedLine/greasedLineRibbonMesh.pure.js +3 -3
  121. package/Meshes/GreasedLine/greasedLineRibbonMesh.pure.js.map +1 -1
  122. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.pure.js +1 -1
  123. package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.pure.js.map +1 -1
  124. package/Meshes/Node/Blocks/geometryOptimizeBlock.pure.js +2 -2
  125. package/Meshes/Node/Blocks/geometryOptimizeBlock.pure.js.map +1 -1
  126. package/Meshes/Node/Blocks/mappingBlock.pure.js +2 -2
  127. package/Meshes/Node/Blocks/mappingBlock.pure.js.map +1 -1
  128. package/Meshes/csg.js +5 -5
  129. package/Meshes/csg.js.map +1 -1
  130. package/Meshes/groundMesh.pure.js +1 -1
  131. package/Meshes/groundMesh.pure.js.map +1 -1
  132. package/Meshes/mesh.pure.js +2 -2
  133. package/Meshes/mesh.pure.js.map +1 -1
  134. package/Misc/deepMerger.js +1 -1
  135. package/Misc/deepMerger.js.map +1 -1
  136. package/Misc/dumpTools.pure.js +1 -1
  137. package/Misc/dumpTools.pure.js.map +1 -1
  138. package/Misc/index.d.ts +1 -0
  139. package/Misc/index.js +1 -0
  140. package/Misc/index.js.map +1 -1
  141. package/Misc/pure.d.ts +1 -0
  142. package/Misc/pure.js +1 -0
  143. package/Misc/pure.js.map +1 -1
  144. package/Misc/shaderImportLoader.d.ts +25 -0
  145. package/Misc/shaderImportLoader.js +54 -0
  146. package/Misc/shaderImportLoader.js.map +1 -0
  147. package/Misc/tools.pure.js +1 -1
  148. package/Misc/tools.pure.js.map +1 -1
  149. package/Particles/Node/Blocks/particleClampBlock.pure.d.ts +0 -1
  150. package/Particles/Node/Blocks/particleClampBlock.pure.js +1 -6
  151. package/Particles/Node/Blocks/particleClampBlock.pure.js.map +1 -1
  152. package/Particles/Node/Blocks/particleMathBlock.pure.js +1 -1
  153. package/Particles/Node/Blocks/particleMathBlock.pure.js.map +1 -1
  154. package/Particles/Node/Blocks/particleNLerpBlock.pure.js +8 -3
  155. package/Particles/Node/Blocks/particleNLerpBlock.pure.js.map +1 -1
  156. package/Particles/Node/Blocks/particleSmoothStepBlock.pure.js +3 -2
  157. package/Particles/Node/Blocks/particleSmoothStepBlock.pure.js.map +1 -1
  158. package/Particles/Node/Blocks/particleStepBlock.pure.js +3 -2
  159. package/Particles/Node/Blocks/particleStepBlock.pure.js.map +1 -1
  160. package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.pure.js +1 -1
  161. package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.pure.js.map +1 -1
  162. package/PostProcesses/depthOfFieldEffect.js +1 -1
  163. package/PostProcesses/depthOfFieldEffect.js.map +1 -1
  164. package/PostProcesses/screenSpaceCurvaturePostProcess.pure.js +1 -1
  165. package/PostProcesses/screenSpaceCurvaturePostProcess.pure.js.map +1 -1
  166. package/PostProcesses/sharpenPostProcess.pure.js +1 -1
  167. package/PostProcesses/sharpenPostProcess.pure.js.map +1 -1
  168. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.d.ts +12 -0
  169. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js +15 -1
  170. package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js.map +1 -1
  171. package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.d.ts +14 -0
  172. package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.js +122 -6
  173. package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.js.map +1 -1
  174. package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.d.ts +7 -0
  175. package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.js +17 -0
  176. package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.js.map +1 -1
  177. package/Rendering/boundingBoxRenderer.pure.js +3 -3
  178. package/Rendering/boundingBoxRenderer.pure.js.map +1 -1
  179. package/Rendering/outlineRenderer.pure.js +1 -0
  180. package/Rendering/outlineRenderer.pure.js.map +1 -1
  181. package/Rendering/subSurfaceConfiguration.js +1 -1
  182. package/Rendering/subSurfaceConfiguration.js.map +1 -1
  183. package/Rendering/subSurfaceSceneComponent.pure.d.ts +1 -1
  184. package/Rendering/subSurfaceSceneComponent.pure.js +1 -1
  185. package/Rendering/subSurfaceSceneComponent.pure.js.map +1 -1
  186. package/Rendering/utilityLayerRenderer.js +1 -1
  187. package/Rendering/utilityLayerRenderer.js.map +1 -1
  188. package/Shaders/gaussianSplattingVoxel.fragment.js +4 -10
  189. package/Shaders/gaussianSplattingVoxel.fragment.js.map +1 -1
  190. package/Shaders/iblCombineVoxelGrids.fragment.js +1 -1
  191. package/Shaders/iblCombineVoxelGrids.fragment.js.map +1 -1
  192. package/Shaders/iblShadowVoxelTracing.fragment.js +24 -7
  193. package/Shaders/iblShadowVoxelTracing.fragment.js.map +1 -1
  194. package/ShadersWGSL/ShadersInclude/iblVoxelOpacityAtomicMax.d.ts +5 -0
  195. package/ShadersWGSL/ShadersInclude/iblVoxelOpacityAtomicMax.js +13 -0
  196. package/ShadersWGSL/ShadersInclude/iblVoxelOpacityAtomicMax.js.map +1 -0
  197. package/ShadersWGSL/gaussianSplattingVoxel.fragment.js +15 -9
  198. package/ShadersWGSL/gaussianSplattingVoxel.fragment.js.map +1 -1
  199. package/ShadersWGSL/iblCombineVoxelGrids.fragment.js +1 -1
  200. package/ShadersWGSL/iblCombineVoxelGrids.fragment.js.map +1 -1
  201. package/ShadersWGSL/iblCopyVoxelBufferToGrid.compute.d.ts +5 -0
  202. package/ShadersWGSL/iblCopyVoxelBufferToGrid.compute.js +14 -0
  203. package/ShadersWGSL/iblCopyVoxelBufferToGrid.compute.js.map +1 -0
  204. package/ShadersWGSL/iblShadowVoxelTracing.fragment.js +24 -7
  205. package/ShadersWGSL/iblShadowVoxelTracing.fragment.js.map +1 -1
  206. package/ShadersWGSL/iblVoxelGrid.fragment.js +26 -6
  207. package/ShadersWGSL/iblVoxelGrid.fragment.js.map +1 -1
  208. package/SmartAssets/smartAssetManager.pure.js +1 -1
  209. package/SmartAssets/smartAssetManager.pure.js.map +1 -1
  210. package/Sprites/thinSprite.js +1 -1
  211. package/Sprites/thinSprite.js.map +1 -1
  212. package/XR/features/Layers/WebXRCompositionLayer.d.ts +130 -12
  213. package/XR/features/Layers/WebXRCompositionLayer.js +192 -3
  214. package/XR/features/Layers/WebXRCompositionLayer.js.map +1 -1
  215. package/XR/features/Layers/WebXRFallbackLayer.d.ts +84 -0
  216. package/XR/features/Layers/WebXRFallbackLayer.js +137 -0
  217. package/XR/features/Layers/WebXRFallbackLayer.js.map +1 -0
  218. package/XR/features/Layers/WebXRWebGPUCompositionLayer.d.ts +4 -4
  219. package/XR/features/Layers/WebXRWebGPUCompositionLayer.js.map +1 -1
  220. package/XR/features/WebXRAnchorSystem.pure.d.ts +45 -0
  221. package/XR/features/WebXRAnchorSystem.pure.js +153 -13
  222. package/XR/features/WebXRAnchorSystem.pure.js.map +1 -1
  223. package/XR/features/WebXRLayers.pure.d.ts +171 -8
  224. package/XR/features/WebXRLayers.pure.js +500 -98
  225. package/XR/features/WebXRLayers.pure.js.map +1 -1
  226. package/XR/features/WebXRLayersFallback.d.ts +5 -0
  227. package/XR/features/WebXRLayersFallback.js +8 -0
  228. package/XR/features/WebXRLayersFallback.js.map +1 -0
  229. package/XR/features/WebXRLayersFallback.pure.d.ts +6 -0
  230. package/XR/features/WebXRLayersFallback.pure.js +44 -0
  231. package/XR/features/WebXRLayersFallback.pure.js.map +1 -0
  232. package/XR/features/WebXRLightEstimation.pure.d.ts +3 -4
  233. package/XR/features/WebXRLightEstimation.pure.js +22 -21
  234. package/XR/features/WebXRLightEstimation.pure.js.map +1 -1
  235. package/XR/features/WebXRMeshDetector.pure.d.ts +5 -0
  236. package/XR/features/WebXRMeshDetector.pure.js +1 -0
  237. package/XR/features/WebXRMeshDetector.pure.js.map +1 -1
  238. package/XR/features/WebXRNearInteraction.pure.js +3 -3
  239. package/XR/features/WebXRNearInteraction.pure.js.map +1 -1
  240. package/XR/features/WebXRPlaneDetector.pure.d.ts +9 -5
  241. package/XR/features/WebXRPlaneDetector.pure.js +12 -8
  242. package/XR/features/WebXRPlaneDetector.pure.js.map +1 -1
  243. package/XR/features/pure.d.ts +1 -0
  244. package/XR/features/pure.js +1 -0
  245. package/XR/features/pure.js.map +1 -1
  246. package/XR/webXRCamera.d.ts +2 -0
  247. package/XR/webXRCamera.js +8 -2
  248. package/XR/webXRCamera.js.map +1 -1
  249. package/XR/webXRLayerWrapper.d.ts +19 -5
  250. package/XR/webXRLayerWrapper.js +9 -0
  251. package/XR/webXRLayerWrapper.js.map +1 -1
  252. package/XR/webXRRenderTargetTextureProvider.d.ts +4 -4
  253. package/XR/webXRRenderTargetTextureProvider.js.map +1 -1
  254. package/XR/webXRWebGLRenderTargetTextureProvider.d.ts +2 -1
  255. package/XR/webXRWebGLRenderTargetTextureProvider.js.map +1 -1
  256. package/XR/webXRWebGPURenderTargetTextureProvider.d.ts +3 -3
  257. package/XR/webXRWebGPURenderTargetTextureProvider.js.map +1 -1
  258. package/package.json +1 -1
  259. package/scene.pure.d.ts +5 -0
  260. package/scene.pure.js +25 -0
  261. package/scene.pure.js.map +1 -1
@@ -3,14 +3,26 @@ import { WebXRFeatureName, WebXRFeaturesManager } from "../webXRFeaturesManager.
3
3
  import { WebXRAbstractFeature } from "./WebXRAbstractFeature.js";
4
4
  import { WebXRWebGLLayerWrapper } from "../webXRWebGLLayer.js";
5
5
  import { WebXRProjectionLayerWrapper, DefaultXRProjectionLayerInit } from "./Layers/WebXRProjectionLayer.js";
6
- import { WebXRCompositionLayerRenderTargetTextureProvider, WebXRCompositionLayerWrapper } from "./Layers/WebXRCompositionLayer.js";
6
+ import { WebXRCompositionLayerRenderTargetTextureProvider, WebXRCompositionLayerWrapper, WebXRCubeLayerWrapper, WebXRMediaLayerWrapper, WebXRSpatialLayerWrapper, } from "./Layers/WebXRCompositionLayer.js";
7
7
  import { WebXRWebGPUProjectionLayerWrapper, CreateDefaultXRGPUProjectionLayerInit } from "./Layers/WebXRWebGPUProjectionLayer.js";
8
- import { WebXRWebGPUCompositionLayerRenderTargetTextureProvider, WebXRWebGPUCompositionLayerWrapper } from "./Layers/WebXRWebGPUCompositionLayer.js";
8
+ import { WebXRWebGPUCompositionLayerRenderTargetTextureProvider } from "./Layers/WebXRWebGPUCompositionLayer.js";
9
9
  import { Color4 } from "../../Maths/math.color.pure.js";
10
10
  import { Logger } from "../../Misc/logger.js";
11
+ import { TransformNode } from "../../Meshes/transformNode.pure.js";
12
+ import { Quaternion } from "../../Maths/math.vector.pure.js";
13
+ export { WebXRCompositionLayerWrapper, WebXRCubeLayerWrapper, WebXRMediaLayerWrapper, WebXRSpatialLayerWrapper } from "./Layers/WebXRCompositionLayer.js";
11
14
  const DefaultXRWebGLLayerInit = {};
12
15
  const WebGPUQuadLayerCreateWarning = "WebGPU XR quad layers are unavailable because XRGPUBinding.createQuadLayer is not supported; the requested quad layer was skipped and projection rendering remains active.";
13
16
  const WebGPUQuadLayerSubImageWarning = "WebGPU XR quad layers are unavailable because XRGPUBinding.getSubImage is not supported; the requested quad layer was skipped and projection rendering remains active.";
17
+ let _FallbackLayerFactory = null;
18
+ /**
19
+ * Registers the optional mesh-fallback implementation without making its rendering dependencies part of projection-only bundles.
20
+ * @param factory creates a fallback wrapper
21
+ * @internal
22
+ */
23
+ export function _RegisterWebXRFallbackLayerFactory(factory) {
24
+ _FallbackLayerFactory = factory;
25
+ }
14
26
  /**
15
27
  * Exposes the WebXR Layers API.
16
28
  */
@@ -22,11 +34,13 @@ export class WebXRLayers extends WebXRAbstractFeature {
22
34
  * Already-created layers
23
35
  */
24
36
  this._existingLayers = [];
37
+ this._fallbackLayers = [];
25
38
  this._isWebGPU = false;
26
39
  this._isMultiviewEnabled = false;
27
40
  this._projectionLayerInitialized = false;
28
41
  this._compositionLayerTextureMapping = new WeakMap();
29
42
  this._layerToRTTProviderMapping = new WeakMap();
43
+ this._layerCleanupFunctions = new WeakMap();
30
44
  this.xrNativeFeatureName = "layers";
31
45
  }
32
46
  /**
@@ -64,6 +78,13 @@ export class WebXRLayers extends WebXRAbstractFeature {
64
78
  this.createProjectionLayer(projectionLayerInit /*, projectionLayerMultiview*/);
65
79
  }
66
80
  this._projectionLayerInitialized = true;
81
+ this._addNewAttachObserver(this._xrSessionManager.onXRReferenceSpaceChanged, (referenceSpace) => {
82
+ for (const layer of this._existingLayers) {
83
+ if (layer instanceof WebXRSpatialLayerWrapper && layer.usesSessionReferenceSpace) {
84
+ layer.layer.space = referenceSpace;
85
+ }
86
+ }
87
+ });
67
88
  return true;
68
89
  }
69
90
  detach() {
@@ -71,9 +92,15 @@ export class WebXRLayers extends WebXRAbstractFeature {
71
92
  return false;
72
93
  }
73
94
  for (const layer of this._existingLayers) {
95
+ this._layerCleanupFunctions.get(layer)?.();
74
96
  layer.dispose();
75
97
  }
76
98
  this._existingLayers.length = 0;
99
+ for (const layer of this._fallbackLayers) {
100
+ layer.dispose();
101
+ }
102
+ this._fallbackLayers.length = 0;
103
+ this._xrMediaBinding = undefined;
77
104
  this._projectionLayerInitialized = false;
78
105
  return true;
79
106
  }
@@ -86,7 +113,7 @@ export class WebXRLayers extends WebXRAbstractFeature {
86
113
  const layer = new XRWebGLLayer(this._xrSessionManager.session, this._glContext, params);
87
114
  return new WebXRWebGLLayerWrapper(layer);
88
115
  }
89
- _validateLayerInit(params, multiview = this._isMultiviewEnabled) {
116
+ _validateLayerInit(params, multiview = this._isMultiviewEnabled, allowTextureArrayWithoutMultiview = false) {
90
117
  // check if we are in session
91
118
  if (!this._xrSessionManager.inXRSession) {
92
119
  throw new Error("Cannot create a layer outside of a WebXR session. Make sure the session has started before creating layers.");
@@ -95,7 +122,7 @@ export class WebXRLayers extends WebXRAbstractFeature {
95
122
  throw new Error("Projection layers can only be made multiview if they use texture arrays. Set the textureType parameter to 'texture-array'.");
96
123
  }
97
124
  // TODO (rgerd): Support RTT's that are bound to sub-images in the texture array.
98
- if (!multiview && params.textureType === "texture-array") {
125
+ if (!multiview && params.textureType === "texture-array" && !allowTextureArrayWithoutMultiview) {
99
126
  throw new Error("We currently only support multiview rendering when the textureType parameter is set to 'texture-array'.");
100
127
  }
101
128
  }
@@ -105,6 +132,175 @@ export class WebXRLayers extends WebXRAbstractFeature {
105
132
  }
106
133
  return params;
107
134
  }
135
+ _getProjectionLayerDimensions() {
136
+ const projectionLayer = this._existingLayers.find((layer) => layer.layerType === "XRProjectionLayer");
137
+ if (!projectionLayer) {
138
+ throw new Error("A projection layer must be created before adding WebXR composition layers.");
139
+ }
140
+ return {
141
+ width: projectionLayer.getWidth(),
142
+ height: projectionLayer.getHeight(),
143
+ };
144
+ }
145
+ _createTransformNode(layerType, transformNode, transform, orientation) {
146
+ if (transformNode) {
147
+ return { node: transformNode, ownsNode: false };
148
+ }
149
+ const node = new TransformNode(`WebXR ${layerType}`, this._xrSessionManager.scene);
150
+ node.rotationQuaternion = new Quaternion();
151
+ const sourcePosition = transform?.position;
152
+ const sourceOrientation = transform?.orientation ?? orientation;
153
+ if (sourcePosition) {
154
+ const worldScalingFactor = this._xrSessionManager.worldScalingFactor;
155
+ node.position.set(sourcePosition.x * worldScalingFactor, sourcePosition.y * worldScalingFactor, sourcePosition.z * worldScalingFactor);
156
+ }
157
+ if (sourceOrientation) {
158
+ node.rotationQuaternion.set(sourceOrientation.x, sourceOrientation.y, sourceOrientation.z, sourceOrientation.w);
159
+ }
160
+ if (!this._xrSessionManager.scene.useRightHandedSystem) {
161
+ node.position.z *= -1;
162
+ node.rotationQuaternion.z *= -1;
163
+ node.rotationQuaternion.w *= -1;
164
+ }
165
+ return { node, ownsNode: true };
166
+ }
167
+ _createFallbackLayer(layerType, transformNode, transform, orientation, dimensions, texture, video) {
168
+ if (!_FallbackLayerFactory) {
169
+ Logger.Warn("WebXR mesh fallbacks require importing `@babylonjs/core/XR/features/WebXRLayersFallback`.");
170
+ return null;
171
+ }
172
+ const transformInfo = this._createTransformNode(layerType, transformNode, transform, orientation);
173
+ const wrapper = _FallbackLayerFactory({
174
+ scene: this._xrSessionManager.scene,
175
+ isWebGPU: this._isWebGPU,
176
+ layerType,
177
+ transformNode: transformInfo.node,
178
+ ownsTransformNode: transformInfo.ownsNode,
179
+ dimensions,
180
+ worldScalingFactor: this._xrSessionManager.worldScalingFactor,
181
+ texture,
182
+ video,
183
+ });
184
+ if (wrapper) {
185
+ this._fallbackLayers.push(wrapper);
186
+ }
187
+ else if (transformInfo.ownsNode) {
188
+ transformInfo.node.dispose();
189
+ }
190
+ return wrapper;
191
+ }
192
+ _createGraphicsLayer(layerType, factoryName, factorySupported, options, createWebGLLayer, createWebGPULayer, copyWebGPUSpecificInit) {
193
+ if (!this._xrSessionManager.inXRSession) {
194
+ throw new Error("Cannot create a layer outside of a WebXR session. Make sure the session has started before creating layers.");
195
+ }
196
+ if (!factorySupported) {
197
+ if (options.fallbackMode !== "mesh") {
198
+ Logger.Warn(`${layerType} is unavailable because ${factoryName} is not supported; the requested layer was skipped and projection rendering remains active.`);
199
+ }
200
+ return null;
201
+ }
202
+ if (this._isWebGPU && typeof this._xrGPUBinding?.getSubImage !== "function") {
203
+ if (options.fallbackMode !== "mesh") {
204
+ Logger.Warn(`${layerType} is unavailable because XRGPUBinding.getSubImage is not supported; the requested layer was skipped and projection rendering remains active.`);
205
+ }
206
+ return null;
207
+ }
208
+ const dimensions = this._getProjectionLayerDimensions();
209
+ const defaultViewPixelWidth = layerType === "XRCubeLayer" ? Math.min(dimensions.width, dimensions.height) : dimensions.width;
210
+ const defaultViewPixelHeight = layerType === "XRCubeLayer" ? defaultViewPixelWidth : dimensions.height;
211
+ const populatedParams = {
212
+ space: this._xrSessionManager.referenceSpace,
213
+ viewPixelWidth: defaultViewPixelWidth,
214
+ viewPixelHeight: defaultViewPixelHeight,
215
+ clearOnAccess: true,
216
+ textureType: "texture",
217
+ layout: "mono",
218
+ ...options.layerInit,
219
+ };
220
+ if (layerType === "XRCubeLayer" && populatedParams.viewPixelWidth !== populatedParams.viewPixelHeight) {
221
+ throw new Error("WebXR cube layer faces must have equal pixel width and height.");
222
+ }
223
+ this._validateLayerInit(populatedParams, false, layerType === "XRCubeLayer");
224
+ let layer;
225
+ let effectiveParams = populatedParams;
226
+ let depthStencilFormat;
227
+ if (this._isWebGPU) {
228
+ const binding = this._xrGPUBinding;
229
+ const gpuParams = {
230
+ colorFormat: binding.getPreferredColorFormat(),
231
+ textureUsage: 0x10,
232
+ space: populatedParams.space,
233
+ viewPixelWidth: populatedParams.viewPixelWidth,
234
+ viewPixelHeight: populatedParams.viewPixelHeight,
235
+ layout: populatedParams.layout,
236
+ mipLevels: populatedParams.mipLevels,
237
+ isStatic: populatedParams.isStatic,
238
+ };
239
+ copyWebGPUSpecificInit(populatedParams, gpuParams);
240
+ Object.assign(gpuParams, options.gpuLayerInit);
241
+ if (layerType === "XRCubeLayer" && gpuParams.viewPixelWidth !== gpuParams.viewPixelHeight) {
242
+ throw new Error("WebXR cube layer faces must have equal pixel width and height.");
243
+ }
244
+ effectiveParams = gpuParams;
245
+ depthStencilFormat = gpuParams.depthStencilFormat;
246
+ layer = createWebGPULayer(binding, gpuParams);
247
+ }
248
+ else {
249
+ layer = createWebGLLayer(this._xrWebGLBinding, populatedParams);
250
+ }
251
+ const transform = "transform" in effectiveParams ? effectiveParams.transform : undefined;
252
+ const orientation = "orientation" in effectiveParams ? effectiveParams.orientation : undefined;
253
+ const usesSessionReferenceSpace = options.layerInit?.space === undefined && (!this._isWebGPU || options.gpuLayerInit?.space === undefined);
254
+ const transformInfo = this._createTransformNode(layerType, options.transformNode, transform, orientation);
255
+ let wrapper;
256
+ if (layerType === "XRCubeLayer") {
257
+ wrapper = new WebXRCubeLayerWrapper(() => effectiveParams.viewPixelWidth, () => effectiveParams.viewPixelHeight, layer, !!effectiveParams.isStatic, usesSessionReferenceSpace, this._isWebGPU ? this._xrGPUBinding : this._xrWebGLBinding, transformInfo.node, transformInfo.ownsNode);
258
+ }
259
+ else if (this._isWebGPU) {
260
+ const binding = this._xrGPUBinding;
261
+ wrapper = new WebXRSpatialLayerWrapper(() => effectiveParams.viewPixelWidth, () => effectiveParams.viewPixelHeight, layer, layerType, false, !!effectiveParams.isStatic, usesSessionReferenceSpace, (sessionManager) => new WebXRWebGPUCompositionLayerRenderTargetTextureProvider(sessionManager, binding, wrapper, depthStencilFormat), transformInfo.node, transformInfo.ownsNode);
262
+ }
263
+ else {
264
+ wrapper = new WebXRSpatialLayerWrapper(() => effectiveParams.viewPixelWidth, () => effectiveParams.viewPixelHeight, layer, layerType, false, !!effectiveParams.isStatic, usesSessionReferenceSpace, (sessionManager) => new WebXRCompositionLayerRenderTargetTextureProvider(sessionManager, this._xrWebGLBinding, wrapper), transformInfo.node, transformInfo.ownsNode);
265
+ }
266
+ if (wrapper.usesRenderTargetProvider) {
267
+ const rttProvider = wrapper.createRenderTargetTextureProvider(this._xrSessionManager);
268
+ this._layerToRTTProviderMapping.set(layer, rttProvider);
269
+ }
270
+ this.addXRSessionLayer(wrapper);
271
+ return wrapper;
272
+ }
273
+ _createMediaLayer(layerType, factoryName, video, options, createLayer) {
274
+ if (!this._xrSessionManager.inXRSession) {
275
+ throw new Error("Cannot create a layer outside of a WebXR session. Make sure the session has started before creating layers.");
276
+ }
277
+ if (typeof XRMediaBinding === "undefined") {
278
+ if (options.fallbackMode !== "mesh") {
279
+ Logger.Warn(`${layerType} media layers are unavailable because XRMediaBinding is not supported; the requested layer was skipped.`);
280
+ }
281
+ return null;
282
+ }
283
+ this._xrMediaBinding ?? (this._xrMediaBinding = new XRMediaBinding(this._xrSessionManager.session));
284
+ const mediaBinding = this._xrMediaBinding;
285
+ const factory = mediaBinding[factoryName];
286
+ if (typeof factory !== "function") {
287
+ if (options.fallbackMode !== "mesh") {
288
+ Logger.Warn(`${layerType} media layers are unavailable because XRMediaBinding.${factoryName} is not supported; the requested layer was skipped.`);
289
+ }
290
+ return null;
291
+ }
292
+ const populatedParams = {
293
+ space: this._xrSessionManager.referenceSpace,
294
+ layout: "mono",
295
+ ...options.layerInit,
296
+ };
297
+ const layer = createLayer(mediaBinding, video, populatedParams);
298
+ const transform = "transform" in populatedParams ? populatedParams.transform : undefined;
299
+ const transformInfo = this._createTransformNode(layerType, options.transformNode, transform);
300
+ const wrapper = new WebXRMediaLayerWrapper(() => video.videoWidth, () => video.videoHeight, layer, layerType, transformInfo.node, transformInfo.ownsNode, options.layerInit?.space === undefined);
301
+ this.addXRSessionLayer(wrapper);
302
+ return wrapper;
303
+ }
108
304
  /**
109
305
  * Creates a new XRProjectionLayer.
110
306
  * @param params an object providing configuration options for the new XRProjectionLayer.
@@ -112,9 +308,9 @@ export class WebXRLayers extends WebXRAbstractFeature {
112
308
  * @returns the projection layer
113
309
  */
114
310
  createProjectionLayer(params = DefaultXRProjectionLayerInit, multiview = this._isMultiviewEnabled) {
115
- this._extendXRLayerInit(params, multiview);
116
- this._validateLayerInit(params, multiview);
117
- const projLayer = this._xrWebGLBinding.createProjectionLayer(params);
311
+ const extendedParams = this._extendXRLayerInit(params, multiview);
312
+ this._validateLayerInit(extendedParams, multiview);
313
+ const projLayer = this._xrWebGLBinding.createProjectionLayer(extendedParams);
118
314
  const layer = new WebXRProjectionLayerWrapper(projLayer, multiview, this._xrWebGLBinding);
119
315
  this.addXRSessionLayer(layer);
120
316
  return layer;
@@ -136,25 +332,138 @@ export class WebXRLayers extends WebXRAbstractFeature {
136
332
  return layer;
137
333
  }
138
334
  /**
139
- * Note about making it private - this function will be exposed once I decide on a proper API to support all of the XR layers' options
140
- * @param options an object providing configuration options for the new XRQuadLayer.
141
- * @param babylonTexture the texture to display in the layer
142
- * @returns the quad layer, or null when the WebGPU binding lacks quad-layer support
335
+ * Creates a graphics-backed quad layer and adds it to the current XR session.
336
+ * @param options initialization and transform-node options for the layer
337
+ * @returns the created layer wrapper, or `null` when the active graphics binding does not support quad layers
338
+ */
339
+ createQuadLayer(options = {}) {
340
+ const factorySupported = this._isWebGPU ? typeof this._xrGPUBinding?.createQuadLayer === "function" : typeof this._xrWebGLBinding.createQuadLayer === "function";
341
+ const factoryName = this._isWebGPU ? "XRGPUBinding.createQuadLayer" : "XRWebGLBinding.createQuadLayer";
342
+ const nativeLayer = this._createGraphicsLayer("XRQuadLayer", factoryName, factorySupported, options, (binding, init) => binding.createQuadLayer(init), (binding, init) => binding.createQuadLayer(init), (webGLInit, webGPUInit) => {
343
+ webGPUInit.transform = webGLInit.transform;
344
+ webGPUInit.width = webGLInit.width;
345
+ webGPUInit.height = webGLInit.height;
346
+ });
347
+ if (nativeLayer || options.fallbackMode !== "mesh") {
348
+ return nativeLayer;
349
+ }
350
+ return this._createFallbackLayer("XRQuadLayer", options.transformNode, options.layerInit?.transform, undefined, { width: options.layerInit?.width, height: options.layerInit?.height }, options.fallbackTexture);
351
+ }
352
+ /**
353
+ * Creates a graphics-backed cylinder layer and adds it to the current XR session.
354
+ * @param options initialization and transform-node options for the layer
355
+ * @returns the created layer wrapper, or `null` when the active graphics binding does not support cylinder layers
143
356
  */
357
+ createCylinderLayer(options = {}) {
358
+ const factorySupported = this._isWebGPU ? typeof this._xrGPUBinding?.createCylinderLayer === "function" : typeof this._xrWebGLBinding.createCylinderLayer === "function";
359
+ const factoryName = this._isWebGPU ? "XRGPUBinding.createCylinderLayer" : "XRWebGLBinding.createCylinderLayer";
360
+ const nativeLayer = this._createGraphicsLayer("XRCylinderLayer", factoryName, factorySupported, options, (binding, init) => binding.createCylinderLayer(init), (binding, init) => binding.createCylinderLayer(init), (webGLInit, webGPUInit) => {
361
+ webGPUInit.transform = webGLInit.transform;
362
+ webGPUInit.radius = webGLInit.radius;
363
+ webGPUInit.centralAngle = webGLInit.centralAngle;
364
+ webGPUInit.aspectRatio = webGLInit.aspectRatio;
365
+ });
366
+ if (nativeLayer || options.fallbackMode !== "mesh") {
367
+ return nativeLayer;
368
+ }
369
+ return this._createFallbackLayer("XRCylinderLayer", options.transformNode, options.layerInit?.transform, undefined, {
370
+ radius: options.layerInit?.radius,
371
+ centralAngle: options.layerInit?.centralAngle,
372
+ aspectRatio: options.layerInit?.aspectRatio,
373
+ }, options.fallbackTexture);
374
+ }
375
+ /**
376
+ * Creates a graphics-backed equirectangular layer and adds it to the current XR session.
377
+ * @param options initialization and transform-node options for the layer
378
+ * @returns the created layer wrapper, or `null` when the active graphics binding does not support equirectangular layers
379
+ */
380
+ createEquirectLayer(options = {}) {
381
+ const factorySupported = this._isWebGPU ? typeof this._xrGPUBinding?.createEquirectLayer === "function" : typeof this._xrWebGLBinding.createEquirectLayer === "function";
382
+ const factoryName = this._isWebGPU ? "XRGPUBinding.createEquirectLayer" : "XRWebGLBinding.createEquirectLayer";
383
+ const nativeLayer = this._createGraphicsLayer("XREquirectLayer", factoryName, factorySupported, options, (binding, init) => binding.createEquirectLayer(init), (binding, init) => binding.createEquirectLayer(init), (webGLInit, webGPUInit) => {
384
+ webGPUInit.transform = webGLInit.transform;
385
+ webGPUInit.radius = webGLInit.radius;
386
+ webGPUInit.centralHorizontalAngle = webGLInit.centralHorizontalAngle;
387
+ webGPUInit.upperVerticalAngle = webGLInit.upperVerticalAngle;
388
+ webGPUInit.lowerVerticalAngle = webGLInit.lowerVerticalAngle;
389
+ });
390
+ if (nativeLayer || options.fallbackMode !== "mesh") {
391
+ return nativeLayer;
392
+ }
393
+ return this._createFallbackLayer("XREquirectLayer", options.transformNode, options.layerInit?.transform, undefined, {
394
+ radius: options.layerInit?.radius,
395
+ centralHorizontalAngle: options.layerInit?.centralHorizontalAngle,
396
+ upperVerticalAngle: options.layerInit?.upperVerticalAngle,
397
+ lowerVerticalAngle: options.layerInit?.lowerVerticalAngle,
398
+ }, options.fallbackTexture);
399
+ }
400
+ /**
401
+ * Creates a graphics-backed cube layer and adds it to the current XR session.
402
+ * Cube layers synchronize only the rotation of their transform node because the WebXR API does not support cube-layer translation.
403
+ * @param options initialization and transform-node options for the layer
404
+ * @returns the created layer wrapper, or `null` when the active graphics binding does not support cube layers
405
+ */
406
+ createCubeLayer(options = {}) {
407
+ const factorySupported = this._isWebGPU ? typeof this._xrGPUBinding?.createCubeLayer === "function" : typeof this._xrWebGLBinding.createCubeLayer === "function";
408
+ const factoryName = this._isWebGPU ? "XRGPUBinding.createCubeLayer" : "XRWebGLBinding.createCubeLayer";
409
+ const nativeLayer = this._createGraphicsLayer("XRCubeLayer", factoryName, factorySupported, options, (binding, init) => binding.createCubeLayer(init), (binding, init) => binding.createCubeLayer(init), (webGLInit, webGPUInit) => {
410
+ webGPUInit.orientation = webGLInit.orientation;
411
+ });
412
+ if (nativeLayer || options.fallbackMode !== "mesh") {
413
+ return nativeLayer;
414
+ }
415
+ return this._createFallbackLayer("XRCubeLayer", options.transformNode, undefined, options.layerInit?.orientation, {}, options.fallbackTexture);
416
+ }
417
+ /**
418
+ * Creates a video-backed quad layer and adds it to the current XR session.
419
+ * @see https://playground.babylonjs.com/#D35HOL#0
420
+ * @param video the video element presented by the XR compositor
421
+ * @param options initialization and transform-node options for the layer
422
+ * @returns the created media layer wrapper, or `null` when XRMediaBinding is unavailable
423
+ */
424
+ createMediaQuadLayer(video, options = {}) {
425
+ const nativeLayer = this._createMediaLayer("XRQuadLayer", "createQuadLayer", video, options, (binding, media, init) => binding.createQuadLayer(media, init));
426
+ if (nativeLayer || options.fallbackMode !== "mesh") {
427
+ return nativeLayer;
428
+ }
429
+ return this._createFallbackLayer("XRQuadLayer", options.transformNode, options.layerInit?.transform, undefined, { width: options.layerInit?.width, height: options.layerInit?.height }, undefined, video);
430
+ }
431
+ /**
432
+ * Creates a video-backed cylinder layer and adds it to the current XR session.
433
+ * @param video the video element presented by the XR compositor
434
+ * @param options initialization and transform-node options for the layer
435
+ * @returns the created media layer wrapper, or `null` when XRMediaBinding is unavailable
436
+ */
437
+ createMediaCylinderLayer(video, options = {}) {
438
+ const nativeLayer = this._createMediaLayer("XRCylinderLayer", "createCylinderLayer", video, options, (binding, media, init) => binding.createCylinderLayer(media, init));
439
+ if (nativeLayer || options.fallbackMode !== "mesh") {
440
+ return nativeLayer;
441
+ }
442
+ return this._createFallbackLayer("XRCylinderLayer", options.transformNode, options.layerInit?.transform, undefined, {
443
+ radius: options.layerInit?.radius,
444
+ centralAngle: options.layerInit?.centralAngle,
445
+ aspectRatio: options.layerInit?.aspectRatio,
446
+ }, undefined, video);
447
+ }
448
+ /**
449
+ * Creates a video-backed equirectangular layer and adds it to the current XR session.
450
+ * @param video the video element presented by the XR compositor
451
+ * @param options initialization and transform-node options for the layer
452
+ * @returns the created media layer wrapper, or `null` when XRMediaBinding is unavailable
453
+ */
454
+ createMediaEquirectLayer(video, options = {}) {
455
+ const nativeLayer = this._createMediaLayer("XREquirectLayer", "createEquirectLayer", video, options, (binding, media, init) => binding.createEquirectLayer(media, init));
456
+ if (nativeLayer || options.fallbackMode !== "mesh") {
457
+ return nativeLayer;
458
+ }
459
+ return this._createFallbackLayer("XREquirectLayer", options.transformNode, options.layerInit?.transform, undefined, {
460
+ radius: options.layerInit?.radius,
461
+ centralHorizontalAngle: options.layerInit?.centralHorizontalAngle,
462
+ upperVerticalAngle: options.layerInit?.upperVerticalAngle,
463
+ lowerVerticalAngle: options.layerInit?.lowerVerticalAngle,
464
+ }, undefined, video);
465
+ }
144
466
  _createQuadLayer(options = { params: {} }, babylonTexture) {
145
- this._extendXRLayerInit(options.params, false);
146
- const width = this._existingLayers[0].layer.textureWidth;
147
- const height = this._existingLayers[0].layer.textureHeight;
148
- const populatedParams = {
149
- space: this._xrSessionManager.referenceSpace,
150
- viewPixelWidth: width,
151
- viewPixelHeight: height,
152
- clearOnAccess: true,
153
- ...options.params,
154
- };
155
- this._validateLayerInit(populatedParams, false);
156
- let quadLayer;
157
- let wrapper;
158
467
  if (this._isWebGPU) {
159
468
  const binding = this._xrGPUBinding;
160
469
  if (typeof binding.createQuadLayer !== "function") {
@@ -165,48 +474,17 @@ export class WebXRLayers extends WebXRAbstractFeature {
165
474
  Logger.Warn(WebGPUQuadLayerSubImageWarning);
166
475
  return null;
167
476
  }
168
- const gpuParams = {
169
- colorFormat: binding.getPreferredColorFormat(),
170
- // GPUTextureUsage.RENDER_ATTACHMENT (0x10) is requested explicitly. The usage of a
171
- // compositor-owned sub-image texture is not a valid source for layer creation flags.
172
- textureUsage: 0x10,
173
- space: populatedParams.space,
174
- viewPixelWidth: populatedParams.viewPixelWidth,
175
- viewPixelHeight: populatedParams.viewPixelHeight,
176
- };
177
- if (populatedParams.layout !== undefined) {
178
- gpuParams.layout = populatedParams.layout;
179
- }
180
- if (populatedParams.mipLevels !== undefined) {
181
- gpuParams.mipLevels = populatedParams.mipLevels;
182
- }
183
- if (populatedParams.isStatic !== undefined) {
184
- gpuParams.isStatic = populatedParams.isStatic;
185
- }
186
- if (populatedParams.transform !== undefined) {
187
- gpuParams.transform = populatedParams.transform;
188
- }
189
- if (populatedParams.width !== undefined) {
190
- gpuParams.width = populatedParams.width;
191
- }
192
- if (populatedParams.height !== undefined) {
193
- gpuParams.height = populatedParams.height;
194
- }
195
- quadLayer = binding.createQuadLayer(gpuParams);
196
- wrapper = new WebXRWebGPUCompositionLayerWrapper(() => quadLayer.width, () => quadLayer.height, quadLayer, "XRQuadLayer", false, (sessionManager) => new WebXRWebGPUCompositionLayerRenderTargetTextureProvider(sessionManager, binding, wrapper));
197
477
  }
198
- else {
199
- quadLayer = this._xrWebGLBinding.createQuadLayer(populatedParams);
200
- wrapper = new WebXRCompositionLayerWrapper(() => quadLayer.width, () => quadLayer.height, quadLayer, "XRQuadLayer", false, (sessionManager) => new WebXRCompositionLayerRenderTargetTextureProvider(sessionManager, this._xrWebGLBinding, wrapper));
478
+ const wrapper = this.createQuadLayer({ layerInit: options.params });
479
+ if (!wrapper || wrapper.layer === null) {
480
+ return null;
201
481
  }
482
+ const quadLayer = wrapper.layer;
202
483
  quadLayer.width = this._isMultiviewEnabled ? 1 : 2;
203
484
  quadLayer.height = 1;
204
485
  if (babylonTexture) {
205
486
  this._compositionLayerTextureMapping.set(quadLayer, babylonTexture);
206
487
  }
207
- const rtt = wrapper.createRenderTargetTextureProvider(this._xrSessionManager);
208
- this._layerToRTTProviderMapping.set(quadLayer, rtt);
209
- this.addXRSessionLayer(wrapper);
210
488
  return wrapper;
211
489
  }
212
490
  /**
@@ -228,13 +506,12 @@ export class WebXRLayers extends WebXRAbstractFeature {
228
506
  if (!wrapper) {
229
507
  return null;
230
508
  }
231
- const layer = wrapper.layer;
232
509
  const distance = Math.max(0.1, options.distanceFromHeadset);
233
- const pos = { x: 0, y: 0, z: -distance };
234
- const orient = { x: 0, y: 0, z: 0, w: 1 };
235
- layer.transform = new XRRigidTransform(pos, orient);
236
- const rttProvider = this._layerToRTTProviderMapping.get(layer);
237
- if (!rttProvider) {
510
+ const z = this._xrSessionManager.scene.useRightHandedSystem ? -distance : distance;
511
+ wrapper.transformNode.position.set(0, 0, z * this._xrSessionManager.worldScalingFactor);
512
+ const rttProvider = this._layerToRTTProviderMapping.get(wrapper.layer);
513
+ if (!rttProvider ||
514
+ (!(rttProvider instanceof WebXRCompositionLayerRenderTargetTextureProvider) && !(rttProvider instanceof WebXRWebGPUCompositionLayerRenderTargetTextureProvider))) {
238
515
  throw new Error("Could not find the RTT provider for the layer");
239
516
  }
240
517
  const babylonLayer = this._xrSessionManager.scene.layers.find((babylonLayer) => {
@@ -243,25 +520,43 @@ export class WebXRLayers extends WebXRAbstractFeature {
243
520
  if (!babylonLayer) {
244
521
  throw new Error("Could not find the babylon layer for the texture");
245
522
  }
246
- rttProvider.onRenderTargetTextureCreatedObservable.add((data) => {
523
+ const renderTargetTextures = new Set();
524
+ const beforeRenderObservers = [];
525
+ const previousRenderOnlyInRenderTargetTextures = babylonLayer.renderOnlyInRenderTargetTextures;
526
+ let cleanedUp = false;
527
+ const renderTargetCreatedObserver = rttProvider.onRenderTargetTextureCreatedObservable.add((data) => {
247
528
  if (data.eye && data.eye === "right") {
248
529
  return;
249
530
  }
250
531
  data.texture.clearColor = new Color4(0, 0, 0, 0);
251
532
  babylonLayer.renderTargetTextures.push(data.texture);
533
+ renderTargetTextures.add(data.texture);
252
534
  babylonLayer.renderOnlyInRenderTargetTextures = true;
253
535
  // for stereo (not for gui) it should be onBeforeCameraRenderObservable
254
- this._xrSessionManager.scene.onBeforeRenderObservable.add(() => {
536
+ beforeRenderObservers.push(this._xrSessionManager.scene.onBeforeRenderObservable.add(() => {
255
537
  data.texture.render();
256
- });
257
- babylonLayer.renderTargetTextures.push(data.texture);
258
- babylonLayer.renderOnlyInRenderTargetTextures = true;
259
- // add it back when the session ends
260
- this._xrSessionManager.onXRSessionEnded.addOnce(() => {
261
- babylonLayer.renderTargetTextures.splice(babylonLayer.renderTargetTextures.indexOf(data.texture), 1);
262
- babylonLayer.renderOnlyInRenderTargetTextures = false;
263
- });
538
+ }));
264
539
  });
540
+ const cleanup = () => {
541
+ if (cleanedUp) {
542
+ return;
543
+ }
544
+ cleanedUp = true;
545
+ rttProvider.onRenderTargetTextureCreatedObservable.remove(renderTargetCreatedObserver);
546
+ for (const observer of beforeRenderObservers) {
547
+ this._xrSessionManager.scene.onBeforeRenderObservable.remove(observer);
548
+ }
549
+ for (const renderTargetTexture of renderTargetTextures) {
550
+ const index = babylonLayer.renderTargetTextures.indexOf(renderTargetTexture);
551
+ if (index !== -1) {
552
+ babylonLayer.renderTargetTextures.splice(index, 1);
553
+ }
554
+ }
555
+ babylonLayer.renderOnlyInRenderTargetTextures = previousRenderOnlyInRenderTargetTextures;
556
+ this._layerCleanupFunctions.delete(wrapper);
557
+ };
558
+ this._layerCleanupFunctions.set(wrapper, cleanup);
559
+ this._xrSessionManager.onXRSessionEnded.addOnce(cleanup);
265
560
  return wrapper;
266
561
  }
267
562
  /**
@@ -287,12 +582,12 @@ export class WebXRLayers extends WebXRAbstractFeature {
287
582
  layer.width = 2;
288
583
  layer.height = 1;
289
584
  const distance = 10;
290
- const pos = { x: 0, y: 0, z: -distance };
291
- const orient = { x: 0, y: 0, z: 0, w: 1 };
292
- layer.transform = new XRRigidTransform(pos, orient);
585
+ const z = this._xrSessionManager.scene.useRightHandedSystem ? -distance : distance;
586
+ wrapper.transformNode.position.set(0, 0, z * this._xrSessionManager.worldScalingFactor);
293
587
  // get the rtt wrapper
294
588
  const rttProvider = this._layerToRTTProviderMapping.get(layer);
295
- if (!rttProvider) {
589
+ if (!rttProvider ||
590
+ (!(rttProvider instanceof WebXRCompositionLayerRenderTargetTextureProvider) && !(rttProvider instanceof WebXRWebGPUCompositionLayerRenderTargetTextureProvider))) {
296
591
  throw new Error("Could not find the RTT provider for the layer");
297
592
  }
298
593
  // render the flare system to the rtt
@@ -324,6 +619,53 @@ export class WebXRLayers extends WebXRAbstractFeature {
324
619
  this._existingLayers.push(wrappedLayer);
325
620
  this.setXRSessionLayers(this._existingLayers);
326
621
  }
622
+ /**
623
+ * Removes a non-projection layer from the current XR session.
624
+ * @param wrappedLayer the layer wrapper to remove
625
+ * @param dispose whether to dispose the wrapper and destroy its native composition layer
626
+ * @returns whether the layer was present and removed
627
+ */
628
+ removeXRSessionLayer(wrappedLayer, dispose = true) {
629
+ const index = this._existingLayers.indexOf(wrappedLayer);
630
+ if (index === -1) {
631
+ return false;
632
+ }
633
+ if (wrappedLayer.layerType === "XRProjectionLayer") {
634
+ Logger.Warn("The active projection layer cannot be removed from WebXRLayers.");
635
+ return false;
636
+ }
637
+ this._existingLayers.splice(index, 1);
638
+ this._layerCleanupFunctions.get(wrappedLayer)?.();
639
+ if (wrappedLayer instanceof WebXRCompositionLayerWrapper) {
640
+ this._layerToRTTProviderMapping.delete(wrappedLayer.layer);
641
+ this._compositionLayerTextureMapping.delete(wrappedLayer.layer);
642
+ }
643
+ this.setXRSessionLayers(this._existingLayers);
644
+ if (dispose) {
645
+ wrappedLayer.dispose();
646
+ }
647
+ return true;
648
+ }
649
+ /**
650
+ * Removes either a native spatial layer or a fallback layer created by this feature.
651
+ * @param wrappedLayer the native or fallback layer wrapper to remove
652
+ * @param dispose whether to dispose resources owned by the wrapper
653
+ * @returns whether the wrapper was present and removed
654
+ */
655
+ removeLayer(wrappedLayer, dispose = true) {
656
+ if (wrappedLayer.layer === null) {
657
+ const index = this._fallbackLayers.indexOf(wrappedLayer);
658
+ if (index === -1) {
659
+ return false;
660
+ }
661
+ this._fallbackLayers.splice(index, 1);
662
+ if (dispose) {
663
+ wrappedLayer.dispose();
664
+ }
665
+ return true;
666
+ }
667
+ return this.removeXRSessionLayer(wrappedLayer, dispose);
668
+ }
327
669
  /**
328
670
  * Sets the layers to be used by the XR session.
329
671
  * Note that you must call this function with any layers you wish to render to
@@ -344,6 +686,60 @@ export class WebXRLayers extends WebXRAbstractFeature {
344
686
  this._xrSessionManager._setBaseLayerWrapper(wrappedLayers.length > 0 ? wrappedLayers.at(0) : null);
345
687
  }
346
688
  }
689
+ /**
690
+ * Checks whether the active runtime exposes the factory needed for a layer type.
691
+ * This is a capability check only; creation can still fail when an initialization dictionary is invalid.
692
+ * @param layerType the concrete WebXR layer type
693
+ * @param source whether to check a graphics-backed or media-backed layer
694
+ * @returns whether the requested factory is available
695
+ */
696
+ isLayerTypeSupported(layerType, source = "graphics") {
697
+ if (source === "media") {
698
+ if (layerType === "XRProjectionLayer" || layerType === "XRCubeLayer" || typeof XRMediaBinding === "undefined") {
699
+ return false;
700
+ }
701
+ switch (layerType) {
702
+ case "XRQuadLayer":
703
+ return typeof XRMediaBinding.prototype.createQuadLayer === "function";
704
+ case "XRCylinderLayer":
705
+ return typeof XRMediaBinding.prototype.createCylinderLayer === "function";
706
+ case "XREquirectLayer":
707
+ return typeof XRMediaBinding.prototype.createEquirectLayer === "function";
708
+ }
709
+ }
710
+ if (this._xrSessionManager.scene.getEngine().isWebGPU) {
711
+ if (typeof XRGPUBinding === "undefined") {
712
+ return false;
713
+ }
714
+ switch (layerType) {
715
+ case "XRProjectionLayer":
716
+ return typeof XRGPUBinding.prototype.createProjectionLayer === "function";
717
+ case "XRQuadLayer":
718
+ return typeof XRGPUBinding.prototype.createQuadLayer === "function";
719
+ case "XRCylinderLayer":
720
+ return typeof XRGPUBinding.prototype.createCylinderLayer === "function";
721
+ case "XREquirectLayer":
722
+ return typeof XRGPUBinding.prototype.createEquirectLayer === "function";
723
+ case "XRCubeLayer":
724
+ return typeof XRGPUBinding.prototype.createCubeLayer === "function";
725
+ }
726
+ }
727
+ if (typeof XRWebGLBinding === "undefined") {
728
+ return false;
729
+ }
730
+ switch (layerType) {
731
+ case "XRProjectionLayer":
732
+ return typeof XRWebGLBinding.prototype.createProjectionLayer === "function";
733
+ case "XRQuadLayer":
734
+ return typeof XRWebGLBinding.prototype.createQuadLayer === "function";
735
+ case "XRCylinderLayer":
736
+ return typeof XRWebGLBinding.prototype.createCylinderLayer === "function";
737
+ case "XREquirectLayer":
738
+ return typeof XRWebGLBinding.prototype.createEquirectLayer === "function";
739
+ case "XRCubeLayer":
740
+ return typeof XRWebGLBinding.prototype.createCubeLayer === "function";
741
+ }
742
+ }
347
743
  isCompatible() {
348
744
  if (this._xrSessionManager.scene.getEngine().isWebGPU) {
349
745
  return typeof XRGPUBinding !== "undefined" && !!XRGPUBinding.prototype.createProjectionLayer;
@@ -361,30 +757,36 @@ export class WebXRLayers extends WebXRAbstractFeature {
361
757
  super.dispose();
362
758
  }
363
759
  _onXRFrame(_xrFrame) {
364
- // Replace once the mapped internal texture of each available composition layer, apart from the last one, which is the projection layer that needs an RTT
760
+ for (let i = 0; i < this._fallbackLayers.length; ++i) {
761
+ this._fallbackLayers[i].updateFromTransformNode(this._xrSessionManager.worldScalingFactor);
762
+ }
365
763
  const layers = this._existingLayers;
366
764
  for (let i = 0; i < layers.length; ++i) {
367
765
  const layer = layers[i];
368
- if (layer.layerType !== "XRProjectionLayer") {
369
- // get the rtt provider
370
- const rttProvider = this._layerToRTTProviderMapping.get(layer.layer);
371
- if (!rttProvider) {
372
- continue;
373
- }
374
- if (rttProvider.layerWrapper.isMultiview) {
375
- // get the views, if we are in multiview
376
- const pose = _xrFrame.getViewerPose(this._xrSessionManager.referenceSpace);
377
- if (pose) {
378
- const views = pose.views;
379
- for (let j = 0; j < views.length; ++j) {
380
- const view = views[j];
381
- rttProvider.getRenderTargetTextureForView(view);
382
- }
766
+ if (layer instanceof WebXRSpatialLayerWrapper) {
767
+ layer.updateFromTransformNode(this._xrSessionManager.scene.useRightHandedSystem, this._xrSessionManager.worldScalingFactor);
768
+ }
769
+ if (layer.layerType === "XRProjectionLayer" || !(layer instanceof WebXRCompositionLayerWrapper) || !layer.usesRenderTargetProvider) {
770
+ continue;
771
+ }
772
+ if (layer.isStatic && !layer.layer.needsRedraw) {
773
+ continue;
774
+ }
775
+ const rttProvider = this._layerToRTTProviderMapping.get(layer.layer);
776
+ if (!rttProvider) {
777
+ continue;
778
+ }
779
+ if (layer.layer.layout === "mono") {
780
+ rttProvider.getRenderTargetTextureForEye("none");
781
+ }
782
+ else {
783
+ const pose = _xrFrame.getViewerPose(this._xrSessionManager.referenceSpace);
784
+ if (pose) {
785
+ const views = pose.views;
786
+ for (let j = 0; j < views.length; ++j) {
787
+ rttProvider.getRenderTargetTextureForView(views[j]);
383
788
  }
384
789
  }
385
- else {
386
- rttProvider.getRenderTargetTextureForView();
387
- }
388
790
  }
389
791
  }
390
792
  }