super-three 0.172.0 → 0.173.0

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 (178) hide show
  1. package/LICENSE +1 -1
  2. package/build/three.cjs +439 -380
  3. package/build/three.core.js +413 -41
  4. package/build/three.core.min.js +2 -2
  5. package/build/three.module.js +28 -344
  6. package/build/three.module.min.js +2 -2
  7. package/build/three.tsl.js +11 -3
  8. package/build/three.tsl.min.js +2 -2
  9. package/build/three.webgpu.js +7550 -1798
  10. package/build/three.webgpu.min.js +2 -2
  11. package/build/three.webgpu.nodes.js +7551 -1798
  12. package/build/three.webgpu.nodes.min.js +2 -2
  13. package/examples/jsm/animation/CCDIKSolver.js +6 -5
  14. package/examples/jsm/capabilities/WebGPU.js +1 -1
  15. package/examples/jsm/controls/ArcballControls.js +23 -21
  16. package/examples/jsm/exporters/GLTFExporter.js +26 -25
  17. package/examples/jsm/geometries/TextGeometry.js +1 -12
  18. package/examples/jsm/interactive/InteractiveGroup.js +108 -51
  19. package/examples/jsm/libs/demuxer_mp4.js +109 -0
  20. package/examples/jsm/loaders/GCodeLoader.js +3 -1
  21. package/examples/jsm/loaders/GLTFLoader.js +0 -2
  22. package/examples/jsm/loaders/TDSLoader.js +0 -1
  23. package/examples/jsm/materials/MeshGouraudMaterial.js +2 -0
  24. package/examples/jsm/misc/GPUComputationRenderer.js +6 -7
  25. package/examples/jsm/misc/ProgressiveLightMap.js +4 -3
  26. package/examples/jsm/misc/ProgressiveLightMapGPU.js +4 -3
  27. package/examples/jsm/misc/Volume.js +7 -5
  28. package/examples/jsm/misc/VolumeSlice.js +5 -3
  29. package/examples/jsm/objects/WaterMesh.js +25 -20
  30. package/examples/jsm/physics/JoltPhysics.js +7 -7
  31. package/examples/jsm/physics/RapierPhysics.js +4 -4
  32. package/examples/jsm/postprocessing/OutputPass.js +2 -0
  33. package/examples/jsm/shaders/OutputShader.js +5 -1
  34. package/examples/jsm/transpiler/GLSLDecoder.js +2 -2
  35. package/examples/jsm/transpiler/TSLEncoder.js +2 -0
  36. package/package.json +1 -1
  37. package/src/Three.Core.js +2 -0
  38. package/src/Three.TSL.js +9 -1
  39. package/src/cameras/ArrayCamera.js +1 -0
  40. package/src/constants.js +6 -1
  41. package/src/core/BufferAttribute.js +4 -0
  42. package/src/core/EventDispatcher.js +8 -6
  43. package/src/extras/ImageUtils.js +1 -11
  44. package/src/loaders/nodes/NodeObjectLoader.js +1 -1
  45. package/src/materials/nodes/MeshBasicNodeMaterial.js +1 -1
  46. package/src/materials/nodes/MeshPhysicalNodeMaterial.js +1 -1
  47. package/src/materials/nodes/NodeMaterial.js +5 -5
  48. package/src/materials/nodes/NodeMaterials.js +0 -1
  49. package/src/materials/nodes/PointsNodeMaterial.js +109 -7
  50. package/src/materials/nodes/SpriteNodeMaterial.js +1 -1
  51. package/src/materials/nodes/VolumeNodeMaterial.js +3 -3
  52. package/src/materials/nodes/manager/NodeMaterialObserver.js +8 -0
  53. package/src/nodes/Nodes.js +4 -0
  54. package/src/nodes/TSL.js +4 -0
  55. package/src/nodes/accessors/Arrays.js +30 -8
  56. package/src/nodes/accessors/BatchNode.js +3 -3
  57. package/src/nodes/accessors/BufferAttributeNode.js +1 -1
  58. package/src/nodes/accessors/Camera.js +64 -3
  59. package/src/nodes/accessors/InstanceNode.js +1 -1
  60. package/src/nodes/accessors/MaterialNode.js +9 -9
  61. package/src/nodes/accessors/ModelViewProjectionNode.js +1 -1
  62. package/src/nodes/accessors/Normal.js +6 -2
  63. package/src/nodes/accessors/Object3DNode.js +0 -1
  64. package/src/nodes/accessors/Position.js +6 -6
  65. package/src/nodes/accessors/ReferenceBaseNode.js +2 -4
  66. package/src/nodes/accessors/ReferenceNode.js +2 -3
  67. package/src/nodes/accessors/StorageBufferNode.js +42 -5
  68. package/src/nodes/accessors/Tangent.js +2 -2
  69. package/src/nodes/accessors/Texture3DNode.js +1 -1
  70. package/src/nodes/accessors/TextureNode.js +12 -5
  71. package/src/nodes/accessors/UniformArrayNode.js +9 -3
  72. package/src/nodes/accessors/VelocityNode.js +0 -2
  73. package/src/nodes/code/ScriptableNode.js +3 -3
  74. package/src/nodes/core/ArrayNode.js +125 -0
  75. package/src/nodes/core/ConstNode.js +8 -0
  76. package/src/nodes/core/Node.js +14 -1
  77. package/src/nodes/core/NodeBuilder.js +229 -19
  78. package/src/nodes/core/NodeUtils.js +11 -1
  79. package/src/nodes/core/NodeVar.js +17 -1
  80. package/src/nodes/core/OutputStructNode.js +19 -9
  81. package/src/nodes/core/StackNode.js +20 -1
  82. package/src/nodes/core/StructNode.js +121 -0
  83. package/src/nodes/core/StructType.js +13 -0
  84. package/src/nodes/core/StructTypeNode.js +82 -21
  85. package/src/nodes/core/TempNode.js +1 -1
  86. package/src/nodes/core/VarNode.js +94 -7
  87. package/src/nodes/core/VaryingNode.js +19 -3
  88. package/src/nodes/display/BlendModes.js +88 -1
  89. package/src/nodes/display/BumpMapNode.js +6 -6
  90. package/src/nodes/display/NormalMapNode.js +6 -6
  91. package/src/nodes/display/PassNode.js +3 -1
  92. package/src/nodes/display/ScreenNode.js +9 -0
  93. package/src/nodes/fog/Fog.js +17 -0
  94. package/src/nodes/gpgpu/AtomicFunctionNode.js +20 -4
  95. package/src/nodes/gpgpu/ComputeBuiltinNode.js +8 -0
  96. package/src/nodes/gpgpu/WorkgroupInfoNode.js +1 -1
  97. package/src/nodes/lighting/ShadowNode.js +1 -1
  98. package/src/nodes/math/ConditionalNode.js +8 -1
  99. package/src/nodes/math/MathNode.js +14 -1
  100. package/src/nodes/math/OperatorNode.js +96 -18
  101. package/src/nodes/pmrem/PMREMUtils.js +1 -1
  102. package/src/nodes/shapes/Shapes.js +33 -0
  103. package/src/nodes/tsl/TSLBase.js +1 -0
  104. package/src/nodes/tsl/TSLCore.js +22 -2
  105. package/src/nodes/utils/ArrayElementNode.js +1 -1
  106. package/src/nodes/utils/LoopNode.js +8 -1
  107. package/src/nodes/utils/MemberNode.js +68 -0
  108. package/src/nodes/utils/StorageArrayElementNode.js +14 -0
  109. package/src/nodes/utils/Timer.js +21 -0
  110. package/src/objects/BatchedMesh.js +1 -1
  111. package/src/objects/Line.js +6 -6
  112. package/src/renderers/WebGLRenderer.js +7 -0
  113. package/src/renderers/common/Animation.js +23 -1
  114. package/src/renderers/common/Backend.js +58 -15
  115. package/src/renderers/common/Background.js +14 -0
  116. package/src/renderers/common/Binding.js +1 -1
  117. package/src/renderers/common/BufferUtils.js +1 -1
  118. package/src/renderers/common/BundleGroup.js +1 -1
  119. package/src/renderers/common/ChainMap.js +9 -7
  120. package/src/renderers/common/ClippingContext.js +1 -1
  121. package/src/renderers/common/Color4.js +7 -3
  122. package/src/renderers/common/Geometries.js +2 -23
  123. package/src/renderers/common/Info.js +1 -45
  124. package/src/renderers/common/Lighting.js +8 -6
  125. package/src/renderers/common/Pipelines.js +3 -3
  126. package/src/renderers/common/PostProcessing.js +24 -8
  127. package/src/renderers/common/QuadMesh.js +1 -1
  128. package/src/renderers/common/RenderBundles.js +9 -3
  129. package/src/renderers/common/RenderContext.js +37 -3
  130. package/src/renderers/common/RenderContexts.js +30 -17
  131. package/src/renderers/common/RenderList.js +2 -2
  132. package/src/renderers/common/RenderLists.js +9 -3
  133. package/src/renderers/common/RenderObject.js +76 -17
  134. package/src/renderers/common/RenderObjects.js +9 -7
  135. package/src/renderers/common/Renderer.js +86 -67
  136. package/src/renderers/common/SampledTexture.js +0 -1
  137. package/src/renderers/common/StorageBufferAttribute.js +1 -1
  138. package/src/renderers/common/StorageInstancedBufferAttribute.js +1 -1
  139. package/src/renderers/common/StorageTexture.js +1 -1
  140. package/src/renderers/common/Textures.js +14 -7
  141. package/src/renderers/common/TimestampQueryPool.js +39 -0
  142. package/src/renderers/common/Uniform.js +37 -1
  143. package/src/renderers/common/UniformsGroup.js +2 -0
  144. package/src/renderers/common/XRManager.js +1193 -0
  145. package/src/renderers/common/XRRenderTarget.js +74 -0
  146. package/src/renderers/common/extras/PMREMGenerator.js +53 -8
  147. package/src/renderers/common/nodes/NodeBuilderState.js +4 -4
  148. package/src/renderers/common/nodes/NodeLibrary.js +5 -5
  149. package/src/renderers/common/nodes/NodeSampledTexture.js +0 -1
  150. package/src/renderers/common/nodes/NodeUniform.js +54 -2
  151. package/src/renderers/common/nodes/Nodes.js +25 -18
  152. package/src/renderers/webgl/WebGLBackground.js +4 -0
  153. package/src/renderers/webgl-fallback/WebGLBackend.js +295 -110
  154. package/src/renderers/webgl-fallback/nodes/GLSLNodeBuilder.js +347 -17
  155. package/src/renderers/webgl-fallback/utils/WebGLAttributeUtils.js +57 -0
  156. package/src/renderers/webgl-fallback/utils/WebGLCapabilities.js +28 -0
  157. package/src/renderers/webgl-fallback/utils/WebGLExtensions.js +45 -0
  158. package/src/renderers/webgl-fallback/utils/WebGLState.js +323 -11
  159. package/src/renderers/webgl-fallback/utils/WebGLTextureUtils.js +167 -21
  160. package/src/renderers/webgl-fallback/utils/WebGLTimestampQueryPool.js +359 -0
  161. package/src/renderers/webgl-fallback/utils/WebGLUtils.js +43 -0
  162. package/src/renderers/webgpu/WebGPUBackend.js +132 -149
  163. package/src/renderers/webgpu/WebGPURenderer.Nodes.js +6 -4
  164. package/src/renderers/webgpu/WebGPURenderer.js +5 -4
  165. package/src/renderers/webgpu/nodes/WGSLNodeBuilder.js +615 -41
  166. package/src/renderers/webgpu/utils/WebGPUAttributeUtils.js +85 -6
  167. package/src/renderers/webgpu/utils/WebGPUBindingUtils.js +85 -0
  168. package/src/renderers/webgpu/utils/WebGPUPipelineUtils.js +102 -3
  169. package/src/renderers/webgpu/utils/WebGPUTexturePassUtils.js +98 -1
  170. package/src/renderers/webgpu/utils/WebGPUTextureUtils.js +257 -9
  171. package/src/renderers/webgpu/utils/WebGPUTimestampQueryPool.js +274 -0
  172. package/src/renderers/webgpu/utils/WebGPUUtils.js +86 -4
  173. package/src/renderers/webxr/WebXRManager.js +13 -2
  174. package/src/textures/VideoFrameTexture.js +35 -0
  175. package/examples/jsm/geometries/InstancedPointsGeometry.js +0 -176
  176. package/examples/jsm/objects/InstancedPoints.js +0 -19
  177. package/src/materials/nodes/InstancedPointsNodeMaterial.js +0 -209
  178. package/src/nodes/accessors/InstancedPointsMaterialNode.js +0 -37
