@onerjs/core 8.55.8 → 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.
- package/Animations/animation.pure.js +2 -2
- package/Animations/animation.pure.js.map +1 -1
- package/Animations/runtimeAnimation.js +4 -0
- package/Animations/runtimeAnimation.js.map +1 -1
- package/Behaviors/Cameras/autoRotationBehavior.js +1 -1
- package/Behaviors/Cameras/autoRotationBehavior.js.map +1 -1
- package/Behaviors/Meshes/followBehavior.js +1 -0
- package/Behaviors/Meshes/followBehavior.js.map +1 -1
- package/Behaviors/Meshes/surfaceMagnetismBehavior.js +1 -0
- package/Behaviors/Meshes/surfaceMagnetismBehavior.js.map +1 -1
- package/Cameras/Inputs/followCameraMouseWheelInput.js +2 -2
- package/Cameras/Inputs/followCameraMouseWheelInput.js.map +1 -1
- package/Cameras/Inputs/followCameraPointersInput.d.ts +15 -0
- package/Cameras/Inputs/followCameraPointersInput.js +18 -3
- package/Cameras/Inputs/followCameraPointersInput.js.map +1 -1
- package/Cameras/Stereoscopic/stereoscopicScreenUniversalCamera.js +1 -1
- package/Cameras/Stereoscopic/stereoscopicScreenUniversalCamera.js.map +1 -1
- package/Cameras/Stereoscopic/stereoscopicUniversalCamera.pure.js +1 -1
- package/Cameras/Stereoscopic/stereoscopicUniversalCamera.pure.js.map +1 -1
- package/Cameras/arcRotateCamera.pure.js +1 -1
- package/Cameras/arcRotateCamera.pure.js.map +1 -1
- package/Collisions/gpuPicker.d.ts +1 -0
- package/Collisions/gpuPicker.js +5 -4
- package/Collisions/gpuPicker.js.map +1 -1
- package/Culling/Helper/boundingInfoHelper.js +1 -1
- package/Culling/Helper/boundingInfoHelper.js.map +1 -1
- package/Culling/boundingSphere.js +7 -4
- package/Culling/boundingSphere.js.map +1 -1
- package/Engines/Extensions/engine.prefilteredCubeTexture.pure.js +1 -1
- package/Engines/Extensions/engine.prefilteredCubeTexture.pure.js.map +1 -1
- package/Engines/Native/Extensions/nativeEngine.cubeTexture.pure.js +48 -6
- package/Engines/Native/Extensions/nativeEngine.cubeTexture.pure.js.map +1 -1
- package/Engines/Native/nativeInterfaces.d.ts +1 -1
- package/Engines/Native/nativeInterfaces.js.map +1 -1
- package/Engines/abstractEngine.pure.js +2 -2
- package/Engines/abstractEngine.pure.js.map +1 -1
- package/Engines/engine.d.ts +10 -1
- package/Engines/thinNativeEngine.pure.d.ts +6 -1
- package/Engines/thinNativeEngine.pure.js +29 -2
- package/Engines/thinNativeEngine.pure.js.map +1 -1
- package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.d.ts +3 -63
- package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.js +5 -71
- package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.js.map +1 -1
- package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.pure.d.ts +71 -0
- package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.pure.js +86 -0
- package/FlowGraph/Blocks/Data/flowGraphIsKeyPressedBlock.pure.js.map +1 -0
- package/FlowGraph/Blocks/Data/pure.d.ts +1 -0
- package/FlowGraph/Blocks/Data/pure.js +1 -0
- package/FlowGraph/Blocks/Data/pure.js.map +1 -1
- package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.d.ts +3 -37
- package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.js +5 -39
- package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.js.map +1 -1
- package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.pure.d.ts +45 -0
- package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.pure.js +54 -0
- package/FlowGraph/Blocks/Event/flowGraphKeyDownEventBlock.pure.js.map +1 -0
- package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.d.ts +3 -17
- package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.js +5 -22
- package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.js.map +1 -1
- package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.pure.d.ts +25 -0
- package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.pure.js +37 -0
- package/FlowGraph/Blocks/Event/flowGraphKeyUpEventBlock.pure.js.map +1 -0
- package/FlowGraph/Blocks/Event/pure.d.ts +2 -0
- package/FlowGraph/Blocks/Event/pure.js +2 -0
- package/FlowGraph/Blocks/Event/pure.js.map +1 -1
- package/FlowGraph/Blocks/flowGraphBlockFactory.d.ts +1 -1
- package/FlowGraph/Blocks/flowGraphBlockFactory.js +198 -172
- package/FlowGraph/Blocks/flowGraphBlockFactory.js.map +1 -1
- package/FrameGraph/frameGraph.js +10 -1
- package/FrameGraph/frameGraph.js.map +1 -1
- package/Gamepads/gamepadManager.d.ts +1 -0
- package/Gamepads/gamepadManager.js +5 -2
- package/Gamepads/gamepadManager.js.map +1 -1
- package/Gizmos/scaleGizmo.js +1 -0
- package/Gizmos/scaleGizmo.js.map +1 -1
- package/Lights/IES/iesLoader.js +6 -8
- package/Lights/IES/iesLoader.js.map +1 -1
- package/Lights/Shadows/cascadedShadowGenerator.pure.js +4 -6
- package/Lights/Shadows/cascadedShadowGenerator.pure.js.map +1 -1
- package/Lights/Shadows/shadowGenerator.js +2 -2
- package/Lights/Shadows/shadowGenerator.js.map +1 -1
- package/Lights/light.js +3 -5
- package/Lights/light.js.map +1 -1
- package/Lights/spotLight.pure.js +1 -1
- package/Lights/spotLight.pure.js.map +1 -1
- package/Materials/Background/backgroundMaterial.pure.d.ts +1 -1
- package/Materials/Background/backgroundMaterial.pure.js +3 -12
- package/Materials/Background/backgroundMaterial.pure.js.map +1 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js +2 -0
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.pure.js.map +1 -1
- package/Materials/Node/Blocks/Fragment/TBNBlock.pure.js +1 -1
- package/Materials/Node/Blocks/Fragment/TBNBlock.pure.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.pure.d.ts +1 -1
- package/Materials/PBR/openpbrMaterial.pure.js +3 -12
- package/Materials/PBR/openpbrMaterial.pure.js.map +1 -1
- package/Materials/PBR/pbrBaseMaterial.pure.d.ts +1 -1
- package/Materials/PBR/pbrBaseMaterial.pure.js +3 -12
- package/Materials/PBR/pbrBaseMaterial.pure.js.map +1 -1
- package/Materials/Textures/renderTargetTexture.pure.js +1 -1
- package/Materials/Textures/renderTargetTexture.pure.js.map +1 -1
- package/Materials/material.pure.js +2 -2
- package/Materials/material.pure.js.map +1 -1
- package/Materials/standardMaterial.pure.d.ts +1 -1
- package/Materials/standardMaterial.pure.js +4 -13
- package/Materials/standardMaterial.pure.js.map +1 -1
- package/Maths/math.path.js +1 -1
- package/Maths/math.path.js.map +1 -1
- package/Maths/math.polar.js +1 -1
- package/Maths/math.polar.js.map +1 -1
- package/Maths/math.vector.pure.js +4 -3
- package/Maths/math.vector.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.d.ts +72 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js +164 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.d.ts +2 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js +36 -18
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.pure.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.pure.d.ts +5 -4
- package/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.pure.js +25 -8
- package/Meshes/GaussianSplatting/gaussianSplattingPartProxyMesh.pure.js.map +1 -1
- package/Meshes/GreasedLine/greasedLineRibbonMesh.pure.js +3 -3
- package/Meshes/GreasedLine/greasedLineRibbonMesh.pure.js.map +1 -1
- package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.pure.js +1 -1
- package/Meshes/Node/Blocks/Instances/instantiateOnVolumeBlock.pure.js.map +1 -1
- package/Meshes/Node/Blocks/geometryOptimizeBlock.pure.js +2 -2
- package/Meshes/Node/Blocks/geometryOptimizeBlock.pure.js.map +1 -1
- package/Meshes/Node/Blocks/mappingBlock.pure.js +2 -2
- package/Meshes/Node/Blocks/mappingBlock.pure.js.map +1 -1
- package/Meshes/csg.js +5 -5
- package/Meshes/csg.js.map +1 -1
- package/Meshes/groundMesh.pure.js +1 -1
- package/Meshes/groundMesh.pure.js.map +1 -1
- package/Meshes/mesh.pure.js +2 -2
- package/Meshes/mesh.pure.js.map +1 -1
- package/Misc/deepMerger.js +1 -1
- package/Misc/deepMerger.js.map +1 -1
- package/Misc/dumpTools.pure.js +1 -1
- package/Misc/dumpTools.pure.js.map +1 -1
- package/Misc/index.d.ts +1 -0
- package/Misc/index.js +1 -0
- package/Misc/index.js.map +1 -1
- package/Misc/pure.d.ts +1 -0
- package/Misc/pure.js +1 -0
- package/Misc/pure.js.map +1 -1
- package/Misc/shaderImportLoader.d.ts +25 -0
- package/Misc/shaderImportLoader.js +54 -0
- package/Misc/shaderImportLoader.js.map +1 -0
- package/Misc/tools.pure.js +1 -1
- package/Misc/tools.pure.js.map +1 -1
- package/Particles/Node/Blocks/particleClampBlock.pure.d.ts +0 -1
- package/Particles/Node/Blocks/particleClampBlock.pure.js +1 -6
- package/Particles/Node/Blocks/particleClampBlock.pure.js.map +1 -1
- package/Particles/Node/Blocks/particleMathBlock.pure.js +1 -1
- package/Particles/Node/Blocks/particleMathBlock.pure.js.map +1 -1
- package/Particles/Node/Blocks/particleNLerpBlock.pure.js +8 -3
- package/Particles/Node/Blocks/particleNLerpBlock.pure.js.map +1 -1
- package/Particles/Node/Blocks/particleSmoothStepBlock.pure.js +3 -2
- package/Particles/Node/Blocks/particleSmoothStepBlock.pure.js.map +1 -1
- package/Particles/Node/Blocks/particleStepBlock.pure.js +3 -2
- package/Particles/Node/Blocks/particleStepBlock.pure.js.map +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.pure.js +1 -1
- package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.pure.js.map +1 -1
- package/PostProcesses/depthOfFieldEffect.js +1 -1
- package/PostProcesses/depthOfFieldEffect.js.map +1 -1
- package/PostProcesses/screenSpaceCurvaturePostProcess.pure.js +1 -1
- package/PostProcesses/screenSpaceCurvaturePostProcess.pure.js.map +1 -1
- package/PostProcesses/sharpenPostProcess.pure.js +1 -1
- package/PostProcesses/sharpenPostProcess.pure.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.d.ts +12 -0
- package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js +15 -1
- package/Rendering/IBLShadows/iblShadowsRenderPipeline.pure.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.d.ts +14 -0
- package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.js +122 -6
- package/Rendering/IBLShadows/iblShadowsVoxelRenderer.pure.js.map +1 -1
- package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.d.ts +7 -0
- package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.js +17 -0
- package/Rendering/IBLShadows/iblShadowsVoxelTracingPass.js.map +1 -1
- package/Rendering/boundingBoxRenderer.pure.js +3 -3
- package/Rendering/boundingBoxRenderer.pure.js.map +1 -1
- package/Rendering/outlineRenderer.pure.js +1 -0
- package/Rendering/outlineRenderer.pure.js.map +1 -1
- package/Rendering/subSurfaceConfiguration.js +1 -1
- package/Rendering/subSurfaceConfiguration.js.map +1 -1
- package/Rendering/subSurfaceSceneComponent.pure.d.ts +1 -1
- package/Rendering/subSurfaceSceneComponent.pure.js +1 -1
- package/Rendering/subSurfaceSceneComponent.pure.js.map +1 -1
- package/Rendering/utilityLayerRenderer.js +1 -1
- package/Rendering/utilityLayerRenderer.js.map +1 -1
- package/Shaders/gaussianSplattingVoxel.fragment.js +4 -10
- package/Shaders/gaussianSplattingVoxel.fragment.js.map +1 -1
- package/Shaders/iblCombineVoxelGrids.fragment.js +1 -1
- package/Shaders/iblCombineVoxelGrids.fragment.js.map +1 -1
- package/Shaders/iblShadowVoxelTracing.fragment.js +24 -7
- package/Shaders/iblShadowVoxelTracing.fragment.js.map +1 -1
- package/ShadersWGSL/ShadersInclude/iblVoxelOpacityAtomicMax.d.ts +5 -0
- package/ShadersWGSL/ShadersInclude/iblVoxelOpacityAtomicMax.js +13 -0
- package/ShadersWGSL/ShadersInclude/iblVoxelOpacityAtomicMax.js.map +1 -0
- package/ShadersWGSL/gaussianSplattingVoxel.fragment.js +15 -9
- package/ShadersWGSL/gaussianSplattingVoxel.fragment.js.map +1 -1
- package/ShadersWGSL/iblCombineVoxelGrids.fragment.js +1 -1
- package/ShadersWGSL/iblCombineVoxelGrids.fragment.js.map +1 -1
- package/ShadersWGSL/iblCopyVoxelBufferToGrid.compute.d.ts +5 -0
- package/ShadersWGSL/iblCopyVoxelBufferToGrid.compute.js +14 -0
- package/ShadersWGSL/iblCopyVoxelBufferToGrid.compute.js.map +1 -0
- package/ShadersWGSL/iblShadowVoxelTracing.fragment.js +24 -7
- package/ShadersWGSL/iblShadowVoxelTracing.fragment.js.map +1 -1
- package/ShadersWGSL/iblVoxelGrid.fragment.js +26 -6
- package/ShadersWGSL/iblVoxelGrid.fragment.js.map +1 -1
- package/SmartAssets/smartAssetManager.pure.js +1 -1
- package/SmartAssets/smartAssetManager.pure.js.map +1 -1
- package/Sprites/thinSprite.js +1 -1
- package/Sprites/thinSprite.js.map +1 -1
- package/XR/features/Layers/WebXRCompositionLayer.d.ts +130 -12
- package/XR/features/Layers/WebXRCompositionLayer.js +192 -3
- package/XR/features/Layers/WebXRCompositionLayer.js.map +1 -1
- package/XR/features/Layers/WebXRFallbackLayer.d.ts +84 -0
- package/XR/features/Layers/WebXRFallbackLayer.js +137 -0
- package/XR/features/Layers/WebXRFallbackLayer.js.map +1 -0
- package/XR/features/Layers/WebXRWebGPUCompositionLayer.d.ts +4 -4
- package/XR/features/Layers/WebXRWebGPUCompositionLayer.js.map +1 -1
- package/XR/features/WebXRAnchorSystem.pure.d.ts +45 -0
- package/XR/features/WebXRAnchorSystem.pure.js +153 -13
- package/XR/features/WebXRAnchorSystem.pure.js.map +1 -1
- package/XR/features/WebXRLayers.pure.d.ts +171 -8
- package/XR/features/WebXRLayers.pure.js +500 -98
- package/XR/features/WebXRLayers.pure.js.map +1 -1
- package/XR/features/WebXRLayersFallback.d.ts +5 -0
- package/XR/features/WebXRLayersFallback.js +8 -0
- package/XR/features/WebXRLayersFallback.js.map +1 -0
- package/XR/features/WebXRLayersFallback.pure.d.ts +6 -0
- package/XR/features/WebXRLayersFallback.pure.js +44 -0
- package/XR/features/WebXRLayersFallback.pure.js.map +1 -0
- package/XR/features/WebXRLightEstimation.pure.d.ts +3 -4
- package/XR/features/WebXRLightEstimation.pure.js +22 -21
- package/XR/features/WebXRLightEstimation.pure.js.map +1 -1
- package/XR/features/WebXRMeshDetector.pure.d.ts +5 -0
- package/XR/features/WebXRMeshDetector.pure.js +1 -0
- package/XR/features/WebXRMeshDetector.pure.js.map +1 -1
- package/XR/features/WebXRNearInteraction.pure.js +3 -3
- package/XR/features/WebXRNearInteraction.pure.js.map +1 -1
- package/XR/features/WebXRPlaneDetector.pure.d.ts +9 -5
- package/XR/features/WebXRPlaneDetector.pure.js +12 -8
- package/XR/features/WebXRPlaneDetector.pure.js.map +1 -1
- package/XR/features/pure.d.ts +1 -0
- package/XR/features/pure.js +1 -0
- package/XR/features/pure.js.map +1 -1
- package/XR/webXRCamera.d.ts +2 -0
- package/XR/webXRCamera.js +8 -2
- package/XR/webXRCamera.js.map +1 -1
- package/XR/webXRLayerWrapper.d.ts +19 -5
- package/XR/webXRLayerWrapper.js +9 -0
- package/XR/webXRLayerWrapper.js.map +1 -1
- package/XR/webXRRenderTargetTextureProvider.d.ts +4 -4
- package/XR/webXRRenderTargetTextureProvider.js.map +1 -1
- package/XR/webXRWebGLRenderTargetTextureProvider.d.ts +2 -1
- package/XR/webXRWebGLRenderTargetTextureProvider.js.map +1 -1
- package/XR/webXRWebGPURenderTargetTextureProvider.d.ts +3 -3
- package/XR/webXRWebGPURenderTargetTextureProvider.js.map +1 -1
- package/package.json +1 -1
- package/scene.pure.d.ts +5 -0
- package/scene.pure.js +25 -0
- 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
|
|
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(
|
|
117
|
-
const projLayer = this._xrWebGLBinding.createProjectionLayer(
|
|
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
|
-
*
|
|
140
|
-
* @param options
|
|
141
|
-
* @
|
|
142
|
-
|
|
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
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
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
|
|
291
|
-
|
|
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
|
-
|
|
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
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
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
|
}
|