UNPKG

videx-3d

Version:

React 3D component library designed for sub surface visualizations in the browser

476 lines (475 loc) 20.5 kB
var $ = Object.defineProperty; var y = (o, t, s) => t in o ? $(o, t, { enumerable: !0, configurable: !0, writable: !0, value: s }) : o[t] = s; var L = (o, t, s) => y(o, typeof t != "symbol" ? t + "" : t, s); import { BufferGeometry as O, BufferAttribute as j } from "three"; import { lerp as S } from "three/src/math/MathUtils.js"; import { d as x, b as V, a1 as tt, y as st, f as H, a3 as nt, a0 as et, a5 as it } from "./chunk-DBaq_0xI.js"; function ot(o, t) { let s = t.findIndex((c) => c[0] > o); s === -1 && (s = t.length - 1); let n = s - 1; n < 0 && (n = 0); const e = t[n], a = t[s]; return [e, a]; } function E(o, t, s) { if (t[0] === s[0]) return s[1]; const n = s[0] - t[0], e = x((o - t[0]) / n, 0, 1); return S(t[1], s[1], e); } function at(o, t, s, n, e, a, c, d) { const r = []; if (t === "none" || a.length === 0) r.push([s, e], [n, e]); else { let i = [0, e], u = [1, e]; const h = a.findIndex((l) => l[0] > s); h === -1 ? i = a[a.length - 1] : (h > 0 && (i = a[h - 1]), u = a[h]); const _ = t === "linear" ? E(s, i, u) : i[1]; r.push([s, _]); for (let l = h; l >= 0 && l < a.length; l++) { const f = a[l]; if (f[0] < n) r.push(f); else { t === "linear" ? r.push([n, E(n, r[r.length - 1], f)]) : r.push([n, r[r.length - 1][1]]); break; } } r[r.length - 1][0] < n && (t === "linear" ? r.push([n, E(n, r[r.length - 1], [1, e])]) : r.push([n, r[r.length - 1][1]])); } const v = o.length, g = []; for (let i = 0; i < r.length - 1; i++) { const u = i + 1, [h, _] = r[i], [l, f] = r[u], m = l - h, q = m * v, w = f - _, C = Math.atan2(w, q), T = Math.floor(c * q), F = m / T; g.push([h, _, t === "linear" ? C : 0]); let B = d ? o.getTangentAt(h) : null; for (let I = 1; I < T; I++) { const p = h + I * F, M = d ? o.getTangentAt(p) : null; if (!d || Math.abs(tt(B, M)) < 1 - d) { const [R, z] = ot(p, r), P = t === "linear" ? E(p, R, z) : R[1]; g.push([p, P, t === "linear" ? C : 0]), B = M; } } if (u < r.length) { if (t === "linear") g.push([l, f, t === "linear" ? C : 0]); else if (t === "stepped") { const I = C < 0 ? -V / 2 : V / 2; g.push([l, _, 0], [l, _, I], [l, f, I]); } } u === r.length - 1 && t === "none" && g.push([l, f, C]); } const b = st(o, g.map((i) => i[0])); return g.map((i, u) => ({ radius: i[1], theta: i[2], ...b[u] })); } function Y(o, t, s = !0, n, e = 0) { let a = 0, c = 0; const d = [], r = [], v = n.computeNormals ? [] : null, g = n.computeUvs ? [] : null, b = s ? [-o.tangent[0], -o.tangent[1], -o.tangent[2]] : o.tangent; d.push(...o.position), a++, v && v.push(...b), g && g.push(0.5, 0.5); for (let i = 0; i <= t; i++) { const u = i / t * V * 2, h = Math.sin(u), _ = -Math.cos(u), l = H([ _ * o.normal[0] + h * o.binormal[0], _ * o.normal[1] + h * o.binormal[1], _ * o.normal[2] + h * o.binormal[2] ]); if (d.push( o.position[0] + o.radius * l[0], o.position[1] + o.radius * l[1], o.position[2] + o.radius * l[2] ), a++, v && v.push(...b), g) { const f = [(_ + 1) / 2, (h + 1) / 2]; s && (f[0] = 1 - f[0]), g.push(...f); } } for (let i = 1; i <= t; i++) { let h, _; s ? (h = i + 0, _ = i + 0 + 1) : (h = i + 0 + 1, _ = i + 0), r.push(h + e, _ + e, 0 + e), c += 3; } return { vertices: d, indices: r, normals: v, uvs: g, vertexCount: a, indexCount: c }; } function J(o, t, s, n = !0, e, a = 0) { let c = 0, d = 0; const r = [], v = [], g = e.computeNormals ? [] : null, b = e.computeUvs ? [] : null, i = n ? [-o.tangent[0], -o.tangent[1], -o.tangent[2]] : o.tangent, u = t.radius / o.radius; for (let h = 0; h <= s; h++) { const _ = h / s * V * 2, l = Math.sin(_), f = -Math.cos(_), m = H([ f * o.normal[0] + l * o.binormal[0], f * o.normal[1] + l * o.binormal[1], f * o.normal[2] + l * o.binormal[2] ]); if (r.push( o.position[0] + o.radius * m[0], o.position[1] + o.radius * m[1], o.position[2] + o.radius * m[2] ), c++, r.push( t.position[0] + t.radius * m[0], t.position[1] + t.radius * m[1], t.position[2] + t.radius * m[2] ), c++, g && g.push(...i, ...i), b) { const q = [(f + 1) / 2, (l + 1) / 2], w = [(f * u + 1) / 2, (l * u + 1) / 2]; n && (q[0] = 1 - q[0], w[0] = 1 - w[0]), b.push(...q, ...w); } } for (let h = 0; h < s; h++) { const _ = h * 2, l = _ + 1, f = _ + 2, m = _ + 3; n ? v.push( _ + a, f + a, l + a, l + a, f + a, m + a ) : v.push( f + a, _ + a, l + a, l + a, m + a, f + a ), d += 6; } return { vertices: r, indices: v, normals: g, uvs: b, vertexCount: c, indexCount: d }; } function K(o, t, s, n, e = 0) { let a = 0, c = 0; const d = [], r = [], v = n.computeNormals ? [] : null, g = n.computeUvs ? [] : null, b = (i) => { for (let u = 0; u <= t; u++) { const h = u / t * V * 2, _ = Math.sin(h), l = -Math.cos(h), f = H([ l * i.normal[0] + _ * i.binormal[0], l * i.normal[1] + _ * i.binormal[1], l * i.normal[2] + _ * i.binormal[2] ]), m = [ i.position[0] + i.radius * f[0], i.position[1] + i.radius * f[1], i.position[2] + i.radius * f[2] ]; if (v) { let q = nt(f); if (i.theta) { const w = H(et(i.tangent, f)); q = it(f, w, i.theta); } v.push(...q); } d.push(...m), a++; } }; for (let i = 0; i < o.length; i++) b(o[i]); if (s && b(o[0]), g) for (let i = 0; i < o.length; i++) for (let u = 0; u <= t; u++) g.push( u / t, i / (o.length - 1) ); for (let i = 1; i < o.length; i++) for (let u = 1; u <= t; u++) { const h = (t + 1) * (i - 1) + (u - 1), _ = (t + 1) * i + (u - 1), l = (t + 1) * i + u, f = (t + 1) * (i - 1) + u; r.push(h + e, _ + e, f + e), r.push(_ + e, l + e, f + e), c += 6; } return { vertices: d, indices: r, normals: v, uvs: g, vertexCount: a, indexCount: c }; } function ft(o, t = {}) { var B, I; const s = x(t.from || 0, 0, 1), n = x(t.to || 1); if (n < s) throw Error('Value of "from" must be less than the value of "to"!'); const e = new O(), a = t.radius || 1, c = ((B = t.radiusModifier) == null ? void 0 : B.steps) || [], d = t.radialSegments || 8, r = t.startCap || !1, v = t.endCap || !1, g = o.closed; c.sort((p, M) => p[0] - M[0]); const b = t.segmentsPerMeter || 0.1, i = ((I = t.radiusModifier) == null ? void 0 : I.type) || "none", u = x(t.simplificationThreshold || 0, 0, 1), h = at(o, i, s, n, a, c, b, u), _ = K(h, d, g, t); let l = null, f = null, m = null, q = _.vertexCount, w = 0; t.addGroups && (e.addGroup(w, _.indexCount, e.groups.length), w += _.indexCount); let C = null; (t.innerRadius || t.thickness) && (C = h.map((p) => ({ ...p, radius: t.innerRadius || p.radius - t.thickness, theta: p.theta - V })), l = K(C, d, g, t, q), q += l.vertexCount, t.addGroups && (e.addGroup(w, l.indexCount, e.groups.length), w += l.indexCount)), r && (!g || s > 0 || n < 1) && (C ? f = J(h[0], C[0], d, !0, t, q) : f = Y(h[0], d, !0, t, q), q += f.vertexCount, t.addGroups && (e.addGroup(w, f.indexCount, e.groups.length), w += f.indexCount)), v && (!g || s > 0 || n < 1) && (C ? m = J(h[h.length - 1], C[C.length - 1], d, !1, t, q) : m = Y(h[h.length - 1], d, !1, t, q), q += m.vertexCount, t.addGroups && (e.addGroup(w, m.indexCount, e.groups.length), w += m.indexCount)); let T = _.vertices, F = _.indices; if (l && (T = T.concat(l.vertices), F = F.concat(l.indices.reverse())), f && (T = T.concat(f.vertices), F = F.concat(f.indices)), m && (T = T.concat(m.vertices), F = F.concat(m.indices)), e.setAttribute("position", new j(Float32Array.from(T), 3)), t.computeNormals) { let p = _.normals; l && (p = p.concat(l.normals)), f && (p = p.concat(f.normals)), m && (p = p.concat(m.normals)), e.setAttribute("normal", new j(Float32Array.from(p), 3)); } if (t.computeLengths || t.computeCurveNormals || t.computeCurveTangents || t.computeCurveBinormals || t.computeRelativeLengths) { const p = t.computeLengths ? [] : null, M = t.computeRelativeLengths ? [] : null, R = t.computeCurveNormals ? [] : null, z = t.computeCurveTangents ? [] : null, P = t.computeCurveBinormals ? [] : null, G = o.length; for (let A = 0; A < h.length; A++) for (let N = 0; N <= d; N++) p && p.push(h[A].curvePosition * G), M && M.push((h[A].curvePosition - s) * G), R && R.push(...h[A].normal), z && z.push(...h[A].tangent), P && P.push(...h[A].binormal); if (l && C) for (let A = 0; A < C.length; A++) for (let N = 0; N <= d; N++) p && p.push(C[A].curvePosition * G), M && M.push((h[A].curvePosition - s) * G), R && R.push(...C[A].normal), z && z.push(...C[A].tangent), P && P.push(...C[A].binormal); if (f) for (let A = 0; A < f.vertexCount; A++) p && p.push(s * G), M && M.push(0), R && R.push(...h[0].normal), z && z.push(...h[0].tangent), P && P.push(...h[0].binormal); if (m) for (let A = 0; A < m.vertexCount; A++) p && p.push(n * G), M && M.push(G), R && R.push(...h[h.length - 1].normal), z && z.push(...h[h.length - 1].tangent), P && P.push(...h[h.length - 1].binormal); p && e.setAttribute("curveLength", new j(Float32Array.from(p), 1)), M && e.setAttribute("curveRelativeLength", new j(Float32Array.from(M), 1)), R && e.setAttribute("curveNormal", new j(Float32Array.from(R), 3)), z && e.setAttribute("curveTangent", new j(Float32Array.from(z), 3)), P && e.setAttribute("curveBinormal", new j(Float32Array.from(P), 3)); } if (t.computeUvs) { let p = _.uvs; l && (p = p.concat(l.uvs)), f && (p = p.concat(f.uvs)), m && (p = p.concat(m.uvs)), e.setAttribute("uv", new j(Float32Array.from(p), 2)); } return e.setIndex(new j(Uint32Array.from(F), 1)), e; } const Q = -1e3; class rt { constructor(t, s, n = -1) { L(this, "data"); L(this, "width"); L(this, "height"); L(this, "coords", []); // vertex coordinates (x, y) L(this, "triangles", []); // mesh triangle indices L(this, "nullValue"); L(this, "_queue", []); L(this, "_queueIndices", []); L(this, "_errors", []); L(this, "_halfedges", []); L(this, "_candidates", []); L(this, "_invalidPoints"); L(this, "_rms", []); L(this, "_pending", []); L(this, "_pendingLen", 0); L(this, "_rmsSum", 0); this.data = t, this.width = s, this.height = this.data.length / s, this.nullValue = n, this._invalidPoints = /* @__PURE__ */ new Set(); const e = this.width - 1, a = this.height - 1, c = this._addPoint(0, 0), d = this._addPoint(e, 0), r = this._addPoint(0, a), v = this._addPoint(e, a), g = this._addTriangle(v, c, r, -1, -1, -1); this._addTriangle(c, v, d, g, -1, -1), this._flush(); } // refine the mesh until its maximum error gets below the given one run(t = 1) { for (; this.getMaxError() > t; ) this.refine(); } // Removes triangles where one or more vertices contains a null value (nullValue) removeInvalidTriangles() { const t = []; for (let s = 0; s < this.triangles.length; s += 3) { const n = this.triangles[s], e = this.triangles[s + 1], a = this.triangles[s + 2]; !this._invalidPoints.has(n) && !this._invalidPoints.has(e) && !this._invalidPoints.has(a) && t.push( this.triangles[s], this.triangles[s + 1], this.triangles[s + 2] ); } this.triangles = t; } // refine the mesh with a single point refine() { this._step(), this._flush(); } // max error of the current mesh getMaxError() { return this._errors[0]; } // root-mean-square deviation of the current mesh getRMSD() { return this._rmsSum > 0 ? Math.sqrt(this._rmsSum / (this.width * this.height)) : 0; } // height value at a given position heightAt(t, s) { const n = this.data[this.width * s + t]; return n === this.nullValue ? Q : n; } // rasterize a triangle, find its max error, and queue it for processing _findCandidate(t, s, n, e, a, c, d) { const r = Math.min(t, n, a), v = Math.min(s, e, c), g = Math.max(t, n, a), b = Math.max(s, e, c); let i = U(n, e, a, c, r, v), u = U(a, c, t, s, r, v), h = U(t, s, n, e, r, v); const _ = e - s, l = t - n, f = c - e, m = n - a, q = s - c, w = a - t, C = U(t, s, n, e, a, c), T = this.heightAt(t, s) / C, F = this.heightAt(n, e) / C, B = this.heightAt(a, c) / C; let I = 0, p = 0, M = 0, R = 0; for (let z = v; z <= b; z++) { let P = 0; i < 0 && f !== 0 && (P = Math.max(P, Math.floor(-i / f))), u < 0 && q !== 0 && (P = Math.max(P, Math.floor(-u / q))), h < 0 && _ !== 0 && (P = Math.max(P, Math.floor(-h / _))); let G = i + f * P, A = u + q * P, N = h + _ * P, X = !1; for (let k = r + P; k <= g; k++) { if (G >= 0 && A >= 0 && N >= 0) { X = !0; const W = T * G + F * A + B * N, Z = this.heightAt(k, z), D = Math.abs(W - Z); R += D * D, D > I && (I = D, p = k, M = z); } else if (X) break; G += f, A += q, N += _; } i += m, u += w, h += l; } (p === t && M === s || p === n && M === e || p === a && M === c) && (I = 0), this._candidates[2 * d] = p, this._candidates[2 * d + 1] = M, this._rms[d] = R, this._queuePush(d, I, R); } // process the next triangle in the queue, splitting it with a new point _step() { const t = this._queuePop(), s = t * 3 + 0, n = t * 3 + 1, e = t * 3 + 2, a = this.triangles[s], c = this.triangles[n], d = this.triangles[e], r = this.coords[2 * a], v = this.coords[2 * a + 1], g = this.coords[2 * c], b = this.coords[2 * c + 1], i = this.coords[2 * d], u = this.coords[2 * d + 1], h = this._candidates[2 * t], _ = this._candidates[2 * t + 1], l = this._addPoint(h, _); if (U(r, v, g, b, h, _) === 0) this._handleCollinear(l, s); else if (U(g, b, i, u, h, _) === 0) this._handleCollinear(l, n); else if (U(i, u, r, v, h, _) === 0) this._handleCollinear(l, e); else { const f = this._halfedges[s], m = this._halfedges[n], q = this._halfedges[e], w = this._addTriangle(a, c, l, f, -1, -1, s), C = this._addTriangle(c, d, l, m, -1, w + 1), T = this._addTriangle(d, a, l, q, w + 2, C + 1); this._legalize(w), this._legalize(C), this._legalize(T); } } _addPoint(t, s) { const n = this.coords.length >> 1; return this.coords.push(t, s), this.heightAt(t, s) === Q && this._invalidPoints.add(n), n; } _addTriangle(t, s, n, e, a, c, d = this.triangles.length) { const r = d / 3; return this.triangles[d + 0] = t, this.triangles[d + 1] = s, this.triangles[d + 2] = n, this._halfedges[d + 0] = e, this._halfedges[d + 1] = a, this._halfedges[d + 2] = c, e >= 0 && (this._halfedges[e] = d + 0), a >= 0 && (this._halfedges[a] = d + 1), c >= 0 && (this._halfedges[c] = d + 2), this._candidates[2 * r + 0] = 0, this._candidates[2 * r + 1] = 0, this._queueIndices[r] = -1, this._rms[r] = 0, this._pending[this._pendingLen++] = r, d; } _flush() { const t = this.coords; for (let s = 0; s < this._pendingLen; s++) { const n = this._pending[s], e = 2 * this.triangles[n * 3 + 0], a = 2 * this.triangles[n * 3 + 1], c = 2 * this.triangles[n * 3 + 2]; this._findCandidate( t[e], t[e + 1], t[a], t[a + 1], t[c], t[c + 1], n ); } this._pendingLen = 0; } _legalize(t) { const s = this._halfedges[t]; if (s < 0) return; const n = t - t % 3, e = s - s % 3, a = n + (t + 1) % 3, c = n + (t + 2) % 3, d = e + (s + 2) % 3, r = e + (s + 1) % 3, v = this.triangles[c], g = this.triangles[t], b = this.triangles[a], i = this.triangles[d], u = this.coords; if (!ht( u[2 * v], u[2 * v + 1], u[2 * g], u[2 * g + 1], u[2 * b], u[2 * b + 1], u[2 * i], u[2 * i + 1] )) return; const h = this._halfedges[a], _ = this._halfedges[c], l = this._halfedges[d], f = this._halfedges[r]; this._queueRemove(n / 3), this._queueRemove(e / 3); const m = this._addTriangle(v, i, b, -1, l, h, n), q = this._addTriangle(i, v, g, m, _, f, e); this._legalize(m + 1), this._legalize(q + 2); } _handleCollinear(t, s) { const n = s - s % 3, e = n + (s + 1) % 3, a = n + (s + 2) % 3, c = this.triangles[a], d = this.triangles[s], r = this.triangles[e], v = this._halfedges[e], g = this._halfedges[a], b = this._halfedges[s]; if (b < 0) { const T = this._addTriangle(t, c, d, -1, g, -1, n), F = this._addTriangle(c, t, r, T, -1, v); this._legalize(T + 1), this._legalize(F + 2); return; } const i = b - b % 3, u = i + (b + 2) % 3, h = i + (b + 1) % 3, _ = this.triangles[u], l = this._halfedges[u], f = this._halfedges[h]; this._queueRemove(i / 3); const m = this._addTriangle(c, d, t, g, -1, -1, n), q = this._addTriangle(d, _, t, f, -1, m + 1, i), w = this._addTriangle(_, r, t, l, -1, q + 1), C = this._addTriangle(r, c, t, v, m + 2, w + 1); this._legalize(m), this._legalize(q), this._legalize(w), this._legalize(C); } // priority queue methods _queuePush(t, s, n) { const e = this._queue.length; this._queueIndices[t] = e, this._queue.push(t), this._errors.push(s), this._rmsSum += n, this._queueUp(e); } _queuePop() { const t = this._queue.length - 1; return this._queueSwap(0, t), this._queueDown(0, t), this._queuePopBack(); } _queuePopBack() { const t = this._queue.pop(); return this._errors.pop(), this._rmsSum -= this._rms[t], this._queueIndices[t] = -1, t; } _queueRemove(t) { const s = this._queueIndices[t]; if (s < 0) { const e = this._pending.indexOf(t); if (e !== -1) this._pending[e] = this._pending[--this._pendingLen]; else throw new Error("Broken triangulation (something went wrong)."); return; } const n = this._queue.length - 1; n !== s && (this._queueSwap(s, n), this._queueDown(s, n) || this._queueUp(s)), this._queuePopBack(); } _queueLess(t, s) { return this._errors[t] > this._errors[s]; } _queueSwap(t, s) { const n = this._queue[t], e = this._queue[s]; this._queue[t] = e, this._queue[s] = n, this._queueIndices[n] = s, this._queueIndices[e] = t; const a = this._errors[t]; this._errors[t] = this._errors[s], this._errors[s] = a; } _queueUp(t) { let s = t; for (; ; ) { const n = s - 1 >> 1; if (n === s || !this._queueLess(s, n)) break; this._queueSwap(n, s), s = n; } } _queueDown(t, s) { let n = t; for (; ; ) { const e = 2 * n + 1; if (e >= s || e < 0) break; const a = e + 1; let c = e; if (a < s && this._queueLess(a, e) && (c = a), !this._queueLess(c, n)) break; this._queueSwap(n, c), n = c; } return n > t; } } function U(o, t, s, n, e, a) { return (s - e) * (t - a) - (n - a) * (o - e); } function ht(o, t, s, n, e, a, c, d) { const r = o - c, v = t - d, g = s - c, b = n - d, i = e - c, u = a - d, h = r * r + v * v, _ = g * g + b * b, l = i * i + u * u; return r * (b * l - _ * u) - v * (g * l - _ * i) + h * (g * u - b * i) < 0; } function _t(o, t, s = 1, n = 1, e = -1, a = 5) { const c = t, d = o.length / c; console.time("delatin"); const r = new rt(o, c, e); r.run(a), r.removeInvalidTriangles(), console.timeEnd("delatin"); const v = new Float32Array(r.coords.length * 1.5), g = new Float32Array(r.coords.length); for (let i = 0, u = 0; i < r.coords.length; i += 2) g[i] = r.coords[i] / (c - 1), g[i + 1] = 1 - r.coords[i + 1] / (d - 1), u = i * 1.5, v[u] = r.coords[i] * s, v[u + 1] = r.heightAt(r.coords[i], r.coords[i + 1]), v[u + 2] = r.coords[i + 1] * n; const b = new Uint32Array(r.triangles); return console.log(r.triangles.length / 3), { positions: v, uvs: g, indices: b }; } function gt(o) { return o / 3.28084; } function vt(o) { return o * (Math.PI / 180); } function pt(o) { let t = 0, s, n; if (!o || o.length === 0) return t; for (s = 0; s < o.length; s++) n = o.charCodeAt(s), t = (t << 5) - t + n, t |= 0; return t; } function mt(o) { return o.replace(/(^|\s)\S/g, (t) => t.toUpperCase()); } export { rt as D, pt as a, mt as b, ft as c, vt as d, gt as f, _t as t };