UNPKG

mind-ar

Version:

web augmented reality framework

122 lines (121 loc) 6.3 kB
import { Scene as m, WebGLRenderer as w, sRGBEncoding as y, PerspectiveCamera as g, Mesh as M, MeshStandardMaterial as x, Group as p, BufferGeometry as A, BufferAttribute as R } from "three"; import { CSS3DRenderer as S } from "three/addons/renderers/CSS3DRenderer.js"; import { C as b } from "./controller-212bb69c.js"; import { U as E } from "./ui-56ede774.js"; const C = { BufferGeometry: A, BufferAttribute: R }; class U { constructor({ container: o, uiLoading: e = "yes", uiScanning: i = "yes", uiError: n = "yes", filterMinCF: t = null, filterBeta: h = null }) { this.container = o, this.ui = new E({ uiLoading: e, uiScanning: i, uiError: n }), this.controller = new b({ filterMinCF: t, filterBeta: h }), this.scene = new m(), this.cssScene = new m(), this.renderer = new w({ antialias: !0, alpha: !0 }), this.cssRenderer = new S({ antialias: !0 }), this.renderer.outputEncoding = y, this.renderer.setPixelRatio(window.devicePixelRatio), this.camera = new g(), this.anchors = [], this.faceMeshes = [], this.container.appendChild(this.renderer.domElement), this.container.appendChild(this.cssRenderer.domElement), this.shouldFaceUser = !0, window.addEventListener("resize", this._resize.bind(this)); } async start() { this.ui.showLoading(), await this._startVideo(), await this._startAR(), this.ui.hideLoading(); } stop() { this.video.srcObject.getTracks().forEach(function(e) { e.stop(); }), this.video.remove(), this.controller.stopProcessVideo(); } switchCamera() { this.shouldFaceUser = !this.shouldFaceUser, this.stop(), this.start(); } addFaceMesh() { const o = this.controller.createThreeFaceGeometry(C), e = new M(o, new x({ color: 16777215 })); return e.visible = !1, e.matrixAutoUpdate = !1, this.faceMeshes.push(e), e; } addAnchor(o) { const e = new p(); e.matrixAutoUpdate = !1; const i = { group: e, landmarkIndex: o, css: !1 }; return this.anchors.push(i), this.scene.add(e), i; } addCSSAnchor(o) { const e = new p(); e.matrixAutoUpdate = !1; const i = { group: e, landmarkIndex: o, css: !0 }; return this.anchors.push(i), this.cssScene.add(e), i; } _startVideo() { return new Promise((o, e) => { if (this.video = document.createElement("video"), this.video.setAttribute("autoplay", ""), this.video.setAttribute("muted", ""), this.video.setAttribute("playsinline", ""), this.video.style.position = "absolute", this.video.style.top = "0px", this.video.style.left = "0px", this.video.style.zIndex = "-2", this.container.appendChild(this.video), !navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) { this.ui.showCompatibility(), e(); return; } navigator.mediaDevices.getUserMedia({ audio: !1, video: { facingMode: this.shouldFaceUser ? "face" : "environment" } }).then((i) => { this.video.addEventListener("loadedmetadata", () => { this.video.setAttribute("width", this.video.videoWidth), this.video.setAttribute("height", this.video.videoHeight), o(); }), this.video.srcObject = i; }).catch((i) => { console.log("getUserMedia error", i), e(); }); }); } _startAR() { return new Promise(async (o, e) => { const i = this.video; this.container, this.controller.onUpdate = ({ hasFace: l, estimateResult: f }) => { for (let r = 0; r < this.anchors.length; r++) this.anchors[r].css ? this.anchors[r].group.children.forEach((a) => { a.element.style.visibility = l ? "visible" : "hidden"; }) : this.anchors[r].group.visible = l; for (let r = 0; r < this.faceMeshes.length; r++) this.faceMeshes[r].visible = l; if (l) { const { metricLandmarks: r, faceMatrix: a, faceScale: F } = f; for (let c = 0; c < this.anchors.length; c++) { const u = this.anchors[c].landmarkIndex, s = this.controller.getLandmarkMatrix(u); if (this.anchors[c].css) { const v = [ 1e-3 * s[0], 1e-3 * s[1], s[2], s[3], 1e-3 * s[4], 1e-3 * s[5], s[6], s[7], 1e-3 * s[8], 1e-3 * s[9], s[10], s[11], 1e-3 * s[12], 1e-3 * s[13], s[14], s[15] ]; this.anchors[c].group.matrix.set(...v); } else this.anchors[c].group.matrix.set(...s); } for (let c = 0; c < this.faceMeshes.length; c++) this.faceMeshes[c].matrix.set(...a); } }, this._resize(), await this.controller.setup(i); const { fov: n, aspect: t, near: h, far: d } = this.controller.getCameraParams(); this.camera.fov = n, this.camera.aspect = t, this.camera.near = h, this.camera.far = d, this.camera.updateProjectionMatrix(), this.renderer.setSize(this.video.videoWidth, this.video.videoHeight), this.cssRenderer.setSize(this.video.videoWidth, this.video.videoHeight), await this.controller.dummyRun(i), this._resize(), this.controller.processVideo(i), o(); }); } _resize() { const { renderer: o, cssRenderer: e, camera: i, container: n, video: t } = this; if (!t) return; let h, d; const l = t.videoWidth / t.videoHeight, f = n.clientWidth / n.clientHeight; l > f ? (d = n.clientHeight, h = d * l) : (h = n.clientWidth, d = h / l), t.style.top = -(d - n.clientHeight) / 2 + "px", t.style.left = -(h - n.clientWidth) / 2 + "px", t.style.width = h + "px", t.style.height = d + "px"; const r = o.domElement, a = e.domElement; r.style.position = "absolute", r.style.top = t.style.top, r.style.left = t.style.left, r.style.width = t.style.width, r.style.height = t.style.height, a.style.position = "absolute", a.style.top = t.style.top, a.style.left = t.style.left, a.style.transformOrigin = "top left", a.style.transform = "scale(" + h / parseFloat(a.style.width) + "," + d / parseFloat(a.style.height) + ")"; } } window.MINDAR || (window.MINDAR = {}); window.MINDAR.FACE || (window.MINDAR.FACE = {}); window.MINDAR.FACE.MindARThree = U; export { U as MindARThree };