<!-- NEW7 — TEST 7 · THE WOVEN CITY · part 410 -->
XR
		 * camera of the scene as a parameter. The passed in camera's transformation
		 * is automatically adjusted to the position of the XR camera when calling
		 * this method.
		 *
		 * @param {Camera} camera - The camera.
		 */
		this.updateCamera = function ( camera ) {

			if ( session === null ) return;

			let depthNear = camera.near;
			let depthFar = camera.far;

			if ( depthSensing.texture !== null ) {

				if ( depthSensing.depthNear > 0 ) depthNear = depthSensing.depthNear;
				if ( depthSensing.depthFar > 0 ) depthFar = depthSensing.depthFar;

			}

			cameraXR.near = cameraR.near = cameraL.near = depthNear;
			cameraXR.far = cameraR.far = cameraL.far = depthFar;

			if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {

				// Note that the new renderState won't apply until the next frame. See #18320

				session.updateRenderState( {
					depthNear: cameraXR.near,
					depthFar: cameraXR.far
				} );

				_currentDepthNear = cameraXR.near;
				_currentDepthFar = cameraXR.far;

			}

			// inherit camera layers and enable eye layers (1 = left, 2 = right)
			cameraXR.layers.mask = camera.layers.mask | 0b110;
			cameraL.layers.mask = cameraXR.layers.mask & -5;
			cameraR.layers.mask = cameraXR.layers.mask & -3;

			const parent = camera.parent;
			const cameras = cameraXR.cameras;

			updateCamera( cameraXR, parent );

			for ( let i = 0; i < cameras.length; i ++ ) {

				updateCamera( cameras[ i ], parent );

			}

			// update projection matrix for proper view frustum culling

			if ( cameras.length === 2 ) {

				setProjectionFromUnion( cameraXR, cameraL, cameraR );

			} else {

				// assume single camera setup (AR)

				cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );

			}

			// update user camera and its children

			if ( currentCameraSettings === null && camera.isPerspectiveCamera ) {

				currentCameraSettings = { camera: camera, fov: camera.fov, zoom: camera.zoom };

			}

			updateUserCamera( camera, cameraXR, parent );

		};

		function updateUserCamera( camera, cameraXR, parent ) {

			if ( parent === null ) {

				camera.matrix.copy( cameraXR.matrixWorld );

			} else {

				camera.matrix.copy( parent.matrixWorld );
				camera.matrix.invert();
				camera.matrix.multiply( cameraXR.matrixWorld );

			}

			camera.matrix.decompose( camera.position, camera.quaternion, camera.scale );
			camera.updateMatrixWorld( true );

			camera.projectionMatrix.copy( cameraXR.projectionMatrix );
			camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );

			if ( camera.isPerspectiveCamera ) {

				camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
				camera.zoom = 1;

			}

		}

		/**
		 * Returns an instance of {@link ArrayCamera} which represents the XR camera
		 * of the active XR session. For each view it holds a separate camera object.
		 *
		 * The camera's `fov` is currently not used and does not reflect the fov of
		 * the XR camera. If you need the fov on app level, you have to compute in
		 * manually from the XR camera's projection matrices.
		 *
		 * @return {ArrayCamera} The XR camera.
		 */
		this.getCamera = function () {

			return cameraXR;

		};

		/**
		 * Returns the amount of foveation used by the XR compositor for the projection layer.
		 *
		 * @return {number|undefined} The amount of foveation.
		 */
		this.getFoveation = function () {

			if ( glProjLayer === null && glBaseLayer === null ) {

				return undefined;

			}

			return foveation;

		};

		/**
		 * Sets the foveation value.
		 *
		 * @param {number} value - A number in the range `[0,1]` where `0` means no foveation (full resolution)
		 * and `1` means maximum foveation (the edges render at lower resolution).
		 */
		this.setFoveation = function ( value ) {

			// 0 = no foveation = full resolution
			// 1 = maximum foveation = the edges render at lower resolution

			foveation = value;

			if ( glProjLayer !== null ) {

				glProjLayer.fixedFoveation = value;

			}

			if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {

				glBaseLayer.fixedFoveation = value;

			}

		};

		/**
		 * Returns `true` if depth sensing is supported.
		 *
		 * @return {boolean} Whether depth sensing is supported or not.
		 */
		this.hasDepthSensing = function () {

			return depthSensing.texture !== null;

		};

		/**
		 * Returns the depth sensing mesh.
		 *
		 * See {@link WebXRDepthSensing#getMesh}.
		 *
		 * @return {Mesh} The depth sensing mesh.
		 */
		this.getDepthSensingMesh = function () {

			return depthSensing.getMesh( cameraXR );

		};

		/**
		 * Retrieves an opaque texture from the view-aligned {@link XRCamera}.
		 * Only available during the current animation loop.
		 *
		 * @param {XRCamera} xrCamera - The camera to query.
		 * @return {?Texture} An opaque texture representing the current raw camera frame.
		 */
		this.getCameraTexture = function ( xrCamera