UNPKG

3d-tiles-renderer

Version:

https://github.com/AnalyticalGraphicsInc/3d-tiles/tree/master/specification

271 lines (270 loc) 10.1 kB
import { T as E } from "./TilesRendererBase-BGxy2Uih.js"; import { L, g as O, r as j } from "./LoaderBase-CU5shB7w.js"; import { TransformNode as S } from "@babylonjs/core/Meshes/transformNode"; import { Matrix as u, Quaternion as W, Vector3 as i } from "@babylonjs/core/Maths/math.vector"; import { Frustum as A } from "@babylonjs/core/Maths/math.frustum"; import { Observable as N } from "@babylonjs/core/Misc/observable"; import { Plane as Q } from "@babylonjs/core/Maths/math.plane"; import { B as U } from "./B3DMLoaderBase-CMKvUOVT.js"; import { LoadAssetContainerAsync as X } from "@babylonjs/core/Loading/sceneLoader"; import "@babylonjs/loaders/glTF/2.0"; import { BoundingSphere as Y } from "@babylonjs/core/Culling/boundingSphere"; import { BoundingBox as G } from "@babylonjs/core/Culling/boundingBox"; const P = /* @__PURE__ */ u.Identity(); class V extends L { /** * @param {Scene} scene - The Babylon.js scene to load assets into. */ constructor(e) { super(), this.scene = e, this.adjustmentTransform = u.Identity(); } /** * @param {ArrayBuffer} buffer - The raw GLTF or GLB file data. * @param {string} url - URL used for resolving relative resources. * @param {string} extension - File extension, either `'gltf'` or `'glb'`. * @returns {Promise<{scene: TransformNode, container: AssetContainer, metadata: Object|null}>} */ async parse(e, t, n) { const { scene: s, workingPath: r, adjustmentTransform: o } = this; let a = r; a.length && !/[\\/]$/.test(a) && (a += "/"); const c = n === "gltf" ? ".gltf" : ".glb"; let f = null; const h = await X( new File([e], t), s, { pluginExtension: c, rootUrl: a, pluginOptions: { gltf: { onParsed: (w) => { f = w.json; } } } } ); h.addAllToScene(); const p = h.rootNodes[0]; p.rotationQuaternion = W.Identity(); const m = p.computeWorldMatrix(!0); return o.multiplyToRef(m, P), P.decompose(p.scaling, p.rotationQuaternion, p.position), { scene: p, container: h, metadata: f }; } } class H extends U { /** * @param {Scene} scene - The Babylon.js scene to load assets into. */ constructor(e) { super(), this.scene = e, this.adjustmentTransform = u.Identity(); } /** * @param {ArrayBuffer} buffer - The raw B3DM file data. * @param {string} url - URL used for resolving relative resources. * @returns {Promise<Object>} */ async parse(e, t) { const n = super.parse(e), { scene: s, workingPath: r, fetchOptions: o, adjustmentTransform: a } = this, c = new V(s); c.workingPath = r, c.fetchOptions = o, a && (c.adjustmentTransform = a); const f = await c.parse(n.glbBytes, t, "glb"), h = f.scene; return { ...n, scene: h, container: f.container, metadata: f.metadata }; } } const _ = /* @__PURE__ */ new i(); class Z { constructor() { this.min = new i(-1, -1, -1), this.max = new i(1, 1, 1), this.transform = u.Identity(), this.inverseTransform = u.Identity(), this.points = new Array(8).fill(null).map(() => new i()); } update() { const { min: e, max: t, points: n, transform: s } = this; s.invertToRef(this.inverseTransform); let r = 0; for (let o = 0; o <= 1; o++) for (let a = 0; a <= 1; a++) for (let c = 0; c <= 1; c++) n[r].set( o === 0 ? e.x : t.x, a === 0 ? e.y : t.y, c === 0 ? e.z : t.z ), i.TransformCoordinatesToRef( n[r], s, n[r] ), r++; } clampPoint(e, t) { const { min: n, max: s, transform: r, inverseTransform: o } = this; return i.TransformCoordinatesToRef(e, o, t), t.x = Math.max(n.x, Math.min(s.x, t.x)), t.y = Math.max(n.y, Math.min(s.y, t.y)), t.z = Math.max(n.z, Math.min(s.z, t.z)), i.TransformCoordinatesToRef(t, r, t), t; } distanceToPoint(e) { return this.clampPoint(e, _), i.Distance(_, e); } intersectsFrustum(e) { return G.IsInFrustum(this.points, e); } } const g = /* @__PURE__ */ new i(), b = /* @__PURE__ */ new i(), T = /* @__PURE__ */ new i(), y = /* @__PURE__ */ new i(), I = /* @__PURE__ */ new i(); class $ { constructor() { this.sphere = null, this.obb = null; } setSphereData(e, t, n, s, r) { const o = new Y(I, I), a = o.centerWorld.set(e, t, n); i.TransformCoordinatesToRef(a, r, a), r.decompose(y, null, null), o.radiusWorld = s * Math.max(Math.abs(y.x), Math.abs(y.y), Math.abs(y.z)), this.sphere = o; } setObbData(e, t) { const n = new Z(); g.set(e[3], e[4], e[5]), b.set(e[6], e[7], e[8]), T.set(e[9], e[10], e[11]); const s = g.length(), r = b.length(), o = T.length(); g.normalize(), b.normalize(), T.normalize(), s === 0 && i.CrossToRef(b, T, g), r === 0 && i.CrossToRef(g, T, b), o === 0 && i.CrossToRef(g, b, T), n.transform = u.FromValues( g.x, b.x, T.x, e[0], g.y, b.y, T.y, e[1], g.z, b.z, T.z, e[2], 0, 0, 0, 1 ).transpose().multiply(t), n.min.set(-s, -r, -o), n.max.set(s, r, o), n.update(), this.obb = n; } distanceToPoint(e) { const { sphere: t, obb: n } = this; let s = -1 / 0, r = -1 / 0; return t && (s = i.Distance(e, t.centerWorld) - t.radiusWorld, s = Math.max(s, 0)), n && (r = n.distanceToPoint(e)), s > r ? s : r; } intersectsFrustum(e) { const { sphere: t, obb: n } = this; return t && !t.isInFrustum(e) || n && !n.intersectsFrustum(e) ? !1 : !!(t || n); } } const D = /* @__PURE__ */ u.Identity(), C = /* @__PURE__ */ new i(), B = /* @__PURE__ */ new Array(6).fill(null).map(() => new Q(0, 0, 0, 0)); class le extends E { /** * @param {string} url - URL of the root tileset JSON. * @param {Scene} scene - The Babylon.js scene to render tiles into. */ constructor(e, t) { super(e), this.scene = t, this.group = new S("tiles-root", t), this.checkCollisions = !1, this._upRotationMatrix = u.Identity(), this._observables = /* @__PURE__ */ new Map(); } addEventListener(e, t) { this._observables.has(e) || this._observables.set(e, new N()), this._observables.get(e).add(t); } removeEventListener(e, t) { if (!this._observables.has(e)) return; this._observables.get(e).removeCallback(t); } dispatchEvent(e) { if (!this._observables.has(e.type)) return; this._observables.get(e.type).notifyObservers(e); } loadRootTileset(...e) { return super.loadRootTileset(...e).then((t) => { const { asset: n } = t; switch ((n && n.gltfUpAxis || "y").toLowerCase()) { case "x": u.RotationYToRef(-Math.PI / 2, this._upRotationMatrix); break; case "y": u.RotationXToRef(Math.PI / 2, this._upRotationMatrix); break; } return t; }); } preprocessNode(e, t, n = null) { super.preprocessNode(e, t, n); const s = u.Identity(); e.transform && u.FromValuesToRef(...e.transform, s), n && s.multiplyToRef(n.engineData.transform, s); const r = u.Identity(); s.invertToRef(r); const o = new $(); "sphere" in e.boundingVolume && o.setSphereData(...e.boundingVolume.sphere, s), "box" in e.boundingVolume && o.setObbData(e.boundingVolume.box, s), e.engineData.transform = s, e.engineData.transformInverse = r, e.engineData.boundingVolume = o, e.engineData.active = !1, e.engineData.scene = null, e.engineData.container = null; } async parseTile(e, t, n, s, r) { const o = t.engineData, a = this.scene, c = O(s), f = this.fetchOptions, h = o.transform, p = this._upRotationMatrix; let m = null; const w = (j(e) || n).toLowerCase(); switch (w) { case "b3dm": { const l = new H(a); l.workingPath = c, l.fetchOptions = f, l.adjustmentTransform.copyFrom(p), m = await l.parse(e, s); break; } case "gltf": case "glb": { const l = new V(a); l.workingPath = c, l.fetchOptions = f, l.adjustmentTransform.copyFrom(p), m = await l.parse(e, s, n); break; } default: throw new Error(`BabylonTilesRenderer: Content type "${w}" not supported.`); } const d = m.scene; if (d.setEnabled(!1), d.computeWorldMatrix(!0).multiply(h).decompose(d.scaling, d.rotationQuaternion, d.position), r.aborted) { m.container.dispose(); return; } if (this.checkCollisions) for (const l of d.getChildMeshes()) l.checkCollisions = !0; o.scene = d, o.container = m.container, o.metadata = m.metadata || null; } disposeTile(e) { super.disposeTile(e); const t = e.engineData; t.container && (t.container.dispose(), t.container = null, t.scene = null, t.metadata = null); } setTileVisible(e, t) { const s = e.engineData.scene; s && (t ? (s.parent = this.group, s.setEnabled(!0)) : (s.parent = null, s.setEnabled(!1)), super.setTileVisible(e, t)); } calculateBytesUsed(e) { return 1; } calculateTileViewError(e, t) { const { scene: n } = this, r = e.engineData.boundingVolume, o = n.activeCamera, a = n.getEngine(), c = a.getHardwareScalingLevel(), f = a.getRenderWidth() * c, h = a.getRenderHeight() * c, m = o.getProjectionMatrix().m, w = m[15] === 1; let d, l; if (w) { const R = 2 / m[0], F = 2 / m[5]; l = Math.max(F / h, R / f); } else d = 2 / m[5] / h; this.group.getWorldMatrix().invertToRef(D), i.TransformCoordinatesToRef(o.globalPosition, D, C), A.GetPlanesToRef(o.getTransformationMatrix(!0), B); const k = B.map((R) => R.transform(D)), M = r.distanceToPoint(C); let v; w ? v = e.geometricError / l : v = M === 0 ? 1 / 0 : e.geometricError / (M * d); const z = r.intersectsFrustum(k); t.inView = z, t.error = v, t.distanceFromCamera = M; } /** * Disposes the renderer, releasing all loaded tile content and the root transform node. * @returns {void} */ dispose() { super.dispose(), this.group.dispose(); } } export { le as TilesRenderer }; //# sourceMappingURL=index.babylonjs.js.map