@@ -0,0 +1,1193 @@
1
+ import { ArrayCamera } from '../../cameras/ArrayCamera.js';
2
+ import { EventDispatcher } from '../../core/EventDispatcher.js';
3
+ import { PerspectiveCamera } from '../../cameras/PerspectiveCamera.js';
4
+ import { RAD2DEG } from '../../math/MathUtils.js';
5
+ import { Vector2 } from '../../math/Vector2.js';
6
+ import { Vector3 } from '../../math/Vector3.js';
7
+ import { Vector4 } from '../../math/Vector4.js';
8
+ import { WebXRController } from '../webxr/WebXRController.js';
9
+ import { DepthFormat, DepthStencilFormat, RGBAFormat, UnsignedByteType, UnsignedInt248Type, UnsignedIntType } from '../../constants.js';
10
+ import { DepthTexture } from '../../textures/DepthTexture.js';
11
+ import { XRRenderTarget } from './XRRenderTarget.js';
12
+
13
+ const _cameraLPos = /*@__PURE__*/ new Vector3();
14
+ const _cameraRPos = /*@__PURE__*/ new Vector3();
15
+
16
+ /**
17
+ * The XR manager is built on top of the WebXR Device API to
18
+ * manage XR sessions with `WebGPURenderer`.
19
+ *
20
+ * XR is currently only supported with a WebGL 2 backend.
21
+ *
22
+ * @augments EventDispatcher
23
+ */
24
+ class XRManager extends EventDispatcher {
25
+
26
+ /**
27
+ * Constructs a new XR manager.
28
+ *
29
+ * @param {Renderer} renderer - The renderer.
30
+ */
31
+ constructor( renderer ) {
32
+
33
+ super();
34
+
35
+ /**
36
+ * This flag globally enables XR rendering.
37
+ *
38
+ * @type {Boolean}
39
+ * @default false
40
+ */
41
+ this.enabled = false;
42
+
43
+ /**
44
+ * Whether the XR device is currently presenting or not.
45
+ *
46
+ * @type {Boolean}
47
+ * @default false
48
+ * @readonly
49
+ */
50
+ this.isPresenting = false;
51
+
52
+ /**
53
+ * Whether the XR camera should automatically be updated or not.
54
+ *
55
+ * @type {Boolean}
56
+ * @default true
57
+ */
58
+ this.cameraAutoUpdate = true;
59
+
60
+ /**
61
+ * The renderer.
62
+ *
63
+ * @private
64
+ * @type {Renderer}
65
+ */
66
+ this._renderer = renderer;
67
+
68
+ // camera
69
+
70
+ /**
71
+ * Represents the camera for the left eye.
72
+ *
73
+ * @private
74
+ * @type {PerspectiveCamera}
75
+ */
76
+ this._cameraL = new PerspectiveCamera();
77
+ this._cameraL.viewport = new Vector4();
78
+
79
+ /**
80
+ * Represents the camera for the right eye.
81
+ *
82
+ * @private
83
+ * @type {PerspectiveCamera}
84
+ */
85
+ this._cameraR = new PerspectiveCamera();
86
+ this._cameraR.viewport = new Vector4();
87
+
88
+ /**
89
+ * A list of cameras used for rendering the XR views.
90
+ *
91
+ * @private
92
+ * @type {Array<Camera>}
93
+ */
94
+ this._cameras = [ this._cameraL, this._cameraR ];
95
+
96
+ /**
97
+ * The main XR camera.
98
+ *
99
+ * @private
100
+ * @type {ArrayCamera}
101
+ */
102
+ this._cameraXR = new ArrayCamera();
103
+
104
+ /**
105
+ * The current near value of the XR camera.
106
+ *
107
+ * @private
108
+ * @type {Number?}
109
+ * @default null
110
+ */
111
+ this._currentDepthNear = null;
112
+
113
+ /**
114
+ * The current far value of the XR camera.
115
+ *
116
+ * @private
117
+ * @type {Number?}
118
+ * @default null
119
+ */
120
+ this._currentDepthFar = null;
121
+
122
+ /**
123
+ * A list of WebXR controllers requested by the application.
124
+ *
125
+ * @private
126
+ * @type {Array<WebXRController>}
127
+ */
128
+ this._controllers = [];
129
+
130
+ /**
131
+ * A list of XR input source. Each input source belongs to
132
+ * an instance of WebXRController.
133
+ *
134
+ * @private
135
+ * @type {Array<XRInputSource?>}
136
+ */
137
+ this._controllerInputSources = [];
138
+
139
+ /**
140
+ * The current render target of the renderer.
141
+ *
142
+ * @private
143
+ * @type {RenderTarget?}
144
+ * @default null
145
+ */
146
+ this._currentRenderTarget = null;
147
+
148
+ /**
149
+ * The XR render target that represents the rendering destination
150
+ * during an active XR session.
151
+ *
152
+ * @private
153
+ * @type {RenderTarget?}
154
+ * @default null
155
+ */
156
+ this._xrRenderTarget = null;
157
+
158
+ /**
159
+ * The current animation context.
160
+ *
161
+ * @private
162
+ * @type {Window?}
163
+ * @default null
164
+ */
165
+ this._currentAnimationContext = null;
166
+
167
+ /**
168
+ * The current animation loop.
169
+ *
170
+ * @private
171
+ * @type {Function?}
172
+ * @default null
173
+ */
174
+ this._currentAnimationLoop = null;
175
+
176
+ /**
177
+ * The current pixel ratio.
178
+ *
179
+ * @private
180
+ * @type {Number?}
181
+ * @default null
182
+ */
183
+ this._currentPixelRatio = null;
184
+
185
+ /**
186
+ * The current size of the renderer's canvas
187
+ * in logical pixel unit.
188
+ *
189
+ * @private
190
+ * @type {Vector2}
191
+ */
192
+ this._currentSize = new Vector2();
193
+
194
+ /**
195
+ * The default event listener for handling events inside a XR session.
196
+ *
197
+ * @private
198
+ * @type {Function}
199
+ */
200
+ this._onSessionEvent = onSessionEvent.bind( this );
201
+
202
+ /**
203
+ * The event listener for handling the end of a XR session.
204
+ *
205
+ * @private
206
+ * @type {Function}
207
+ */
208
+ this._onSessionEnd = onSessionEnd.bind( this );
209
+
210
+ /**
211
+ * The event listener for handling the `inputsourceschange` event.
212
+ *
213
+ * @private
214
+ * @type {Function}
215
+ */
216
+ this._onInputSourcesChange = onInputSourcesChange.bind( this );
217
+
218
+ /**
219
+ * The animation loop which is used as a replacement for the default
220
+ * animation loop of the applicatio. It is only used when a XR session
221
+ * is active.
222
+ *
223
+ * @private
224
+ * @type {Function}
225
+ */
226
+ this._onAnimationFrame = onAnimationFrame.bind( this );
227
+
228
+ /**
229
+ * The current XR reference space.
230
+ *
231
+ * @private
232
+ * @type {XRReferenceSpace?}
233
+ * @default null
234
+ */
235
+ this._referenceSpace = null;
236
+
237
+ /**
238
+ * The current XR reference space type.
239
+ *
240
+ * @private
241
+ * @type {String}
242
+ * @default 'local-floor'
243
+ */
244
+ this._referenceSpaceType = 'local-floor';
245
+
246
+ /**
247
+ * A custom reference space defined by the application.
248
+ *
249
+ * @private
250
+ * @type {XRReferenceSpace?}
251
+ * @default null
252
+ */
253
+ this._customReferenceSpace = null;
254
+
255
+ /**
256
+ * The framebuffer scale factor.
257
+ *
258
+ * @private
259
+ * @type {Number}
260
+ * @default 1
261
+ */
262
+ this._framebufferScaleFactor = 1;
263
+
264
+ /**
265
+ * The foveation factor.
266
+ *
267
+ * @private
268
+ * @type {Number}
269
+ * @default 1
270
+ */
271
+ this._foveation = 1.0;
272
+
273
+ /**
274
+ * A reference to the current XR session.
275
+ *
276
+ * @private
277
+ * @type {XRSession?}
278
+ * @default null
279
+ */
280
+ this._session = null;
281
+
282
+ /**
283
+ * A reference to the current XR base layer.
284
+ *
285
+ * @private
286
+ * @type {XRWebGLLayer?}
287
+ * @default null
288
+ */
289
+ this._glBaseLayer = null;
290
+
291
+ /**
292
+ * A reference to the current XR binding.
293
+ *
294
+ * @private
295
+ * @type {XRWebGLBinding?}
296
+ * @default null
297
+ */
298
+ this._glBinding = null;
299
+
300
+ /**
301
+ * A reference to the current XR projection layer.
302
+ *
303
+ * @private
304
+ * @type {XRProjectionLayer?}
305
+ * @default null
306
+ */
307
+ this._glProjLayer = null;
308
+
309
+ /**
310
+ * A reference to the current XR frame.
311
+ *
312
+ * @private
313
+ * @type {XRFrame?}
314
+ * @default null
315
+ */
316
+ this._xrFrame = null;
317
+
318
+ /**
319
+ * Whether to use the WebXR Layers API or not.
320
+ *
321
+ * @private
322
+ * @type {Boolean}
323
+ * @readonly
324
+ */
325
+ this._useLayers = ( typeof XRWebGLBinding !== 'undefined' && 'createProjectionLayer' in XRWebGLBinding.prototype ); // eslint-disable-line compat/compat
326
+
327
+ }
328
+
329
+ /**
330
+ * Returns an instance of `THREE.Group` that represents the transformation
331
+ * of a XR controller in target ray space. The requested controller is defined
332
+ * by the given index.
333
+ *
334
+ * @param {Number} index - The index of the XR controller.
335
+ * @return {Group} A group that represents the controller's transformation.
336
+ */
337
+ getController( index ) {
338
+
339
+ const controller = this._getController( index );
340
+
341
+ return controller.getTargetRaySpace();
342
+
343
+ }
344
+
345
+ /**
346
+ * Returns an instance of `THREE.Group` that represents the transformation
347
+ * of a XR controller in grip space. The requested controller is defined
348
+ * by the given index.
349
+ *
350
+ * @param {Number} index - The index of the XR controller.
351
+ * @return {Group} A group that represents the controller's transformation.
352
+ */
353
+ getControllerGrip( index ) {
354
+
355
+ const controller = this._getController( index );
356
+
357
+ return controller.getGripSpace();
358
+
359
+ }
360
+
361
+ /**
362
+ * Returns an instance of `THREE.Group` that represents the transformation
363
+ * of a XR controller in hand space. The requested controller is defined
364
+ * by the given index.
365
+ *
366
+ * @param {Number} index - The index of the XR controller.
367
+ * @return {Group} A group that represents the controller's transformation.
368
+ */
369
+ getHand( index ) {
370
+
371
+ const controller = this._getController( index );
372
+
373
+ return controller.getHandSpace();
374
+
375
+ }
376
+
377
+ /**
378
+ * Returns the foveation value.
379
+ *
380
+ * @return {Number|undefined} The foveation value. Returns `undefined` if no base or projection layer is defined.
381
+ */
382
+ getFoveation() {
383
+
384
+ if ( this._glProjLayer === null && this._glBaseLayer === null ) {
385
+
386
+ return undefined;
387
+
388
+ }
389
+
390
+ return this._foveation;
391
+
392
+ }
393
+
394
+ /**
395
+ * Sets the foveation value.
396
+ *
397
+ * @param {Number} foveation - A number in the range `[0,1]` where `0` means no foveation (full resolution)
398
+ * and `1` means maximum foveation (the edges render at lower resolution).
399
+ */
400
+ setFoveation( foveation ) {
401
+
402
+ this._foveation = foveation;
403
+
404
+ if ( this._glProjLayer !== null ) {
405
+
406
+ this._glProjLayer.fixedFoveation = foveation;
407
+
408
+ }
409
+
410
+ if ( this._glBaseLayer !== null && this._glBaseLayer.fixedFoveation !== undefined ) {
411
+
412
+ this._glBaseLayer.fixedFoveation = foveation;
413
+
414
+ }
415
+
416
+ }
417
+
418
+ /**
419
+ * Returns the framebuffer scale factor.
420
+ *
421
+ * @return {Number} The framebuffer scale factor.
422
+ */
423
+ getFramebufferScaleFactor() {
424
+
425
+ return this._framebufferScaleFactor;
426
+
427
+ }
428
+
429
+ /**
430
+ * Sets the framebuffer scale factor.
431
+ *
432
+ * This method can not be used during a XR session.
433
+ *
434
+ * @param {Number} factor - The framebuffer scale factor.
435
+ */
436
+ setFramebufferScaleFactor( factor ) {
437
+
438
+ this._framebufferScaleFactor = factor;
439
+
440
+ if ( this.isPresenting === true ) {
441
+
442
+ console.warn( 'THREE.XRManager: Cannot change framebuffer scale while presenting.' );
443
+
444
+ }
445
+
446
+ }
447
+
448
+ /**
449
+ * Returns the reference space type.
450
+ *
451
+ * @return {String} The reference space type.
452
+ */
453
+ getReferenceSpaceType() {
454
+
455
+ return this._referenceSpaceType;
456
+
457
+ }
458
+
459
+ /**
460
+ * Sets the reference space type.
461
+ *
462
+ * This method can not be used during a XR session.
463
+ *
464
+ * @param {String} type - The reference space type.
465
+ */
466
+ setReferenceSpaceType( type ) {
467
+
468
+ this._referenceSpaceType = type;
469
+
470
+ if ( this.isPresenting === true ) {
471
+
472
+ console.warn( 'THREE.XRManager: Cannot change reference space type while presenting.' );
473
+
474
+ }
475
+
476
+ }
477
+
478
+ /**
479
+ * Returns the XR reference space.
480
+ *
481
+ * @return {XRReferenceSpace} The XR reference space.
482
+ */
483
+ getReferenceSpace() {
484
+
485
+ return this._customReferenceSpace || this._referenceSpace;
486
+
487
+ }
488
+
489
+ /**
490
+ * Sets a custom XR reference space.
491
+ *
492
+ * @param {XRReferenceSpace} space - The XR reference space.
493
+ */
494
+ setReferenceSpace( space ) {
495
+
496
+ this._customReferenceSpace = space;
497
+
498
+ }
499
+
500
+ /**
501
+ * Returns the XR camera.
502
+ *
503
+ * @return {ArrayCamera} The XR camera.
504
+ */
505
+ getCamera() {
506
+
507
+ return this._cameraXR;
508
+
509
+ }
510
+
511
+ /**
512
+ * Returns the environment blend mode from the current XR session.
513
+ *
514
+ * @return {('opaque'|'additive'|'alpha-blend')?} The environment blend mode. Returns `null` when used outside of a XR session.
515
+ */
516
+ getEnvironmentBlendMode() {
517
+
518
+ if ( this._session !== null ) {
519
+
520
+ return this._session.environmentBlendMode;
521
+
522
+ }
523
+
524
+ }
525
+
526
+ /**
527
+ * Returns the current XR frame.
528
+ *
529
+ * @return {XRFrame?} The XR frame. Returns `null` when used outside a XR session.
530
+ */
531
+ getFrame() {
532
+
533
+ return this._xrFrame;
534
+
535
+ }
536
+
537
+ /**
538
+ * Returns the current XR session.
539
+ *
540
+ * @return {XRSession?} The XR session. Returns `null` when used outside a XR session.
541
+ */
542
+ getSession() {
543
+
544
+ return this._session;
545
+
546
+ }
547
+
548
+ /**
549
+ * After a XR session has been requested usually with one of the `*Button` modules, it
550
+ * is injected into the renderer with this method. This method triggers the start of
551
+ * the actual XR rendering.
552
+ *
553
+ * @async
554
+ * @param {XRSession} session - The XR session to set.
555
+ * @return {Promise} A Promise that resolves when the session has been set.
556
+ */
557
+ async setSession( session ) {
558
+
559
+ const renderer = this._renderer;
560
+ const backend = renderer.backend;
561
+
562
+ const gl = renderer.getContext();
563
+
564
+ this._session = session;
565
+
566
+ if ( session !== null ) {
567
+
568
+ if ( backend.isWebGPUBackend === true ) throw new Error( 'THREE.XRManager: XR is currently not supported with a WebGPU backend. Use WebGL by passing "{ forceWebGL: true }" to the constructor of the renderer.' );
569
+
570
+ this._currentRenderTarget = renderer.getRenderTarget();
571
+
572
+ session.addEventListener( 'select', this._onSessionEvent );
573
+ session.addEventListener( 'selectstart', this._onSessionEvent );
574
+ session.addEventListener( 'selectend', this._onSessionEvent );
575
+ session.addEventListener( 'squeeze', this._onSessionEvent );
576
+ session.addEventListener( 'squeezestart', this._onSessionEvent );
577
+ session.addEventListener( 'squeezeend', this._onSessionEvent );
578
+ session.addEventListener( 'end', this._onSessionEnd );
579
+ session.addEventListener( 'inputsourceschange', this._onInputSourcesChange );
580
+
581
+ await backend.makeXRCompatible();
582
+
583
+ this._currentPixelRatio = renderer.getPixelRatio();
584
+ renderer.getSize( this._currentSize );
585
+
586
+ this._currentAnimationContext = renderer._animation.getContext();
587
+ this._currentAnimationLoop = renderer._animation.getAnimationLoop();
588
+ renderer._animation.stop();
589
+
590
+ //
591
+
592
+ if ( this._useLayers === true ) {
593
+
594
+ // default path using XRWebGLBinding/XRProjectionLayer
595
+
596
+ let depthFormat = null;
597
+ let depthType = null;
598
+ let glDepthFormat = null;
599
+
600
+ if ( renderer.depth ) {
601
+
602
+ glDepthFormat = renderer.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
603
+ depthFormat = renderer.stencil ? DepthStencilFormat : DepthFormat;
604
+ depthType = renderer.stencil ? UnsignedInt248Type : UnsignedIntType;
605
+
606
+ }
607
+
608
+ const projectionlayerInit = {
609
+ colorFormat: gl.RGBA8,
610
+ depthFormat: glDepthFormat,
611
+ scaleFactor: this._framebufferScaleFactor
612
+ };
613
+
614
+ const glBinding = new XRWebGLBinding( session, gl );
615
+ const glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );
616
+
617
+ this._glBinding = glBinding;
618
+ this._glProjLayer = glProjLayer;
619
+
620
+ session.updateRenderState( { layers: [ glProjLayer ] } );
621
+
622
+ renderer.setPixelRatio( 1 );
623
+ renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );
624
+
625
+ this._xrRenderTarget = new XRRenderTarget(
626
+ glProjLayer.textureWidth,
627
+ glProjLayer.textureHeight,
628
+ {
629
+ format: RGBAFormat,
630
+ type: UnsignedByteType,
631
+ colorSpace: renderer.outputColorSpace,
632
+ depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
633
+ stencilBuffer: renderer.stencil,
634
+ samples: renderer.samples
635
+ } );
636
+
637
+ this._xrRenderTarget.hasExternalTextures = true;
638
+
639
+ } else {
640
+
641
+ // fallback to XRWebGLLayer
642
+
643
+ const layerInit = {
644
+ antialias: renderer.samples > 0,
645
+ alpha: true,
646
+ depth: renderer.depth,
647
+ stencil: renderer.stencil,
648
+ framebufferScaleFactor: this.getFramebufferScaleFactor()
649
+ };
650
+
651
+ const glBaseLayer = new XRWebGLLayer( session, gl, layerInit );
652
+ this._glBaseLayer = glBaseLayer;
653
+
654
+ session.updateRenderState( { baseLayer: glBaseLayer } );
655
+
656
+ renderer.setPixelRatio( 1 );
657
+ renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false );
658
+
659
+ this._xrRenderTarget = new XRRenderTarget(
660
+ glBaseLayer.framebufferWidth,
661
+ glBaseLayer.framebufferHeight,
662
+ {
663
+ format: RGBAFormat,
664
+ type: UnsignedByteType,
665
+ colorSpace: renderer.outputColorSpace,
666
+ stencilBuffer: renderer.stencil
667
+ }
668
+ );
669
+
670
+ }
671
+
672
+ //
673
+
674
+ this.setFoveation( this.getFoveation() );
675
+
676
+ this._referenceSpace = await session.requestReferenceSpace( this.getReferenceSpaceType() );
677
+
678
+ renderer._animation.setAnimationLoop( this._onAnimationFrame );
679
+ renderer._animation.setContext( session );
680
+ renderer._animation.start();
681
+
682
+ this.isPresenting = true;
683
+
684
+ this.dispatchEvent( { type: 'sessionstart' } );
685
+
686
+ }
687
+
688
+ }
689
+
690
+ /**
691
+ * This method is called by the renderer per frame and updates the XR camera
692
+ * and it sub cameras based on the given camera. The given camera is the "user"
693
+ * camera created on application level and used for non-XR rendering.
694
+ *
695
+ * @param {PerspectiveCamera} camera - The camera.
696
+ */
697
+ updateCamera( camera ) {
698
+
699
+ const session = this._session;
700
+
701
+ if ( session === null ) return;
702
+
703
+ const depthNear = camera.near;
704
+ const depthFar = camera.far;
705
+
706
+ const cameraXR = this._cameraXR;
707
+ const cameraL = this._cameraL;
708
+ const cameraR = this._cameraR;
709
+
710
+ cameraXR.near = cameraR.near = cameraL.near = depthNear;
711
+ cameraXR.far = cameraR.far = cameraL.far = depthFar;
712
+
713
+ if ( this._currentDepthNear !== cameraXR.near || this._currentDepthFar !== cameraXR.far ) {
714
+
715
+ // Note that the new renderState won't apply until the next frame. See #18320
716
+
717
+ session.updateRenderState( {
718
+ depthNear: cameraXR.near,
719
+ depthFar: cameraXR.far
720
+ } );
721
+
722
+ this._currentDepthNear = cameraXR.near;
723
+ this._currentDepthFar = cameraXR.far;
724
+
725
+ }
726
+
727
+ cameraL.layers.mask = camera.layers.mask | 0b010;
728
+ cameraR.layers.mask = camera.layers.mask | 0b100;
729
+ cameraXR.layers.mask = cameraL.layers.mask | cameraR.layers.mask;
730
+
731
+ const parent = camera.parent;
732
+ const cameras = cameraXR.cameras;
733
+
734
+ updateCamera( cameraXR, parent );
735
+
736
+ for ( let i = 0; i < cameras.length; i ++ ) {
737
+
738
+ updateCamera( cameras[ i ], parent );
739
+
740
+ }
741
+
742
+ // update projection matrix for proper view frustum culling
743
+
744
+ if ( cameras.length === 2 ) {
745
+
746
+ setProjectionFromUnion( cameraXR, cameraL, cameraR );
747
+
748
+ } else {
749
+
750
+ // assume single camera setup (AR)
751
+
752
+ cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );
753
+
754
+ }
755
+
756
+ // update user camera and its children
757
+
758
+ updateUserCamera( camera, cameraXR, parent );
759
+
760
+
761
+ }
762
+
763
+ /**
764
+ * Returns a WebXR controller for the given controller index.
765
+ *
766
+ * @private
767
+ * @param {Number} index - The controller index.
768
+ * @return {WebXRController} The XR controller.
769
+ */
770
+ _getController( index ) {
771
+
772
+ let controller = this._controllers[ index ];
773
+
774
+ if ( controller === undefined ) {
775
+
776
+ controller = new WebXRController();
777
+ this._controllers[ index ] = controller;
778
+
779
+ }
780
+
781
+ return controller;
782
+
783
+ }
784
+
785
+ }
786
+
787
+ /**
788
+ * Assumes 2 cameras that are parallel and share an X-axis, and that
789
+ * the cameras' projection and world matrices have already been set.
790
+ * And that near and far planes are identical for both cameras.
791
+ * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
792
+ *
793
+ * @param {ArrayCamera} camera - The camera to update.
794
+ * @param {PerspectiveCamera} cameraL - The left camera.
795
+ * @param {PerspectiveCamera} cameraR - The right camera.
796
+ */
797
+ function setProjectionFromUnion( camera, cameraL, cameraR ) {
798
+
799
+ _cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
800
+ _cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
801
+
802
+ const ipd = _cameraLPos.distanceTo( _cameraRPos );
803
+
804
+ const projL = cameraL.projectionMatrix.elements;
805
+ const projR = cameraR.projectionMatrix.elements;
806
+
807
+ // VR systems will have identical far and near planes, and
808
+ // most likely identical top and bottom frustum extents.
809
+ // Use the left camera for these values.
810
+ const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
811
+ const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
812
+ const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
813
+ const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];
814
+
815
+ const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
816
+ const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
817
+ const left = near * leftFov;
818
+ const right = near * rightFov;
819
+
820
+ // Calculate the new camera's position offset from the
821
+ // left camera. xOffset should be roughly half `ipd`.
822
+ const zOffset = ipd / ( - leftFov + rightFov );
823
+ const xOffset = zOffset * - leftFov;
824
+
825
+ // TODO: Better way to apply this offset?
826
+ cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
827
+ camera.translateX( xOffset );
828
+ camera.translateZ( zOffset );
829
+ camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
830
+ camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
831
+
832
+ // Check if the projection uses an infinite far plane.
833
+ if ( projL[ 10 ] === - 1.0 ) {
834
+
835
+ // Use the projection matrix from the left eye.
836
+ // The camera offset is sufficient to include the view volumes
837
+ // of both eyes (assuming symmetric projections).
838
+ camera.projectionMatrix.copy( cameraL.projectionMatrix );
839
+ camera.projectionMatrixInverse.copy( cameraL.projectionMatrixInverse );
840
+
841
+ } else {
842
+
843
+ // Find the union of the frustum values of the cameras and scale
844
+ // the values so that the near plane's position does not change in world space,
845
+ // although must now be relative to the new union camera.
846
+ const near2 = near + zOffset;
847
+ const far2 = far + zOffset;
848
+ const left2 = left - xOffset;
849
+ const right2 = right + ( ipd - xOffset );
850
+ const top2 = topFov * far / far2 * near2;
851
+ const bottom2 = bottomFov * far / far2 * near2;
852
+
853
+ camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
854
+ camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
855
+
856
+ }
857
+
858
+ }
859
+
860
+ /**
861
+ * Updates the world matrices for the given camera based on the parent 3D object.
862
+ *
863
+ * @inner
864
+ * @param {Camera} camera - The camera to update.
865
+ * @param {Object3D} parent - The parent 3D object.
866
+ */
867
+ function updateCamera( camera, parent ) {
868
+
869
+ if ( parent === null ) {
870
+
871
+ camera.matrixWorld.copy( camera.matrix );
872
+
873
+ } else {
874
+
875
+ camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );
876
+
877
+ }
878
+
879
+ camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();
880
+
881
+ }
882
+
883
+ /**
884
+ * Updates the given camera with the transfomration of the XR camera and parent object.
885
+ *
886
+ * @inner
887
+ * @param {Camera} camera - The camera to update.
888
+ * @param {ArrayCamera} cameraXR - The XR camera.
889
+ * @param {Object3D} parent - The parent 3D object.
890
+ */
891
+ function updateUserCamera( camera, cameraXR, parent ) {
892
+
893
+ if ( parent === null ) {
894
+
895
+ camera.matrix.copy( cameraXR.matrixWorld );
896
+
897
+ } else {
898
+
899
+ camera.matrix.copy( parent.matrixWorld );
900
+ camera.matrix.invert();
901
+ camera.matrix.multiply( cameraXR.matrixWorld );
902
+
903
+ }
904
+
905
+ camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
906
+ camera.updateMatrixWorld( true );
907
+
908
+ camera.projectionMatrix.copy( cameraXR.projectionMatrix );
909
+ camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
910
+
911
+ if ( camera.isPerspectiveCamera ) {
912
+
913
+ camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
914
+ camera.zoom = 1;
915
+
916
+ }
917
+
918
+ }
919
+
920
+ function onSessionEvent( event ) {
921
+
922
+ const controllerIndex = this._controllerInputSources.indexOf( event.inputSource );
923
+
924
+ if ( controllerIndex === - 1 ) {
925
+
926
+ return;
927
+
928
+ }
929
+
930
+ const controller = this._controllers[ controllerIndex ];
931
+
932
+ if ( controller !== undefined ) {
933
+
934
+ const referenceSpace = this.getReferenceSpace();
935
+
936
+ controller.update( event.inputSource, event.frame, referenceSpace );
937
+ controller.dispatchEvent( { type: event.type, data: event.inputSource } );
938
+
939
+ }
940
+
941
+ }
942
+
943
+ function onSessionEnd() {
944
+
945
+ const session = this._session;
946
+ const renderer = this._renderer;
947
+
948
+ session.removeEventListener( 'select', this._onSessionEvent );
949
+ session.removeEventListener( 'selectstart', this._onSessionEvent );
950
+ session.removeEventListener( 'selectend', this._onSessionEvent );
951
+ session.removeEventListener( 'squeeze', this._onSessionEvent );
952
+ session.removeEventListener( 'squeezestart', this._onSessionEvent );
953
+ session.removeEventListener( 'squeezeend', this._onSessionEvent );
954
+ session.removeEventListener( 'end', this._onSessionEnd );
955
+ session.removeEventListener( 'inputsourceschange', this._onInputSourcesChange );
956
+
957
+ for ( let i = 0; i < this._controllers.length; i ++ ) {
958
+
959
+ const inputSource = this._controllerInputSources[ i ];
960
+
961
+ if ( inputSource === null ) continue;
962
+
963
+ this._controllerInputSources[ i ] = null;
964
+
965
+ this._controllers[ i ].disconnect( inputSource );
966
+
967
+ }
968
+
969
+ this._currentDepthNear = null;
970
+ this._currentDepthFar = null;
971
+
972
+ // restore framebuffer/rendering state
973
+
974
+ renderer.backend.setXRTarget( null );
975
+ renderer.setRenderTarget( this._currentRenderTarget );
976
+
977
+ this._session = null;
978
+ this._xrRenderTarget = null;
979
+
980
+ //
981
+
982
+ this.isPresenting = false;
983
+
984
+ renderer._animation.stop();
985
+
986
+ renderer._animation.setAnimationLoop( this._currentAnimationLoop );
987
+ renderer._animation.setContext( this._currentAnimationContext );
988
+ renderer._animation.start();
989
+
990
+ renderer.setPixelRatio( this._currentPixelRatio );
991
+ renderer.setSize( this._currentSize.width, this._currentSize.height, false );
992
+
993
+ this.dispatchEvent( { type: 'sessionend' } );
994
+
995
+ }
996
+
997
+ function onInputSourcesChange( event ) {
998
+
999
+ const controllers = this._controllers;
1000
+ const controllerInputSources = this._controllerInputSources;
1001
+
1002
+ // Notify disconnected
1003
+
1004
+ for ( let i = 0; i < event.removed.length; i ++ ) {
1005
+
1006
+ const inputSource = event.removed[ i ];
1007
+ const index = controllerInputSources.indexOf( inputSource );
1008
+
1009
+ if ( index >= 0 ) {
1010
+
1011
+ controllerInputSources[ index ] = null;
1012
+ controllers[ index ].disconnect( inputSource );
1013
+
1014
+ }
1015
+
1016
+ }
1017
+
1018
+ // Notify connected
1019
+
1020
+ for ( let i = 0; i < event.added.length; i ++ ) {
1021
+
1022
+ const inputSource = event.added[ i ];
1023
+
1024
+ let controllerIndex = controllerInputSources.indexOf( inputSource );
1025
+
1026
+ if ( controllerIndex === - 1 ) {
1027
+
1028
+ // Assign input source a controller that currently has no input source
1029
+
1030
+ for ( let i = 0; i < controllers.length; i ++ ) {
1031
+
1032
+ if ( i >= controllerInputSources.length ) {
1033
+
1034
+ controllerInputSources.push( inputSource );
1035
+ controllerIndex = i;
1036
+ break;
1037
+
1038
+ } else if ( controllerInputSources[ i ] === null ) {
1039
+
1040
+ controllerInputSources[ i ] = inputSource;
1041
+ controllerIndex = i;
1042
+ break;
1043
+
1044
+ }
1045
+
1046
+ }
1047
+
1048
+ // If all controllers do currently receive input we ignore new ones
1049
+
1050
+ if ( controllerIndex === - 1 ) break;
1051
+
1052
+ }
1053
+
1054
+ const controller = controllers[ controllerIndex ];
1055
+
1056
+ if ( controller ) {
1057
+
1058
+ controller.connect( inputSource );
1059
+
1060
+ }
1061
+
1062
+ }
1063
+
1064
+ }
1065
+
1066
+ function onAnimationFrame( time, frame ) {
1067
+
1068
+ if ( frame === undefined ) return;
1069
+
1070
+ const cameraXR = this._cameraXR;
1071
+ const renderer = this._renderer;
1072
+ const backend = renderer.backend;
1073
+
1074
+ const glBaseLayer = this._glBaseLayer;
1075
+
1076
+ const referenceSpace = this.getReferenceSpace();
1077
+ const pose = frame.getViewerPose( referenceSpace );
1078
+
1079
+ this._xrFrame = frame;
1080
+
1081
+ if ( pose !== null ) {
1082
+
1083
+ const views = pose.views;
1084
+
1085
+ if ( this._glBaseLayer !== null ) {
1086
+
1087
+ backend.setXRTarget( glBaseLayer.framebuffer );
1088
+
1089
+ }
1090
+
1091
+ let cameraXRNeedsUpdate = false;
1092
+
1093
+ // check if it's necessary to rebuild cameraXR's camera list
1094
+
1095
+ if ( views.length !== cameraXR.cameras.length ) {
1096
+
1097
+ cameraXR.cameras.length = 0;
1098
+ cameraXRNeedsUpdate = true;
1099
+
1100
+ }
1101
+
1102
+ for ( let i = 0; i < views.length; i ++ ) {
1103
+
1104
+ const view = views[ i ];
1105
+
1106
+ let viewport;
1107
+
1108
+ if ( this._useLayers === true ) {
1109
+
1110
+ const glSubImage = this._glBinding.getViewSubImage( this._glProjLayer, view );
1111
+ viewport = glSubImage.viewport;
1112
+
1113
+ // For side-by-side projection, we only produce a single texture for both eyes.
1114
+ if ( i === 0 ) {
1115
+
1116
+ backend.setXRRenderTargetTextures(
1117
+ this._xrRenderTarget,
1118
+ glSubImage.colorTexture,
1119
+ this._glProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture
1120
+ );
1121
+
1122
+ }
1123
+
1124
+ } else {
1125
+
1126
+ viewport = glBaseLayer.getViewport( view );
1127
+
1128
+ }
1129
+
1130
+ let camera = this._cameras[ i ];
1131
+
1132
+ if ( camera === undefined ) {
1133
+
1134
+ camera = new PerspectiveCamera();
1135
+ camera.layers.enable( i );
1136
+ camera.viewport = new Vector4();
1137
+ this._cameras[ i ] = camera;
1138
+
1139
+ }
1140
+
1141
+ camera.matrix.fromArray( view.transform.matrix );
1142
+ camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
1143
+ camera.projectionMatrix.fromArray( view.projectionMatrix );
1144
+ camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();
1145
+ camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );
1146
+
1147
+ if ( i === 0 ) {
1148
+
1149
+ cameraXR.matrix.copy( camera.matrix );
1150
+ cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );
1151
+
1152
+ }
1153
+
1154
+ if ( cameraXRNeedsUpdate === true ) {
1155
+
1156
+ cameraXR.cameras.push( camera );
1157
+
1158
+ }
1159
+
1160
+ }
1161
+
1162
+ renderer.setRenderTarget( this._xrRenderTarget );
1163
+
1164
+ }
1165
+
1166
+ //
1167
+
1168
+ for ( let i = 0; i < this._controllers.length; i ++ ) {
1169
+
1170
+ const inputSource = this._controllerInputSources[ i ];
1171
+ const controller = this._controllers[ i ];
1172
+
1173
+ if ( inputSource !== null && controller !== undefined ) {
1174
+
1175
+ controller.update( inputSource, frame, referenceSpace );
1176
+
1177
+ }
1178
+
1179
+ }
1180
+
1181
+ if ( this._currentAnimationLoop ) this._currentAnimationLoop( time, frame );
1182
+
1183
+ if ( frame.detectedPlanes ) {
1184
+
1185
+ this.dispatchEvent( { type: 'planesdetected', data: frame } );
1186
+
1187
+ }
1188
+
1189
+ this._xrFrame = null;
1190
+
1191
+ }
1192
+
1193
+ export default XRManager;