UNPKG

luma-splatting-for-babylonjs

Version:
163 lines (162 loc) 4.84 kB
var R = Object.defineProperty; var W = (r, e, t) => e in r ? R(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t; var G = (r, e, t) => W(r, typeof e != "symbol" ? e + "" : e, t); import { Quaternion as H, GaussianSplattingMesh as I } from "@babylonjs/core"; const N = async (r) => { var h; const t = `https://webapp.engineeringlumalabs.com/api/v3/captures/${r}/public`, s = await fetch(t, { method: "GET", headers: { "Content-Type": "application/json" } }).then((n) => n.json()); if (!((h = s.response) != null && h.artifacts)) return null; const i = s.response.artifacts, l = i.find((n) => n.type === "gs_point_cloud"), f = i.find((n) => n.type === "gs_point_cloud_meta"); return !l || !f ? null : { metaFileUrl: f.url, plyFilesUrl: l.url }; }, V = (r) => (e, t) => (s, i) => (r - e) / (t - e) * (i - s) + s, Q = (r, e) => { var L; const t = new Uint8Array(r), s = new TextDecoder().decode(t.slice(0, 1024 * 10)), i = `end_header `, l = s.indexOf(i); if (l < 0 || !s) return r; const f = (L = /element vertex (\d+)\n/.exec(s)) == null ? void 0 : L[1]; if (!f) throw new Error("cannot parse vertex count from header!"); const h = Number.parseInt(f); let n = 0; const S = { double: 8, int: 4, uint: 4, float: 4, short: 2, ushort: 2, uchar: 1 }, U = [], q = s.slice(0, l).split(` `).filter((o) => o.startsWith("property ")); for (const o of q) { const [b, p, c] = o.split(" "); if (U.push({ name: c, type: p, offset: n }), !S[p]) throw new Error(`Unsupported property type: ${p}`); n += S[p]; } const _ = 3 * 4 + 3 * 4 + 4 + 4, w = 0.28209479177387814, z = new DataView(r, l + i.length), y = new ArrayBuffer(_ * h), d = new H(); for (let o = 0; o < h; o++) { const b = new Float32Array(y, o * _, 3), p = new Float32Array(y, o * _ + 12, 3), c = new Uint8ClampedArray(y, o * _ + 24, 4), x = new Uint8ClampedArray(y, o * _ + 28, 4); let M = 255, T = 0, $ = 0, j = 0; for (let A = 0; A < U.length; A++) { const m = U[A]; let u, a; switch (m.type) { case "ushort": u = z.getUint16(m.offset + o * n, !0), a = V(u)(0, 65535); break; case "uchar": u = z.getUint8(m.offset + o * n), a = V(u)(0, 255); break; default: throw new Error(`Unsupported property type: ${m.type}`); } const { f_dc_max: D, f_dc_min: E, opacity_max: O, opacity_min: P, rotation_max: k, rotation_min: g, scale_max: v, scale_min: B, xyz_max: F, xyz_min: C } = e.gaussians.bounds; switch (m.name) { case "x": b[0] = a(C[0], F[0]); break; case "y": b[1] = a(C[1], F[1]); break; case "z": b[2] = a(C[2], F[2]); break; case "scale_0": p[0] = Math.exp(a(B[0], v[0])); break; case "scale_1": p[1] = Math.exp(a(B[1], v[1])); break; case "scale_2": p[2] = Math.exp(a(B[2], v[2])); break; case "red": c[0] = u; break; case "green": c[1] = u; break; case "blue": c[2] = u; break; case "f_dc_0": c[0] = (0.5 + w * a(E[0], D[0])) * 255; break; case "f_dc_1": c[1] = (0.5 + w * a(E[1], D[1])) * 255; break; case "f_dc_2": c[2] = (0.5 + w * a(E[2], D[2])) * 255; break; case "f_dc_3": c[3] = (0.5 + w * u) * 255; break; case "opacity": c[3] = 1 / (1 + Math.exp(-a(P[0], O[0]))) * 255; break; case "rot_0": M = a(g[0], k[0]); break; case "rot_1": T = a(g[1], k[1]); break; case "rot_2": $ = a(g[2], k[2]); break; case "rot_3": j = a(g[3], k[3]); break; } } d.set(T, $, j, M), d.normalize(), x[0] = d.w * 128 + 128, x[1] = d.x * 128 + 128, x[2] = d.y * 128 + 128, x[3] = d.z * 128 + 128; } return y; }; class X { constructor(e, t) { G(this, "_splat"); this.name = e, this.scene = t, this._splat = new I(e, null, t); } get splat() { return this._splat; } async loadDataWithUuidAsync(e) { const t = await N(e); if (!t) return; const { metaFileUrl: s, plyFilesUrl: i } = t, [l, f] = await Promise.all([ fetch(i).then((n) => n.arrayBuffer()), fetch(s).then( (n) => n.json() ) ]), h = await Q( l, f ); this._splat = new I(this.name, null, this.scene), await this._splat.loadDataAsync(h); } } export { X as LumaGaussianSplatting };