@splnlss/3d-story-viewer 0.8.1 → 0.8.2
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/build/computeElevation.cjs +1 -1
- package/build/computeElevation.js +2 -2
- package/build/{index-DaqGSC4W.js → index-BgprA821.js} +107 -18
- package/build/index-XZNzHig1.cjs +1 -0
- package/build/{main-CY1MzgxV.js → main-BUCkukV4.js} +757 -12
- package/build/main-yri0wVzb.cjs +1 -0
- package/build/{spark.module-Y1ABc5im.cjs → spark.module-CKmN4uMZ.cjs} +1 -1
- package/build/{spark.module-BGYmUUum.js → spark.module-T7c-X7OV.js} +2 -2
- package/build/types/src/viewer/WebXRSession.d.ts +75 -0
- package/build/types/src/viewer/XRAttributionPanel.d.ts +23 -0
- package/build/types/src/viewer/XRComfortOverlay.d.ts +15 -0
- package/build/types/src/viewer/XRFrameInput.d.ts +30 -0
- package/build/types/src/viewer/XRNavigationCue.d.ts +10 -0
- package/build/types/src/viewer/XRPlayerRig.d.ts +48 -0
- package/build/types/src/viewer/XRRenderBridge.d.ts +25 -0
- package/build/types/src/viewer/index.d.ts +82 -0
- package/build/types/src/viewer/updateTilesCamera.d.ts +2 -0
- package/build/viewer.cjs +1 -1
- package/build/viewer.js +3 -3
- package/package.json +1 -1
- package/build/index-D87IZDc6.cjs +0 -1
- package/build/main-DFAyOsl5.cjs +0 -1
|
@@ -2,7 +2,7 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
var _a2;
|
|
5
|
-
import { S as ShaderChunk, M as Matrix4, V as Vector3, O as Object3D, a as Vector2, b as Mesh, P as PlaneGeometry, c as ShaderMaterial, R as Ray, E as EventDispatcher$1, d as Plane, e as Raycaster, C as Clock, Q as Quaternion, f as MathUtils, T as TrianglesDrawMode, g as TriangleFanDrawMode, h as TriangleStripDrawMode, L as Loader, i as LoaderUtils, F as FileLoader, j as MeshPhysicalMaterial, k as Color, l as LinearSRGBColorSpace, m as SRGBColorSpace, n as SpotLight, o as PointLight, D as DirectionalLight, I as InstancedMesh, p as InstancedBufferAttribute, B as BufferGeometry, q as TextureLoader, r as ImageBitmapLoader, s as BufferAttribute, t as InterleavedBuffer, u as LinearMipmapLinearFilter, N as NearestMipmapLinearFilter, v as LinearMipmapNearestFilter, w as NearestMipmapNearestFilter, x as LinearFilter, y as NearestFilter, z as RepeatWrapping, A as MirroredRepeatWrapping, G as ClampToEdgeWrapping, H as PointsMaterial, J as Material, K as LineBasicMaterial, U as MeshStandardMaterial, W as DoubleSide, X as MeshBasicMaterial, Y as PropertyBinding, Z as SkinnedMesh, _ as LineSegments, $ as Line, a0 as LineLoop, a1 as Points, a2 as Group$1, a3 as PerspectiveCamera, a4 as OrthographicCamera, a5 as Skeleton, a6 as AnimationClip, a7 as Bone, a8 as InterpolateDiscrete, a9 as InterpolateLinear, aa as InterleavedBufferAttribute, ab as Texture, ac as VectorKeyframeTrack, ad as NumberKeyframeTrack, ae as QuaternionKeyframeTrack, af as ColorManagement, ag as FrontSide, ah as Interpolant, ai as Box3, aj as Sphere, ak as Euler, al as Spherical, am as LoadingManager, an as Frustum, ao as DefaultLoadingManager, ap as Matrix3, aq as TextureUtils, ar as CompressedCubeTexture, as as CompressedArrayTexture, at as CompressedTexture, au as NoColorSpace, av as RGBA_PVRTC_2BPPV1_Format, aw as RGBA_PVRTC_4BPPV1_Format, ax as RGBA_BPTC_Format, ay as RED_GREEN_RGTC2_Format, az as SIGNED_RED_GREEN_RGTC2_Format, aA as RED_RGTC1_Format, aB as SIGNED_RED_RGTC1_Format, aC as RGBA_S3TC_DXT5_Format, aD as RGB_S3TC_DXT1_Format, aE as RGBA_S3TC_DXT1_Format, aF as RGBA_ASTC_6x6_Format, aG as RGBA_ASTC_4x4_Format, aH as SIGNED_RG11_EAC_Format, aI as RG11_EAC_Format, aJ as SIGNED_R11_EAC_Format, aK as R11_EAC_Format, aL as RGB_ETC2_Format, aM as RGBA_ETC2_EAC_Format, aN as RGBFormat, aO as RedFormat, aP as RGFormat, aQ as RGBAFormat, aR as UnsignedByteType, aS as HalfFloatType, aT as UnsignedInt101111Type, aU as UnsignedInt5999Type, aV as UnsignedShortType, aW as FloatType, aX as DataTexture, aY as Data3DTexture, aZ as RGB_PVRTC_4BPPV1_Format, a_ as RGB_ETC1_Format, a$ as RGB_BPTC_UNSIGNED_Format, b0 as Float32BufferAttribute, b1 as LinearMipMapLinearFilter, b2 as Triangle, b3 as CanvasTexture, b4 as WebGLRenderer, b5 as WebGLRenderTarget, b6 as OneFactor, b7 as ZeroFactor, b8 as CustomBlending, b9 as Box2, ba as Matrix2, bb as Vector4, bc as DataTextureLoader, bd as DataUtils, be as REVISION, bf as TextureSource, bg as ImageUtils, bh as Scene, bi as ecefToGeodeticPosition, bj as getEnuBasis, bk as BackSide, bl as BoxGeometry, bm as normalizeLayerOffset, bn as geodeticOffsetToEcefDelta, bo as validateGeodeticPosition, bp as validateTuple, bq as validateScale, br as geodeticToEcefPosition, bs as
|
|
5
|
+
import { S as ShaderChunk, M as Matrix4, V as Vector3, O as Object3D, a as Vector2, b as Mesh, P as PlaneGeometry, c as ShaderMaterial, R as Ray, E as EventDispatcher$1, d as Plane, e as Raycaster, C as Clock, Q as Quaternion, f as MathUtils, T as TrianglesDrawMode, g as TriangleFanDrawMode, h as TriangleStripDrawMode, L as Loader, i as LoaderUtils, F as FileLoader, j as MeshPhysicalMaterial, k as Color, l as LinearSRGBColorSpace, m as SRGBColorSpace, n as SpotLight, o as PointLight, D as DirectionalLight, I as InstancedMesh, p as InstancedBufferAttribute, B as BufferGeometry, q as TextureLoader, r as ImageBitmapLoader, s as BufferAttribute, t as InterleavedBuffer, u as LinearMipmapLinearFilter, N as NearestMipmapLinearFilter, v as LinearMipmapNearestFilter, w as NearestMipmapNearestFilter, x as LinearFilter, y as NearestFilter, z as RepeatWrapping, A as MirroredRepeatWrapping, G as ClampToEdgeWrapping, H as PointsMaterial, J as Material, K as LineBasicMaterial, U as MeshStandardMaterial, W as DoubleSide, X as MeshBasicMaterial, Y as PropertyBinding, Z as SkinnedMesh, _ as LineSegments, $ as Line, a0 as LineLoop, a1 as Points, a2 as Group$1, a3 as PerspectiveCamera, a4 as OrthographicCamera, a5 as Skeleton, a6 as AnimationClip, a7 as Bone, a8 as InterpolateDiscrete, a9 as InterpolateLinear, aa as InterleavedBufferAttribute, ab as Texture, ac as VectorKeyframeTrack, ad as NumberKeyframeTrack, ae as QuaternionKeyframeTrack, af as ColorManagement, ag as FrontSide, ah as Interpolant, ai as Box3, aj as Sphere, ak as Euler, al as Spherical, am as LoadingManager, an as Frustum, ao as DefaultLoadingManager, ap as Matrix3, aq as TextureUtils, ar as CompressedCubeTexture, as as CompressedArrayTexture, at as CompressedTexture, au as NoColorSpace, av as RGBA_PVRTC_2BPPV1_Format, aw as RGBA_PVRTC_4BPPV1_Format, ax as RGBA_BPTC_Format, ay as RED_GREEN_RGTC2_Format, az as SIGNED_RED_GREEN_RGTC2_Format, aA as RED_RGTC1_Format, aB as SIGNED_RED_RGTC1_Format, aC as RGBA_S3TC_DXT5_Format, aD as RGB_S3TC_DXT1_Format, aE as RGBA_S3TC_DXT1_Format, aF as RGBA_ASTC_6x6_Format, aG as RGBA_ASTC_4x4_Format, aH as SIGNED_RG11_EAC_Format, aI as RG11_EAC_Format, aJ as SIGNED_R11_EAC_Format, aK as R11_EAC_Format, aL as RGB_ETC2_Format, aM as RGBA_ETC2_EAC_Format, aN as RGBFormat, aO as RedFormat, aP as RGFormat, aQ as RGBAFormat, aR as UnsignedByteType, aS as HalfFloatType, aT as UnsignedInt101111Type, aU as UnsignedInt5999Type, aV as UnsignedShortType, aW as FloatType, aX as DataTexture, aY as Data3DTexture, aZ as RGB_PVRTC_4BPPV1_Format, a_ as RGB_ETC1_Format, a$ as RGB_BPTC_UNSIGNED_Format, b0 as Float32BufferAttribute, b1 as LinearMipMapLinearFilter, b2 as Triangle, b3 as CanvasTexture, b4 as WebGLRenderer, b5 as WebGLRenderTarget, b6 as OneFactor, b7 as ZeroFactor, b8 as CustomBlending, b9 as Box2, ba as Matrix2, bb as Vector4, bc as DataTextureLoader, bd as DataUtils, be as REVISION, bf as TextureSource, bg as ImageUtils, bh as Scene, bi as ecefToGeodeticPosition, bj as getEnuBasis, bk as BackSide, bl as BoxGeometry, bm as normalizeLayerOffset, bn as geodeticOffsetToEcefDelta, bo as validateGeodeticPosition, bp as validateTuple, bq as validateScale, br as geodeticToEcefPosition, bs as enuToEcefDelta, bt as RingGeometry, bu as AgXToneMapping, bv as EquirectangularReflectionMapping, bw as validateRotation, bx as requireFiniteNumber } from "./index-BgprA821.js";
|
|
6
6
|
var bayer_dither_hash_pars_default$1 = "#ifdef USE_HASH\nuniform float hashOpacity;varying float vCameraDistance;float bayerDitherPattern(vec2 p){float bayerMatrix[16];bayerMatrix[0]=0.0;bayerMatrix[1]=8.0;bayerMatrix[2]=2.0;bayerMatrix[3]=10.0;bayerMatrix[4]=12.0;bayerMatrix[5]=4.0;bayerMatrix[6]=14.0;bayerMatrix[7]=6.0;bayerMatrix[8]=3.0;bayerMatrix[9]=11.0;bayerMatrix[10]=1.0;bayerMatrix[11]=9.0;bayerMatrix[12]=15.0;bayerMatrix[13]=7.0;bayerMatrix[14]=13.0;bayerMatrix[15]=5.0;int x=int(mod(p.x,4.0));int y=int(mod(p.y,4.0));int index=x+y*4;return bayerMatrix[index]/16.0;}\n#endif\n";
|
|
7
7
|
var bayer_dither_hash_default$1 = "#ifdef USE_HASH\nfloat hashAmount=smoothstep(5e4,1e2,vCameraDistance)*0.75+0.1;float ditherValue=bayerDitherPattern(gl_FragCoord.xy);if(hashAmount<ditherValue){discard;}\n#endif\n";
|
|
8
8
|
var bayer_dither_hash_pars_default = "#ifdef USE_HASH\nvarying float vCameraDistance;\n#endif\n";
|
|
@@ -156,7 +156,7 @@ class CSS2DRenderer {
|
|
|
156
156
|
}
|
|
157
157
|
let sparkPromise = null;
|
|
158
158
|
function loadSpark() {
|
|
159
|
-
sparkPromise ?? (sparkPromise = import("./spark.module-
|
|
159
|
+
sparkPromise ?? (sparkPromise = import("./spark.module-T7c-X7OV.js").catch((error) => {
|
|
160
160
|
sparkPromise = null;
|
|
161
161
|
throw error;
|
|
162
162
|
}));
|
|
@@ -7711,8 +7711,14 @@ class TileDecoders {
|
|
|
7711
7711
|
this.disposed = false;
|
|
7712
7712
|
}
|
|
7713
7713
|
getDraco() {
|
|
7714
|
+
var _a3, _b2;
|
|
7714
7715
|
if (this.disposed) throw new Error("Tile decoders disposed");
|
|
7715
|
-
|
|
7716
|
+
if (!this.draco) {
|
|
7717
|
+
const loader = new DRACOLoader();
|
|
7718
|
+
if ((_b2 = (_a3 = globalThis.navigator) == null ? void 0 : _a3.userAgent) == null ? void 0 : _b2.includes("OculusBrowser/")) loader.decoderConfig.type = "js";
|
|
7719
|
+
this.draco = managedLoader(loader, "_initDecoder", "decodeGeometry", "decoderPending");
|
|
7720
|
+
}
|
|
7721
|
+
return this.draco;
|
|
7716
7722
|
}
|
|
7717
7723
|
getKTX2() {
|
|
7718
7724
|
if (this.disposed) throw new Error("Tile decoders disposed");
|
|
@@ -7730,6 +7736,17 @@ class TileDecoders {
|
|
|
7730
7736
|
(_b2 = this.ktx2) == null ? void 0 : _b2.dispose();
|
|
7731
7737
|
}
|
|
7732
7738
|
}
|
|
7739
|
+
function updateTilesCamera(tiles, camera, renderer) {
|
|
7740
|
+
var _a3;
|
|
7741
|
+
tiles.setCamera(camera);
|
|
7742
|
+
const eye = ((_a3 = renderer.xr) == null ? void 0 : _a3.isPresenting) ? renderer.xr.getCamera().cameras[0] : null;
|
|
7743
|
+
const viewport = eye == null ? void 0 : eye.viewport;
|
|
7744
|
+
if (viewport && viewport.width > 0 && viewport.height > 0) {
|
|
7745
|
+
tiles.setResolution(camera, viewport.width, viewport.height);
|
|
7746
|
+
} else {
|
|
7747
|
+
tiles.setResolutionFromRenderer(camera, renderer);
|
|
7748
|
+
}
|
|
7749
|
+
}
|
|
7733
7750
|
var i = class {
|
|
7734
7751
|
constructor(e = {}) {
|
|
7735
7752
|
let { apiToken: t2, autoRefreshToken: n2 = false } = e;
|
|
@@ -11093,8 +11110,7 @@ class GlobeManager extends EventDispatcher {
|
|
|
11093
11110
|
})
|
|
11094
11111
|
);
|
|
11095
11112
|
this.scene.add(this.tiles.group);
|
|
11096
|
-
this.tiles
|
|
11097
|
-
this.tiles.setCamera(this.camera);
|
|
11113
|
+
updateTilesCamera(this.tiles, this.camera, this.renderer);
|
|
11098
11114
|
this.tiles.addEventListener("load-model", ({ scene }) => {
|
|
11099
11115
|
scene.traverse((c3) => {
|
|
11100
11116
|
if (Array.isArray(c3.material)) {
|
|
@@ -11108,8 +11124,7 @@ class GlobeManager extends EventDispatcher {
|
|
|
11108
11124
|
}
|
|
11109
11125
|
update() {
|
|
11110
11126
|
if (!this.tiles) return;
|
|
11111
|
-
this.tiles
|
|
11112
|
-
this.tiles.setCamera(this.camera);
|
|
11127
|
+
updateTilesCamera(this.tiles, this.camera, this.renderer);
|
|
11113
11128
|
this.tiles.errorTarget = 20;
|
|
11114
11129
|
this.tiles.update();
|
|
11115
11130
|
}
|
|
@@ -14578,8 +14593,7 @@ class TilesLayer extends ContentLayer {
|
|
|
14578
14593
|
tiles.parseQueue = this.firstSet.parseQueue;
|
|
14579
14594
|
tiles.processNodeQueue = this.firstSet.processNodeQueue;
|
|
14580
14595
|
}
|
|
14581
|
-
tiles.
|
|
14582
|
-
tiles.setResolutionFromRenderer(this.camera, this.renderer);
|
|
14596
|
+
updateTilesCamera(tiles, this.camera, this.renderer);
|
|
14583
14597
|
tiles.addEventListener("load-model", (event) => {
|
|
14584
14598
|
var _a3;
|
|
14585
14599
|
if (hasOffset && !offsetApplied) {
|
|
@@ -14629,7 +14643,10 @@ class TilesLayer extends ContentLayer {
|
|
|
14629
14643
|
}
|
|
14630
14644
|
update() {
|
|
14631
14645
|
super.update();
|
|
14632
|
-
if (this.visible)
|
|
14646
|
+
if (this.visible) {
|
|
14647
|
+
updateTilesCamera(this.tiles, this.camera, this.renderer);
|
|
14648
|
+
this.tiles.update();
|
|
14649
|
+
}
|
|
14633
14650
|
}
|
|
14634
14651
|
dispose() {
|
|
14635
14652
|
super.dispose();
|
|
@@ -15167,8 +15184,9 @@ function raycastSurfaces(viewer, raycaster, options = {}) {
|
|
|
15167
15184
|
return;
|
|
15168
15185
|
}
|
|
15169
15186
|
const hits = [];
|
|
15170
|
-
(_b3 = object.raycast) == null ? void 0 : _b3.call(object, raycaster, hits);
|
|
15187
|
+
const traverseChildren = (_b3 = object.raycast) == null ? void 0 : _b3.call(object, raycaster, hits);
|
|
15171
15188
|
for (const hit of hits) accept(hit, kind, layerId);
|
|
15189
|
+
if (traverseChildren === false) return;
|
|
15172
15190
|
for (const child of object.children) visit(child, kind, layerId);
|
|
15173
15191
|
};
|
|
15174
15192
|
const previousMask = raycaster.layers.mask;
|
|
@@ -15192,6 +15210,653 @@ function raycastSurfaces(viewer, raycaster, options = {}) {
|
|
|
15192
15210
|
}
|
|
15193
15211
|
return nearest;
|
|
15194
15212
|
}
|
|
15213
|
+
const normalizeDegrees = (degrees) => (degrees % 360 + 360) % 360;
|
|
15214
|
+
class XRPlayerRig {
|
|
15215
|
+
/** @param {Matrix4} initialCameraWorld @param {XRRigidTransform} initialHeadPose */
|
|
15216
|
+
constructor(initialCameraWorld, initialHeadPose) {
|
|
15217
|
+
this.headLocal = new Matrix4().fromArray(initialHeadPose.matrix);
|
|
15218
|
+
const cameraPosition = new Vector3().setFromMatrixPosition(initialCameraWorld);
|
|
15219
|
+
const geo = ecefToGeodeticPosition(...cameraPosition.toArray());
|
|
15220
|
+
const { east, north, up } = getEnuBasis(geo.lon, geo.lat);
|
|
15221
|
+
const eastAxis = new Vector3().fromArray(east);
|
|
15222
|
+
const northAxis = new Vector3().fromArray(north);
|
|
15223
|
+
const cameraForward = new Vector3(0, 0, -1).transformDirection(initialCameraWorld);
|
|
15224
|
+
const desktopHeading = Math.atan2(cameraForward.dot(eastAxis), cameraForward.dot(northAxis));
|
|
15225
|
+
const trackedForward = new Vector3(0, 0, -1).transformDirection(this.headLocal);
|
|
15226
|
+
const trackedHeading = Math.atan2(trackedForward.x, -trackedForward.z);
|
|
15227
|
+
this.worldFromLocal = new Matrix4().makeBasis(eastAxis, new Vector3().fromArray(up), northAxis.negate()).multiply(new Matrix4().makeRotationY(trackedHeading - desktopHeading));
|
|
15228
|
+
const headOffset = new Vector3().setFromMatrixPosition(this.headLocal).applyMatrix4(this.worldFromLocal);
|
|
15229
|
+
this.worldFromLocal.setPosition(cameraPosition.sub(headOffset));
|
|
15230
|
+
this.anchor = this.getHeadPose().geodetic;
|
|
15231
|
+
}
|
|
15232
|
+
/** @param {XRRigidTransform} pose */
|
|
15233
|
+
updateHeadPose(pose) {
|
|
15234
|
+
this.headLocal.fromArray(pose.matrix);
|
|
15235
|
+
}
|
|
15236
|
+
getWorldFromLocalMatrix() {
|
|
15237
|
+
return this.worldFromLocal.clone();
|
|
15238
|
+
}
|
|
15239
|
+
getWorldHeadMatrix() {
|
|
15240
|
+
return this.worldFromLocal.clone().multiply(this.headLocal);
|
|
15241
|
+
}
|
|
15242
|
+
/** @returns {XRHeadPose} WGS84 degrees, ellipsoidal altitude metres, ECEF metres, local-floor metres. */
|
|
15243
|
+
getHeadPose() {
|
|
15244
|
+
const world = this.getWorldHeadMatrix();
|
|
15245
|
+
const position = new Vector3().setFromMatrixPosition(world);
|
|
15246
|
+
const geo = ecefToGeodeticPosition(...position.toArray());
|
|
15247
|
+
const basis = getEnuBasis(geo.lon, geo.lat);
|
|
15248
|
+
const forward = new Vector3(0, 0, -1).transformDirection(world);
|
|
15249
|
+
const headingDegrees = normalizeDegrees(Math.atan2(forward.dot(new Vector3().fromArray(basis.east)), forward.dot(new Vector3().fromArray(basis.north))) * 180 / Math.PI);
|
|
15250
|
+
return {
|
|
15251
|
+
worldEcef: position.toArray(),
|
|
15252
|
+
geodetic: { longitude: geo.lon, latitude: geo.lat, altitude: geo.alt },
|
|
15253
|
+
headingDegrees,
|
|
15254
|
+
localHeadOffset: new Vector3().setFromMatrixPosition(this.headLocal).toArray()
|
|
15255
|
+
};
|
|
15256
|
+
}
|
|
15257
|
+
getNavigationFrame() {
|
|
15258
|
+
const { longitude, latitude, altitude } = this.anchor;
|
|
15259
|
+
const basis = getEnuBasis(longitude, latitude);
|
|
15260
|
+
const frame = new Matrix4().makeBasis(new Vector3().fromArray(basis.east), new Vector3().fromArray(basis.up), new Vector3().fromArray(basis.north).negate());
|
|
15261
|
+
frame.setPosition(new Vector3().fromArray(geodeticToEcefPosition(longitude, latitude, altitude)));
|
|
15262
|
+
return frame;
|
|
15263
|
+
}
|
|
15264
|
+
/** Convert the copied WebXR target-ray transform to ECEF metres. */
|
|
15265
|
+
getControllerWorldRay(controller) {
|
|
15266
|
+
var _a3, _b2;
|
|
15267
|
+
const ray = controller == null ? void 0 : controller.ray;
|
|
15268
|
+
if (!ray || ((_a3 = ray.position) == null ? void 0 : _a3.length) !== 3 || ((_b2 = ray.orientation) == null ? void 0 : _b2.length) !== 4 || ![...ray.position, ...ray.orientation].every(Number.isFinite)) return null;
|
|
15269
|
+
const orientation = new Quaternion(...ray.orientation);
|
|
15270
|
+
if (orientation.lengthSq() < 1e-12) return null;
|
|
15271
|
+
const world = this.getWorldFromLocalMatrix();
|
|
15272
|
+
const origin = new Vector3(...ray.position).applyMatrix4(world);
|
|
15273
|
+
const direction = new Vector3(0, 0, -1).applyQuaternion(orientation.normalize()).transformDirection(world);
|
|
15274
|
+
return { origin: origin.toArray(), direction: direction.toArray() };
|
|
15275
|
+
}
|
|
15276
|
+
/**
|
|
15277
|
+
* Places the tracked head at a WGS84 ellipsoidal position plus ENU metres.
|
|
15278
|
+
* Heading is clockwise degrees from true north. Physical room-scale motion remains tracked.
|
|
15279
|
+
*/
|
|
15280
|
+
setPose({ anchor, east = 0, north = 0, up = 0, headingDegrees }) {
|
|
15281
|
+
const head = this.getHeadPose();
|
|
15282
|
+
const target = new Vector3().fromArray(geodeticToEcefPosition(anchor.longitude, anchor.latitude, anchor.altitude));
|
|
15283
|
+
target.add(new Vector3().fromArray(enuToEcefDelta([east, north, up], anchor.longitude, anchor.latitude)));
|
|
15284
|
+
const delta = target.clone().sub(new Vector3().fromArray(head.worldEcef));
|
|
15285
|
+
this.worldFromLocal.setPosition(new Vector3().setFromMatrixPosition(this.worldFromLocal).add(delta));
|
|
15286
|
+
if (Number.isFinite(headingDegrees)) {
|
|
15287
|
+
let turn = normalizeDegrees(headingDegrees - head.headingDegrees);
|
|
15288
|
+
if (turn > 180) turn -= 360;
|
|
15289
|
+
if (Math.abs(turn) > 1e-10) {
|
|
15290
|
+
const upAxis = new Vector3().fromArray(getEnuBasis(anchor.longitude, anchor.latitude).up);
|
|
15291
|
+
const rotation = new Matrix4().makeRotationFromQuaternion(new Quaternion().setFromAxisAngle(upAxis, -turn * Math.PI / 180));
|
|
15292
|
+
this.worldFromLocal.premultiply(new Matrix4().makeTranslation(-target.x, -target.y, -target.z));
|
|
15293
|
+
this.worldFromLocal.premultiply(rotation);
|
|
15294
|
+
this.worldFromLocal.premultiply(new Matrix4().makeTranslation(target.x, target.y, target.z));
|
|
15295
|
+
}
|
|
15296
|
+
}
|
|
15297
|
+
const anchorEcef = new Vector3().fromArray(geodeticToEcefPosition(this.anchor.longitude, this.anchor.latitude, this.anchor.altitude));
|
|
15298
|
+
if (target.distanceTo(anchorEcef) > 100) this.reanchor(headingDegrees);
|
|
15299
|
+
}
|
|
15300
|
+
reanchor(headingDegrees) {
|
|
15301
|
+
const head = this.getHeadPose();
|
|
15302
|
+
const { longitude, latitude } = head.geodetic;
|
|
15303
|
+
const { east, north, up } = getEnuBasis(longitude, latitude);
|
|
15304
|
+
const trackedForward = new Vector3(0, 0, -1).transformDirection(this.headLocal);
|
|
15305
|
+
const trackedHeading = Math.atan2(trackedForward.x, -trackedForward.z);
|
|
15306
|
+
const worldHeading = (Number.isFinite(headingDegrees) ? headingDegrees : head.headingDegrees) * Math.PI / 180;
|
|
15307
|
+
const frame = new Matrix4().makeBasis(new Vector3().fromArray(east), new Vector3().fromArray(up), new Vector3().fromArray(north).negate()).multiply(new Matrix4().makeRotationY(trackedHeading - worldHeading));
|
|
15308
|
+
const localOffset = new Vector3().setFromMatrixPosition(this.headLocal).applyMatrix4(frame);
|
|
15309
|
+
frame.setPosition(new Vector3(...head.worldEcef).sub(localOffset));
|
|
15310
|
+
this.worldFromLocal.copy(frame);
|
|
15311
|
+
this.anchor = head.geodetic;
|
|
15312
|
+
}
|
|
15313
|
+
}
|
|
15314
|
+
const HEAD_LOCAL_OFFSET = new Matrix4().makeTranslation(0, 0, -0.5);
|
|
15315
|
+
class XRComfortOverlay {
|
|
15316
|
+
constructor() {
|
|
15317
|
+
this.material = new ShaderMaterial({
|
|
15318
|
+
transparent: true,
|
|
15319
|
+
depthTest: false,
|
|
15320
|
+
depthWrite: false,
|
|
15321
|
+
side: DoubleSide,
|
|
15322
|
+
uniforms: { vignette: { value: 0 }, limit: { value: 0 }, fade: { value: 0 } },
|
|
15323
|
+
vertexShader: "varying vec2 uvOut; void main() { uvOut = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }",
|
|
15324
|
+
fragmentShader: "varying vec2 uvOut; uniform float vignette; uniform float limit; uniform float fade; void main() { float edge = smoothstep(0.48, 1.0, length((uvOut - 0.5) * 2.0)); vec3 color = limit > 2.5 ? vec3(0.2, 0.65, 1.0) : limit > 1.5 ? vec3(0.95, 0.65, 0.12) : vec3(0.95, 0.3, 0.08); float alpha = limit > 0.5 ? 0.48 : vignette; gl_FragColor = vec4(mix(limit > 0.5 ? color : vec3(0.0), vec3(0.0), fade), max(edge * alpha, fade)); }"
|
|
15325
|
+
});
|
|
15326
|
+
this.mesh = new Mesh(new PlaneGeometry(2.5, 2.5), this.material);
|
|
15327
|
+
this.mesh.matrixAutoUpdate = false;
|
|
15328
|
+
this.mesh.layers.set(31);
|
|
15329
|
+
this.mesh.renderOrder = 10001;
|
|
15330
|
+
this.mesh.visible = false;
|
|
15331
|
+
this.moving = false;
|
|
15332
|
+
this.navigationLimit = null;
|
|
15333
|
+
this.fade = 0;
|
|
15334
|
+
}
|
|
15335
|
+
setNavigationLimit(reason) {
|
|
15336
|
+
const next = reason === "floor" || reason === "unknown" || reason === "loading" ? reason : null;
|
|
15337
|
+
if (this.navigationLimit === next) return false;
|
|
15338
|
+
this.navigationLimit = next;
|
|
15339
|
+
return true;
|
|
15340
|
+
}
|
|
15341
|
+
setFade(opacity) {
|
|
15342
|
+
this.fade = Number.isFinite(opacity) ? Math.min(1, Math.max(0, opacity)) : 0;
|
|
15343
|
+
}
|
|
15344
|
+
update(headMatrix) {
|
|
15345
|
+
this.mesh.matrix.copy(headMatrix).multiply(HEAD_LOCAL_OFFSET);
|
|
15346
|
+
this.mesh.matrixWorldNeedsUpdate = true;
|
|
15347
|
+
this.material.uniforms.vignette.value = this.moving ? 0.65 : 0;
|
|
15348
|
+
this.material.uniforms.limit.value = this.navigationLimit === "floor" ? 1 : this.navigationLimit === "unknown" ? 2 : this.navigationLimit === "loading" ? 3 : 0;
|
|
15349
|
+
this.material.uniforms.fade.value = this.fade;
|
|
15350
|
+
this.mesh.visible = this.moving || this.navigationLimit !== null || this.fade > 0;
|
|
15351
|
+
}
|
|
15352
|
+
dispose() {
|
|
15353
|
+
this.mesh.geometry.dispose();
|
|
15354
|
+
this.material.dispose();
|
|
15355
|
+
}
|
|
15356
|
+
}
|
|
15357
|
+
const COLORS = { valid: 5242789, blocked: 16747366, unknown: 16765802 };
|
|
15358
|
+
class XRNavigationCue {
|
|
15359
|
+
constructor(scene) {
|
|
15360
|
+
this.scene = scene;
|
|
15361
|
+
this.group = new Group$1();
|
|
15362
|
+
this.group.name = "XRNavigationCue";
|
|
15363
|
+
this.group.matrixAutoUpdate = false;
|
|
15364
|
+
this.group.visible = false;
|
|
15365
|
+
this.scene.add(this.group);
|
|
15366
|
+
}
|
|
15367
|
+
set(cue) {
|
|
15368
|
+
this.clearChildren();
|
|
15369
|
+
if (!cue) {
|
|
15370
|
+
this.group.visible = false;
|
|
15371
|
+
return;
|
|
15372
|
+
}
|
|
15373
|
+
const { anchor, arc, marker, state } = cue;
|
|
15374
|
+
if (!anchor || ![anchor.longitude, anchor.latitude, anchor.altitude].every(Number.isFinite) || !Array.isArray(arc) || arc.length > 17 || !["valid", "blocked", "unknown"].includes(state)) {
|
|
15375
|
+
this.group.visible = false;
|
|
15376
|
+
return;
|
|
15377
|
+
}
|
|
15378
|
+
const basis = getEnuBasis(anchor.longitude, anchor.latitude);
|
|
15379
|
+
const east = new Vector3().fromArray(basis.east);
|
|
15380
|
+
const up = new Vector3().fromArray(basis.up);
|
|
15381
|
+
const south = new Vector3().fromArray(basis.north).negate();
|
|
15382
|
+
this.group.matrix.copy(new Matrix4().makeBasis(east, up, south));
|
|
15383
|
+
this.group.matrix.setPosition(...geodeticToEcefPosition(anchor.longitude, anchor.latitude, anchor.altitude));
|
|
15384
|
+
this.group.updateMatrixWorld(true);
|
|
15385
|
+
const color = COLORS[state];
|
|
15386
|
+
if (arc.length >= 2 && arc.every((point) => (point == null ? void 0 : point.length) === 3 && point.every(Number.isFinite))) {
|
|
15387
|
+
const geometry = new BufferGeometry();
|
|
15388
|
+
geometry.setAttribute("position", new Float32BufferAttribute(arc.flatMap(([e, n2, u2]) => [e, u2, -n2]), 3));
|
|
15389
|
+
const line = new Line(geometry, new LineBasicMaterial({ color, depthTest: true, depthWrite: false }));
|
|
15390
|
+
line.layers.set(0);
|
|
15391
|
+
this.group.add(line);
|
|
15392
|
+
}
|
|
15393
|
+
if ((marker == null ? void 0 : marker.length) === 3 && marker.every(Number.isFinite)) {
|
|
15394
|
+
const ring = new Mesh(new RingGeometry(0.13, 0.19, 24), new MeshBasicMaterial({ color, side: DoubleSide, depthTest: true, depthWrite: false }));
|
|
15395
|
+
ring.rotation.x = -Math.PI / 2;
|
|
15396
|
+
ring.position.set(marker[0], marker[2] + 0.03, -marker[1]);
|
|
15397
|
+
ring.layers.set(0);
|
|
15398
|
+
this.group.add(ring);
|
|
15399
|
+
const stem = new BufferGeometry().setFromPoints([new Vector3(marker[0], marker[2] + 0.03, -marker[1]), new Vector3(marker[0], marker[2] + 0.23, -marker[1])]);
|
|
15400
|
+
const whisker = new Line(stem, new LineBasicMaterial({ color, depthTest: true, depthWrite: false }));
|
|
15401
|
+
whisker.layers.set(0);
|
|
15402
|
+
this.group.add(whisker);
|
|
15403
|
+
}
|
|
15404
|
+
this.group.visible = this.group.children.length > 0;
|
|
15405
|
+
}
|
|
15406
|
+
clearChildren() {
|
|
15407
|
+
var _a3, _b2;
|
|
15408
|
+
for (const child of [...this.group.children]) {
|
|
15409
|
+
this.group.remove(child);
|
|
15410
|
+
(_a3 = child.geometry) == null ? void 0 : _a3.dispose();
|
|
15411
|
+
(_b2 = child.material) == null ? void 0 : _b2.dispose();
|
|
15412
|
+
}
|
|
15413
|
+
}
|
|
15414
|
+
dispose() {
|
|
15415
|
+
this.clearChildren();
|
|
15416
|
+
this.scene.remove(this.group);
|
|
15417
|
+
}
|
|
15418
|
+
}
|
|
15419
|
+
const cesiumLogoUrl = "data:image/png;base64,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";
|
|
15420
|
+
const googleLogoUrl = "data:image/png;base64,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";
|
|
15421
|
+
const HEAD_PANEL_OFFSET = new Matrix4().makeTranslation(-0.35, -0.55, -1.2);
|
|
15422
|
+
function attributionText(tileAttributions = [], terrainCredits = []) {
|
|
15423
|
+
const values = [
|
|
15424
|
+
...tileAttributions.filter(({ type, value }) => type === "string" && typeof value === "string").map(({ value }) => value),
|
|
15425
|
+
...terrainCredits.filter((value) => typeof value === "string")
|
|
15426
|
+
];
|
|
15427
|
+
return [...new Set(values.map((value) => value.replace(/<[^>]+>/g, "").replace(/&/g, "&").replace(/ /g, " ").replace(/</g, "<").replace(/>/g, ">").trim()).filter(Boolean))];
|
|
15428
|
+
}
|
|
15429
|
+
function wrap(ctx, value, maxWidth) {
|
|
15430
|
+
const lines = [];
|
|
15431
|
+
let line = "";
|
|
15432
|
+
const words = value.split(/\s+/).flatMap((word) => {
|
|
15433
|
+
if (ctx.measureText(word).width <= maxWidth) return [word];
|
|
15434
|
+
const pieces = [];
|
|
15435
|
+
let piece = "";
|
|
15436
|
+
for (const character of word) {
|
|
15437
|
+
if (piece && ctx.measureText(piece + character).width > maxWidth) {
|
|
15438
|
+
pieces.push(piece);
|
|
15439
|
+
piece = "";
|
|
15440
|
+
}
|
|
15441
|
+
piece += character;
|
|
15442
|
+
}
|
|
15443
|
+
if (piece) pieces.push(piece);
|
|
15444
|
+
return pieces;
|
|
15445
|
+
});
|
|
15446
|
+
for (const word of words) {
|
|
15447
|
+
const candidate = line ? `${line} ${word}` : word;
|
|
15448
|
+
if (line && ctx.measureText(candidate).width > maxWidth) {
|
|
15449
|
+
lines.push(line);
|
|
15450
|
+
line = word;
|
|
15451
|
+
} else line = candidate;
|
|
15452
|
+
}
|
|
15453
|
+
if (line) lines.push(line);
|
|
15454
|
+
return lines;
|
|
15455
|
+
}
|
|
15456
|
+
function layoutAttributionLines(ctx, values) {
|
|
15457
|
+
const lines = values.flatMap((value) => wrap(ctx, value, 540));
|
|
15458
|
+
const rows = Math.max(1, Math.ceil(lines.length / 2));
|
|
15459
|
+
const lineHeight = Math.min(38, 230 / rows);
|
|
15460
|
+
const fontSize = Math.min(32, lineHeight - 4);
|
|
15461
|
+
return lines.map((text, index) => ({
|
|
15462
|
+
text,
|
|
15463
|
+
x: index < rows ? 30 : 630,
|
|
15464
|
+
y: 120 + index % rows * lineHeight,
|
|
15465
|
+
fontSize
|
|
15466
|
+
}));
|
|
15467
|
+
}
|
|
15468
|
+
class XRAttributionPanel {
|
|
15469
|
+
constructor() {
|
|
15470
|
+
const canvas = document.createElement("canvas");
|
|
15471
|
+
canvas.width = 1200;
|
|
15472
|
+
canvas.height = 360;
|
|
15473
|
+
this.canvas = canvas;
|
|
15474
|
+
this.context = canvas.getContext("2d");
|
|
15475
|
+
this.texture = new CanvasTexture(canvas);
|
|
15476
|
+
this.texture.colorSpace = SRGBColorSpace;
|
|
15477
|
+
this.mesh = new Mesh(new PlaneGeometry(1.1, 0.33), new MeshBasicMaterial({ map: this.texture, transparent: true, depthTest: false, depthWrite: false, side: DoubleSide, toneMapped: false }));
|
|
15478
|
+
this.mesh.name = "XRAttributionPanel";
|
|
15479
|
+
this.mesh.matrixAutoUpdate = false;
|
|
15480
|
+
this.mesh.layers.set(31);
|
|
15481
|
+
this.mesh.renderOrder = 10002;
|
|
15482
|
+
this.terrainCredits = [];
|
|
15483
|
+
this.lastText = "";
|
|
15484
|
+
this.lastTileCheckMs = -Infinity;
|
|
15485
|
+
this.tileCredits = [];
|
|
15486
|
+
this.logos = [];
|
|
15487
|
+
for (const url of [cesiumLogoUrl, googleLogoUrl]) {
|
|
15488
|
+
const image = new Image();
|
|
15489
|
+
image.onload = () => this.draw();
|
|
15490
|
+
image.src = url;
|
|
15491
|
+
this.logos.push(image);
|
|
15492
|
+
}
|
|
15493
|
+
this.draw();
|
|
15494
|
+
}
|
|
15495
|
+
setTerrainCredits(credits) {
|
|
15496
|
+
this.terrainCredits = Array.isArray(credits) ? credits : [];
|
|
15497
|
+
this.draw();
|
|
15498
|
+
}
|
|
15499
|
+
update(headMatrix, tiles, timeMs) {
|
|
15500
|
+
var _a3;
|
|
15501
|
+
this.mesh.matrix.copy(headMatrix).multiply(HEAD_PANEL_OFFSET);
|
|
15502
|
+
this.mesh.matrixWorldNeedsUpdate = true;
|
|
15503
|
+
if (timeMs - this.lastTileCheckMs >= 1e3) {
|
|
15504
|
+
this.lastTileCheckMs = timeMs;
|
|
15505
|
+
this.tileCredits = ((_a3 = tiles == null ? void 0 : tiles.getAttributions) == null ? void 0 : _a3.call(tiles)) ?? [];
|
|
15506
|
+
this.draw();
|
|
15507
|
+
}
|
|
15508
|
+
}
|
|
15509
|
+
draw() {
|
|
15510
|
+
var _a3, _b2;
|
|
15511
|
+
const ctx = this.context;
|
|
15512
|
+
if (!ctx) return;
|
|
15513
|
+
const lines = attributionText(this.tileCredits, this.terrainCredits);
|
|
15514
|
+
const signature = lines.join("\n") + ":" + this.logos.map((logo) => logo.complete && logo.naturalWidth > 0).join(",");
|
|
15515
|
+
if (signature === this.lastText) return;
|
|
15516
|
+
this.lastText = signature;
|
|
15517
|
+
ctx.clearRect(0, 0, 1200, 360);
|
|
15518
|
+
ctx.fillStyle = "rgba(255,255,255,0.82)";
|
|
15519
|
+
ctx.fillRect(0, 0, 1200, 360);
|
|
15520
|
+
ctx.fillStyle = "#1b2430";
|
|
15521
|
+
ctx.font = "bold 28px Arial, sans-serif";
|
|
15522
|
+
if (((_a3 = this.logos[0]) == null ? void 0 : _a3.complete) && this.logos[0].naturalWidth > 0) ctx.drawImage(this.logos[0], 30, 22, 294, 50);
|
|
15523
|
+
else ctx.fillText("Cesium ion", 30, 61);
|
|
15524
|
+
if (((_b2 = this.logos[1]) == null ? void 0 : _b2.complete) && this.logos[1].naturalWidth > 0) ctx.drawImage(this.logos[1], 390, 28, 272, 50);
|
|
15525
|
+
else ctx.fillText("Google Maps", 390, 61);
|
|
15526
|
+
ctx.font = "32px Arial, sans-serif";
|
|
15527
|
+
for (const line of layoutAttributionLines(ctx, lines.length ? lines : ["Google Maps 3D Tiles"])) {
|
|
15528
|
+
ctx.font = `${line.fontSize}px Arial, sans-serif`;
|
|
15529
|
+
ctx.fillText(line.text, line.x, line.y);
|
|
15530
|
+
}
|
|
15531
|
+
this.texture.needsUpdate = true;
|
|
15532
|
+
}
|
|
15533
|
+
dispose() {
|
|
15534
|
+
this.mesh.geometry.dispose();
|
|
15535
|
+
this.mesh.material.dispose();
|
|
15536
|
+
this.texture.dispose();
|
|
15537
|
+
}
|
|
15538
|
+
}
|
|
15539
|
+
function createXRRenderBridge(viewer, initialHeadPose, { showAttribution = true } = {}) {
|
|
15540
|
+
const { camera, renderer } = viewer;
|
|
15541
|
+
if (camera.parent !== null) throw new Error("WebXR camera bridge requires an unparented viewer camera");
|
|
15542
|
+
camera.updateMatrixWorld(true);
|
|
15543
|
+
const rig = new XRPlayerRig(camera.matrixWorld, initialHeadPose);
|
|
15544
|
+
const anchor = new Group$1();
|
|
15545
|
+
anchor.matrixAutoUpdate = false;
|
|
15546
|
+
anchor.matrix.copy(rig.getWorldFromLocalMatrix());
|
|
15547
|
+
anchor.updateMatrixWorld(true);
|
|
15548
|
+
viewer.scene.add(anchor);
|
|
15549
|
+
const originalRender = renderer.render;
|
|
15550
|
+
const originalCameraAutoUpdate = renderer.xr.cameraAutoUpdate;
|
|
15551
|
+
let currentHead = camera.matrix.clone().fromArray(initialHeadPose.matrix);
|
|
15552
|
+
let disposed = false;
|
|
15553
|
+
const comfort = new XRComfortOverlay();
|
|
15554
|
+
const attribution = !showAttribution || typeof document === "undefined" || typeof Image === "undefined" ? null : new XRAttributionPanel();
|
|
15555
|
+
const navigationCue = new XRNavigationCue(viewer.scene);
|
|
15556
|
+
anchor.add(comfort.mesh);
|
|
15557
|
+
if (attribution) anchor.add(attribution.mesh);
|
|
15558
|
+
const restoreWorldPose = (world) => {
|
|
15559
|
+
if (camera.parent === anchor) anchor.remove(camera);
|
|
15560
|
+
world.decompose(camera.position, camera.quaternion, camera.scale);
|
|
15561
|
+
camera.updateMatrixWorld(true);
|
|
15562
|
+
};
|
|
15563
|
+
const renderBridge = (scene, renderCamera) => {
|
|
15564
|
+
var _a3;
|
|
15565
|
+
if (disposed || renderCamera !== camera) return originalRender.call(renderer, scene, renderCamera);
|
|
15566
|
+
camera.updateMatrixWorld(true);
|
|
15567
|
+
const worldBeforeRender = camera.matrixWorld.clone();
|
|
15568
|
+
anchor.matrix.copy(rig.getWorldFromLocalMatrix());
|
|
15569
|
+
anchor.updateMatrixWorld(true);
|
|
15570
|
+
comfort.update(currentHead);
|
|
15571
|
+
attribution == null ? void 0 : attribution.update(currentHead, (_a3 = viewer.globeManager) == null ? void 0 : _a3.tiles, performance.now());
|
|
15572
|
+
anchor.add(camera);
|
|
15573
|
+
currentHead.decompose(camera.position, camera.quaternion, camera.scale);
|
|
15574
|
+
camera.updateMatrixWorld(true);
|
|
15575
|
+
try {
|
|
15576
|
+
if (renderer.xr.isPresenting) {
|
|
15577
|
+
renderer.xr.cameraAutoUpdate = false;
|
|
15578
|
+
renderer.xr.updateCamera(camera);
|
|
15579
|
+
const xrCamera = renderer.xr.getCamera();
|
|
15580
|
+
xrCamera.layers.mask = camera.layers.mask;
|
|
15581
|
+
for (const eye of xrCamera.cameras) eye.layers.mask = camera.layers.mask;
|
|
15582
|
+
}
|
|
15583
|
+
return originalRender.call(renderer, scene, renderCamera);
|
|
15584
|
+
} finally {
|
|
15585
|
+
restoreWorldPose(worldBeforeRender);
|
|
15586
|
+
}
|
|
15587
|
+
};
|
|
15588
|
+
renderer.render = renderBridge;
|
|
15589
|
+
return {
|
|
15590
|
+
getHeadPose: () => rig.getHeadPose(),
|
|
15591
|
+
getControllerWorldRay: (controller) => rig.getControllerWorldRay(controller),
|
|
15592
|
+
setNavigationCue: (cue) => navigationCue.set(cue),
|
|
15593
|
+
setTerrainCredits: (credits) => attribution == null ? void 0 : attribution.setTerrainCredits(credits),
|
|
15594
|
+
setPlayerPose(pose) {
|
|
15595
|
+
if (disposed) return;
|
|
15596
|
+
rig.setPose(pose);
|
|
15597
|
+
restoreWorldPose(rig.getWorldHeadMatrix());
|
|
15598
|
+
},
|
|
15599
|
+
hasUi() {
|
|
15600
|
+
return Boolean(attribution) || comfort.moving || comfort.navigationLimit !== null || comfort.fade > 0;
|
|
15601
|
+
},
|
|
15602
|
+
setNavigationLimit(reason) {
|
|
15603
|
+
if (comfort.setNavigationLimit(reason)) comfort.update(currentHead);
|
|
15604
|
+
},
|
|
15605
|
+
setComfortMoving(moving) {
|
|
15606
|
+
comfort.moving = Boolean(moving);
|
|
15607
|
+
comfort.update(currentHead);
|
|
15608
|
+
},
|
|
15609
|
+
setFade(opacity) {
|
|
15610
|
+
comfort.setFade(opacity);
|
|
15611
|
+
comfort.update(currentHead);
|
|
15612
|
+
},
|
|
15613
|
+
updateHeadPose(pose) {
|
|
15614
|
+
if (disposed) return;
|
|
15615
|
+
currentHead = camera.matrix.clone().fromArray(pose.matrix);
|
|
15616
|
+
rig.updateHeadPose(pose);
|
|
15617
|
+
comfort.update(currentHead);
|
|
15618
|
+
restoreWorldPose(rig.getWorldHeadMatrix());
|
|
15619
|
+
},
|
|
15620
|
+
dispose() {
|
|
15621
|
+
if (disposed) return;
|
|
15622
|
+
disposed = true;
|
|
15623
|
+
renderer.xr.cameraAutoUpdate = originalCameraAutoUpdate;
|
|
15624
|
+
if (renderer.render === renderBridge) renderer.render = originalRender;
|
|
15625
|
+
if (camera.parent === anchor) restoreWorldPose(rig.getWorldHeadMatrix());
|
|
15626
|
+
anchor.remove(comfort.mesh);
|
|
15627
|
+
comfort.dispose();
|
|
15628
|
+
if (attribution) {
|
|
15629
|
+
anchor.remove(attribution.mesh);
|
|
15630
|
+
attribution.dispose();
|
|
15631
|
+
}
|
|
15632
|
+
navigationCue.dispose();
|
|
15633
|
+
viewer.scene.remove(anchor);
|
|
15634
|
+
}
|
|
15635
|
+
};
|
|
15636
|
+
}
|
|
15637
|
+
class WebXRSession {
|
|
15638
|
+
/** @param {import('./index.js').default} viewer @param {{ onFrame?: (input: { time: number, frame: XRFrame, pose: XRViewerPose }) => void, onStateChange?: (active: boolean) => void, showAttribution?: boolean }} [options] */
|
|
15639
|
+
constructor(viewer, options = {}) {
|
|
15640
|
+
this.viewer = viewer;
|
|
15641
|
+
this.onFrame = options.onFrame;
|
|
15642
|
+
this.onStateChange = options.onStateChange;
|
|
15643
|
+
this.showAttribution = options.showAttribution !== false;
|
|
15644
|
+
this.session = null;
|
|
15645
|
+
this.starting = null;
|
|
15646
|
+
this.bridge = null;
|
|
15647
|
+
this.desktop = null;
|
|
15648
|
+
this.sparkProfiles = /* @__PURE__ */ new Map();
|
|
15649
|
+
this.disposed = false;
|
|
15650
|
+
this.stopping = false;
|
|
15651
|
+
this.endRequested = false;
|
|
15652
|
+
this.active = false;
|
|
15653
|
+
this.handleSessionEnd = () => this.cleanup();
|
|
15654
|
+
this.handleFrame = (time, frame) => this.frame(time, frame);
|
|
15655
|
+
}
|
|
15656
|
+
start() {
|
|
15657
|
+
var _a3;
|
|
15658
|
+
if (this.disposed) return Promise.reject(new Error("VR session has been disposed"));
|
|
15659
|
+
if (this.active) return Promise.resolve();
|
|
15660
|
+
if (this.starting) return this.starting;
|
|
15661
|
+
if (!((_a3 = globalThis.navigator) == null ? void 0 : _a3.xr)) return Promise.reject(new Error("Immersive VR is unavailable in this browser"));
|
|
15662
|
+
this.stopping = false;
|
|
15663
|
+
this.endRequested = false;
|
|
15664
|
+
let requested;
|
|
15665
|
+
try {
|
|
15666
|
+
requested = navigator.xr.requestSession("immersive-vr", {
|
|
15667
|
+
requiredFeatures: ["local-floor"],
|
|
15668
|
+
optionalFeatures: ["high-fixed-foveation-level"]
|
|
15669
|
+
});
|
|
15670
|
+
} catch (error) {
|
|
15671
|
+
return Promise.reject(error);
|
|
15672
|
+
}
|
|
15673
|
+
this.starting = this.activate(requested).finally(() => {
|
|
15674
|
+
this.starting = null;
|
|
15675
|
+
});
|
|
15676
|
+
return this.starting;
|
|
15677
|
+
}
|
|
15678
|
+
async activate(requested) {
|
|
15679
|
+
var _a3;
|
|
15680
|
+
const session = await requested;
|
|
15681
|
+
if (this.disposed || this.stopping) {
|
|
15682
|
+
await this.endSessionOnce(session);
|
|
15683
|
+
return;
|
|
15684
|
+
}
|
|
15685
|
+
this.session = session;
|
|
15686
|
+
const { viewer } = this;
|
|
15687
|
+
const { renderer, camera } = viewer;
|
|
15688
|
+
const xr2 = renderer.xr;
|
|
15689
|
+
camera.updateMatrixWorld(true);
|
|
15690
|
+
this.desktop = {
|
|
15691
|
+
cameraWorld: camera.matrixWorld.clone(),
|
|
15692
|
+
near: camera.near,
|
|
15693
|
+
far: camera.far,
|
|
15694
|
+
globeEnabled: viewer.globeControls.enabled,
|
|
15695
|
+
keysEnabled: viewer.keysEnabled,
|
|
15696
|
+
xrEnabled: xr2.enabled,
|
|
15697
|
+
foveation: xr2.getFoveation() ?? 1,
|
|
15698
|
+
referenceSpaceType: xr2.referenceSpaceType ?? "local-floor",
|
|
15699
|
+
framebufferScaleFactor: xr2.framebufferScaleFactor ?? 1,
|
|
15700
|
+
labelRender: viewer.css2DRenderer.render,
|
|
15701
|
+
ensureSparkRenderer: viewer.ensureSparkRenderer,
|
|
15702
|
+
transitionAnimateTo: viewer.transitionControls.animateTo,
|
|
15703
|
+
tilesSchedulerSession: i$1.session
|
|
15704
|
+
};
|
|
15705
|
+
try {
|
|
15706
|
+
viewer.setAnimate(false);
|
|
15707
|
+
viewer.transitionControls.cancel();
|
|
15708
|
+
viewer.transitionControls.animateTo = async () => false;
|
|
15709
|
+
viewer.globeControls.enabled = false;
|
|
15710
|
+
viewer.keysEnabled = false;
|
|
15711
|
+
viewer.css2DRenderer.render = () => void 0;
|
|
15712
|
+
camera.near = 0.25;
|
|
15713
|
+
camera.updateProjectionMatrix();
|
|
15714
|
+
xr2.enabled = true;
|
|
15715
|
+
xr2.setReferenceSpaceType("local-floor");
|
|
15716
|
+
xr2.setFramebufferScaleFactor(0.8);
|
|
15717
|
+
xr2.setFoveation(0.75);
|
|
15718
|
+
xr2.addEventListener("sessionend", this.handleSessionEnd);
|
|
15719
|
+
this.applySparkProfile(viewer.sparkRenderer);
|
|
15720
|
+
const ensureSparkRenderer = this.desktop.ensureSparkRenderer;
|
|
15721
|
+
viewer.ensureSparkRenderer = async () => {
|
|
15722
|
+
const spark = await ensureSparkRenderer.call(viewer);
|
|
15723
|
+
if (this.desktop) this.applySparkProfile(spark);
|
|
15724
|
+
return spark;
|
|
15725
|
+
};
|
|
15726
|
+
await xr2.setSession(session);
|
|
15727
|
+
if (this.disposed || this.stopping || this.session !== session) {
|
|
15728
|
+
await this.endSessionOnce(session);
|
|
15729
|
+
this.cleanup();
|
|
15730
|
+
return;
|
|
15731
|
+
}
|
|
15732
|
+
i$1.setXRSession(session);
|
|
15733
|
+
renderer.setAnimationLoop(this.handleFrame);
|
|
15734
|
+
this.active = true;
|
|
15735
|
+
(_a3 = this.onStateChange) == null ? void 0 : _a3.call(this, true);
|
|
15736
|
+
} catch (error) {
|
|
15737
|
+
try {
|
|
15738
|
+
await this.endSessionOnce(session);
|
|
15739
|
+
} finally {
|
|
15740
|
+
this.cleanup();
|
|
15741
|
+
}
|
|
15742
|
+
throw error;
|
|
15743
|
+
}
|
|
15744
|
+
}
|
|
15745
|
+
frame(time, frame) {
|
|
15746
|
+
var _a3;
|
|
15747
|
+
if (!frame || !this.session || this.stopping) return;
|
|
15748
|
+
try {
|
|
15749
|
+
const referenceSpace = this.viewer.renderer.xr.getReferenceSpace();
|
|
15750
|
+
if (!referenceSpace) return;
|
|
15751
|
+
const pose = frame.getViewerPose(referenceSpace);
|
|
15752
|
+
if (!pose) return;
|
|
15753
|
+
if (!this.bridge) this.bridge = createXRRenderBridge(this.viewer, pose.transform, { showAttribution: this.showAttribution });
|
|
15754
|
+
else this.bridge.updateHeadPose(pose.transform);
|
|
15755
|
+
(_a3 = this.onFrame) == null ? void 0 : _a3.call(this, { time, frame, pose });
|
|
15756
|
+
this.applySparkProfile(this.viewer.sparkRenderer);
|
|
15757
|
+
this.viewer.animate(time);
|
|
15758
|
+
const spark = this.viewer.sparkRenderer;
|
|
15759
|
+
if (spark) this.viewer.renderer.xr.getCamera().layers.mask = spark.layers.mask;
|
|
15760
|
+
} catch (error) {
|
|
15761
|
+
console.error("WebXR frame failed", error);
|
|
15762
|
+
void this.stop();
|
|
15763
|
+
}
|
|
15764
|
+
}
|
|
15765
|
+
applySparkProfile(spark) {
|
|
15766
|
+
if (!spark || typeof spark !== "object") return;
|
|
15767
|
+
if (!this.sparkProfiles.has(spark)) this.sparkProfiles.set(spark, { lodSplatCount: spark.lodSplatCount, lodRenderScale: spark.lodRenderScale });
|
|
15768
|
+
spark.lodSplatCount = 5e4;
|
|
15769
|
+
spark.lodRenderScale = 4;
|
|
15770
|
+
}
|
|
15771
|
+
cleanup() {
|
|
15772
|
+
var _a3, _b2;
|
|
15773
|
+
const desktop = this.desktop;
|
|
15774
|
+
if (!desktop) return;
|
|
15775
|
+
this.desktop = null;
|
|
15776
|
+
const { viewer } = this;
|
|
15777
|
+
const { renderer, camera } = viewer;
|
|
15778
|
+
const xr2 = renderer.xr;
|
|
15779
|
+
xr2.removeEventListener("sessionend", this.handleSessionEnd);
|
|
15780
|
+
renderer.setAnimationLoop(null);
|
|
15781
|
+
i$1.setXRSession(desktop.tilesSchedulerSession);
|
|
15782
|
+
(_a3 = this.bridge) == null ? void 0 : _a3.dispose();
|
|
15783
|
+
this.bridge = null;
|
|
15784
|
+
viewer.ensureSparkRenderer = desktop.ensureSparkRenderer;
|
|
15785
|
+
viewer.transitionControls.animateTo = desktop.transitionAnimateTo;
|
|
15786
|
+
for (const [spark, previous] of this.sparkProfiles) Object.assign(spark, previous);
|
|
15787
|
+
this.sparkProfiles.clear();
|
|
15788
|
+
desktop.cameraWorld.decompose(camera.position, camera.quaternion, camera.scale);
|
|
15789
|
+
camera.updateMatrixWorld(true);
|
|
15790
|
+
camera.near = desktop.near;
|
|
15791
|
+
camera.far = desktop.far;
|
|
15792
|
+
camera.updateProjectionMatrix();
|
|
15793
|
+
viewer.globeControls.enabled = desktop.globeEnabled;
|
|
15794
|
+
viewer.keysEnabled = desktop.keysEnabled;
|
|
15795
|
+
viewer.css2DRenderer.render = desktop.labelRender;
|
|
15796
|
+
xr2.setReferenceSpaceType(desktop.referenceSpaceType);
|
|
15797
|
+
xr2.setFramebufferScaleFactor(desktop.framebufferScaleFactor);
|
|
15798
|
+
xr2.setFoveation(desktop.foveation);
|
|
15799
|
+
xr2.enabled = desktop.xrEnabled;
|
|
15800
|
+
this.session = null;
|
|
15801
|
+
viewer.setAnimate(true);
|
|
15802
|
+
if (this.active) {
|
|
15803
|
+
this.active = false;
|
|
15804
|
+
(_b2 = this.onStateChange) == null ? void 0 : _b2.call(this, false);
|
|
15805
|
+
}
|
|
15806
|
+
}
|
|
15807
|
+
async endSessionOnce(session) {
|
|
15808
|
+
if (this.endRequested) return;
|
|
15809
|
+
this.endRequested = true;
|
|
15810
|
+
try {
|
|
15811
|
+
await session.end();
|
|
15812
|
+
} catch (error) {
|
|
15813
|
+
if (!(error instanceof DOMException && error.name === "InvalidStateError")) throw error;
|
|
15814
|
+
}
|
|
15815
|
+
}
|
|
15816
|
+
async stop() {
|
|
15817
|
+
this.stopping = true;
|
|
15818
|
+
const session = this.session;
|
|
15819
|
+
if (!session) return;
|
|
15820
|
+
try {
|
|
15821
|
+
await this.endSessionOnce(session);
|
|
15822
|
+
} finally {
|
|
15823
|
+
this.cleanup();
|
|
15824
|
+
}
|
|
15825
|
+
}
|
|
15826
|
+
async dispose() {
|
|
15827
|
+
this.disposed = true;
|
|
15828
|
+
this.stopping = true;
|
|
15829
|
+
const ending = this.session ? this.endSessionOnce(this.session) : Promise.resolve();
|
|
15830
|
+
this.cleanup();
|
|
15831
|
+
await ending;
|
|
15832
|
+
}
|
|
15833
|
+
}
|
|
15834
|
+
function copyTransform(transform) {
|
|
15835
|
+
if (!transform) return null;
|
|
15836
|
+
const { position, orientation } = transform;
|
|
15837
|
+
return {
|
|
15838
|
+
position: [position.x, position.y, position.z],
|
|
15839
|
+
orientation: [orientation.x, orientation.y, orientation.z, orientation.w]
|
|
15840
|
+
};
|
|
15841
|
+
}
|
|
15842
|
+
function readXRFrameInput(frame, referenceSpace) {
|
|
15843
|
+
var _a3;
|
|
15844
|
+
if (!referenceSpace) return { head: null, controllers: [] };
|
|
15845
|
+
const head = copyTransform((_a3 = frame.getViewerPose(referenceSpace)) == null ? void 0 : _a3.transform);
|
|
15846
|
+
const controllers = [...frame.session.inputSources].map((source) => {
|
|
15847
|
+
var _a4, _b2;
|
|
15848
|
+
const gamepad = source.gamepad;
|
|
15849
|
+
return {
|
|
15850
|
+
handedness: source.handedness,
|
|
15851
|
+
mapping: (gamepad == null ? void 0 : gamepad.mapping) ?? null,
|
|
15852
|
+
axes: gamepad ? [...gamepad.axes] : [],
|
|
15853
|
+
buttons: gamepad ? gamepad.buttons.map((button) => ({ pressed: button.pressed, touched: button.touched, value: button.value })) : [],
|
|
15854
|
+
ray: copyTransform((_a4 = frame.getPose(source.targetRaySpace, referenceSpace)) == null ? void 0 : _a4.transform),
|
|
15855
|
+
grip: source.gripSpace ? copyTransform((_b2 = frame.getPose(source.gripSpace, referenceSpace)) == null ? void 0 : _b2.transform) : null
|
|
15856
|
+
};
|
|
15857
|
+
});
|
|
15858
|
+
return { head, controllers };
|
|
15859
|
+
}
|
|
15195
15860
|
const shadowCanvas = document.createElement("canvas");
|
|
15196
15861
|
shadowCanvas.width = 128;
|
|
15197
15862
|
shadowCanvas.height = 128;
|
|
@@ -15230,6 +15895,7 @@ class Viewer extends EventDispatcher {
|
|
|
15230
15895
|
this.isViewer = true;
|
|
15231
15896
|
this.type = "viewer";
|
|
15232
15897
|
this.disposed = false;
|
|
15898
|
+
this.xrSession = null;
|
|
15233
15899
|
this.sparkRenderer = null;
|
|
15234
15900
|
this.transparentBackground = options.transparentBackground ?? true;
|
|
15235
15901
|
Tokens.CESIUM = options.cesiumToken || void 0;
|
|
@@ -15361,6 +16027,70 @@ class Viewer extends EventDispatcher {
|
|
|
15361
16027
|
window.addEventListener("pointermove", this._onPointerMove);
|
|
15362
16028
|
this.setAnimate();
|
|
15363
16029
|
}
|
|
16030
|
+
get xrActive() {
|
|
16031
|
+
var _a3;
|
|
16032
|
+
return ((_a3 = this.xrSession) == null ? void 0 : _a3.active) ?? false;
|
|
16033
|
+
}
|
|
16034
|
+
/** @param {{ onFrame?: (input: { time: number, frame: XRFrame, pose: XRViewerPose }) => void, onStateChange?: (active: boolean) => void, showAttribution?: boolean }} [options] */
|
|
16035
|
+
startXRSession(options = {}) {
|
|
16036
|
+
if (this.disposed) return Promise.reject(new Error("Viewer has been disposed"));
|
|
16037
|
+
if (!this.xrSession) this.xrSession = new WebXRSession(this, options);
|
|
16038
|
+
else {
|
|
16039
|
+
this.xrSession.onFrame = options.onFrame;
|
|
16040
|
+
this.xrSession.onStateChange = options.onStateChange;
|
|
16041
|
+
this.xrSession.showAttribution = options.showAttribution !== false;
|
|
16042
|
+
}
|
|
16043
|
+
return this.xrSession.start();
|
|
16044
|
+
}
|
|
16045
|
+
endXRSession() {
|
|
16046
|
+
var _a3;
|
|
16047
|
+
return ((_a3 = this.xrSession) == null ? void 0 : _a3.stop()) ?? Promise.resolve();
|
|
16048
|
+
}
|
|
16049
|
+
/** @param {XRFrame} frame */
|
|
16050
|
+
getXRFrameInput(frame) {
|
|
16051
|
+
return readXRFrameInput(frame, this.renderer.xr.getReferenceSpace());
|
|
16052
|
+
}
|
|
16053
|
+
/** @param {{ anchor: { longitude: number, latitude: number, altitude: number }, east?: number, north?: number, up?: number, headingDegrees: number }} pose */
|
|
16054
|
+
setXRPlayerPose(pose) {
|
|
16055
|
+
var _a3;
|
|
16056
|
+
if (!((_a3 = this.xrSession) == null ? void 0 : _a3.bridge)) throw new Error("No tracked XR head pose is available");
|
|
16057
|
+
this.xrSession.bridge.setPlayerPose(pose);
|
|
16058
|
+
}
|
|
16059
|
+
/** @returns {import('./XRPlayerRig.js').XRHeadPose | null} */
|
|
16060
|
+
getXRHeadPose() {
|
|
16061
|
+
var _a3, _b2;
|
|
16062
|
+
return ((_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.getHeadPose()) ?? null;
|
|
16063
|
+
}
|
|
16064
|
+
/** @param {{ray: {position: number[], orientation: number[]} | null}} controller @returns {{origin: number[], direction: number[]} | null} */
|
|
16065
|
+
getXRControllerWorldRay(controller) {
|
|
16066
|
+
var _a3, _b2;
|
|
16067
|
+
return ((_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.getControllerWorldRay(controller)) ?? null;
|
|
16068
|
+
}
|
|
16069
|
+
/** @param {boolean} moving */
|
|
16070
|
+
setXRComfortMoving(moving) {
|
|
16071
|
+
var _a3, _b2;
|
|
16072
|
+
(_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.setComfortMoving(moving);
|
|
16073
|
+
}
|
|
16074
|
+
/** @param {'floor' | 'unknown' | 'loading' | null} reason */
|
|
16075
|
+
setXRNavigationLimit(reason) {
|
|
16076
|
+
var _a3, _b2;
|
|
16077
|
+
(_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.setNavigationLimit(reason);
|
|
16078
|
+
}
|
|
16079
|
+
/** @param {{anchor: {longitude: number, latitude: number, altitude: number}, arc: readonly (readonly [number, number, number])[], marker: readonly [number, number, number] | null, state: 'valid' | 'blocked' | 'unknown'} | null} cue */
|
|
16080
|
+
setXRNavigationCue(cue) {
|
|
16081
|
+
var _a3, _b2;
|
|
16082
|
+
(_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.setNavigationCue(cue);
|
|
16083
|
+
}
|
|
16084
|
+
/** @param {readonly string[]} credits Current Cesium World Terrain asset credits. */
|
|
16085
|
+
setXRAttribution(credits) {
|
|
16086
|
+
var _a3, _b2;
|
|
16087
|
+
(_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.setTerrainCredits(credits);
|
|
16088
|
+
}
|
|
16089
|
+
/** @param {number} opacity Black headset fade, 0 to 1. */
|
|
16090
|
+
setXRNavigationFade(opacity) {
|
|
16091
|
+
var _a3, _b2;
|
|
16092
|
+
(_b2 = (_a3 = this.xrSession) == null ? void 0 : _a3.bridge) == null ? void 0 : _b2.setFade(opacity);
|
|
16093
|
+
}
|
|
15364
16094
|
get keysEnabled() {
|
|
15365
16095
|
return this._keysEnabled;
|
|
15366
16096
|
}
|
|
@@ -15490,7 +16220,7 @@ class Viewer extends EventDispatcher {
|
|
|
15490
16220
|
}
|
|
15491
16221
|
/** @param {import('../main.js').ContentLayerDefinition[]} content */
|
|
15492
16222
|
defineContentLayers(content = []) {
|
|
15493
|
-
var _a3, _b2, _c;
|
|
16223
|
+
var _a3, _b2, _c, _d;
|
|
15494
16224
|
this.topLayerIndex = 0;
|
|
15495
16225
|
this.clearContentLayers();
|
|
15496
16226
|
for (let i2 = 0; i2 < content.length; i2++) {
|
|
@@ -15549,6 +16279,7 @@ class Viewer extends EventDispatcher {
|
|
|
15549
16279
|
default:
|
|
15550
16280
|
throw new Error(`Unsupported content layer type: ${String(layerData == null ? void 0 : layerData.type)}`);
|
|
15551
16281
|
}
|
|
16282
|
+
this.content.children.at(-1).xrRenderLayer = layerData.type === "mesh" ? 6 : ((_d = layerData.options) == null ? void 0 : _d.renderOrder) ?? 0;
|
|
15552
16283
|
} catch (error) {
|
|
15553
16284
|
this.dispatchEvent({
|
|
15554
16285
|
type: ViewerEvents.CONTENT_LAYER_ERROR,
|
|
@@ -15641,6 +16372,7 @@ class Viewer extends EventDispatcher {
|
|
|
15641
16372
|
return label.element;
|
|
15642
16373
|
}
|
|
15643
16374
|
animate(time) {
|
|
16375
|
+
var _a3, _b2, _c;
|
|
15644
16376
|
if (this.stats) this.stats.begin();
|
|
15645
16377
|
this.transitionControls.update(time);
|
|
15646
16378
|
this.state.get("time").value = time;
|
|
@@ -15677,6 +16409,10 @@ class Viewer extends EventDispatcher {
|
|
|
15677
16409
|
}
|
|
15678
16410
|
}
|
|
15679
16411
|
for (let i2 = 0; i2 < this.topLayerIndex + 1; i2++) {
|
|
16412
|
+
if (i2 > 0 && ((_a3 = this.xrSession) == null ? void 0 : _a3.active) && !this.content.children.some((layer) => {
|
|
16413
|
+
var _a4;
|
|
16414
|
+
return layer.visible && (layer.xrRenderLayer === i2 || ((_a4 = layer.layers) == null ? void 0 : _a4.isEnabled(i2)));
|
|
16415
|
+
})) continue;
|
|
15680
16416
|
this.camera.layers.set(i2);
|
|
15681
16417
|
if (i2 == 0) {
|
|
15682
16418
|
this.renderer.clear();
|
|
@@ -15686,6 +16422,11 @@ class Viewer extends EventDispatcher {
|
|
|
15686
16422
|
this.renderer.render(this.scene, this.camera);
|
|
15687
16423
|
}
|
|
15688
16424
|
}
|
|
16425
|
+
if (((_b2 = this.xrSession) == null ? void 0 : _b2.active) && ((_c = this.xrSession.bridge) == null ? void 0 : _c.hasUi())) {
|
|
16426
|
+
this.camera.layers.set(31);
|
|
16427
|
+
this.renderer.clearDepth();
|
|
16428
|
+
this.renderer.render(this.scene, this.camera);
|
|
16429
|
+
}
|
|
15689
16430
|
this.cameraCoords = ecefToGeodeticRotation(this.camera.position.x, this.camera.position.y, this.camera.position.z, this.camera.quaternion);
|
|
15690
16431
|
this.dispatchEvent({ type: ViewerEvents.ANIMATED, time, deltaTime });
|
|
15691
16432
|
if (this.stats) this.stats.end();
|
|
@@ -15839,6 +16580,10 @@ class Viewer extends EventDispatcher {
|
|
|
15839
16580
|
var _a3, _b2, _c, _d, _e, _f, _g, _h, _i2, _j, _k, _l, _m, _n2, _o;
|
|
15840
16581
|
if (this.disposed) return;
|
|
15841
16582
|
this.disposed = true;
|
|
16583
|
+
if (this.xrSession) {
|
|
16584
|
+
void this.xrSession.dispose().catch((error) => console.error("WebXR session end failed during viewer disposal", error));
|
|
16585
|
+
this.xrSession = null;
|
|
16586
|
+
}
|
|
15842
16587
|
this.setAnimate(false);
|
|
15843
16588
|
this.transitionControls.cancel();
|
|
15844
16589
|
this.clearContentLayers();
|