@srsergio/taptapp-ar 1.0.101 → 1.1.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/dist/compiler/node-worker.js +1 -197
- package/dist/compiler/offline-compiler.js +1 -207
- package/dist/core/constants.js +1 -38
- package/dist/core/detector/crop-detector.js +1 -88
- package/dist/core/detector/detector-lite.js +1 -455
- package/dist/core/detector/freak.js +1 -89
- package/dist/core/estimation/estimate.js +1 -16
- package/dist/core/estimation/estimator.js +1 -30
- package/dist/core/estimation/morph-refinement.js +1 -116
- package/dist/core/estimation/non-rigid-refine.js +1 -70
- package/dist/core/estimation/pnp-solver.js +1 -109
- package/dist/core/estimation/refine-estimate.js +1 -311
- package/dist/core/estimation/utils.js +1 -67
- package/dist/core/features/auto-rotation-feature.js +1 -30
- package/dist/core/features/crop-detection-feature.js +1 -26
- package/dist/core/features/feature-base.js +1 -1
- package/dist/core/features/feature-manager.js +1 -55
- package/dist/core/features/one-euro-filter-feature.js +1 -44
- package/dist/core/features/temporal-filter-feature.js +1 -57
- package/dist/core/image-list.js +1 -54
- package/dist/core/input-loader.js +1 -87
- package/dist/core/matching/hamming-distance.js +1 -66
- package/dist/core/matching/hdc.js +1 -102
- package/dist/core/matching/hierarchical-clustering.js +1 -130
- package/dist/core/matching/hough.js +1 -170
- package/dist/core/matching/matcher.js +1 -66
- package/dist/core/matching/matching.js +1 -401
- package/dist/core/matching/ransacHomography.js +1 -132
- package/dist/core/perception/bio-inspired-engine.js +1 -232
- package/dist/core/perception/foveal-attention.js +1 -280
- package/dist/core/perception/index.js +1 -17
- package/dist/core/perception/predictive-coding.js +1 -278
- package/dist/core/perception/saccadic-controller.js +1 -269
- package/dist/core/perception/saliency-map.js +1 -254
- package/dist/core/perception/scale-orchestrator.js +1 -68
- package/dist/core/protocol.js +1 -254
- package/dist/core/tracker/extract-utils.js +1 -29
- package/dist/core/tracker/extract.js +1 -306
- package/dist/core/tracker/tracker.js +1 -352
- package/dist/core/utils/cumsum.js +1 -37
- package/dist/core/utils/delaunay.js +1 -125
- package/dist/core/utils/geometry.js +1 -101
- package/dist/core/utils/gpu-compute.js +1 -231
- package/dist/core/utils/homography.js +1 -138
- package/dist/core/utils/images.js +1 -108
- package/dist/core/utils/lsh-binarizer.js +1 -37
- package/dist/core/utils/lsh-direct.js +1 -76
- package/dist/core/utils/projection.js +1 -51
- package/dist/core/utils/randomizer.js +1 -25
- package/dist/core/utils/worker-pool.js +1 -89
- package/dist/index.js +1 -7
- package/dist/libs/one-euro-filter.js +1 -70
- package/dist/react/TaptappAR.js +1 -151
- package/dist/react/types.js +1 -16
- package/dist/react/use-ar.js +1 -118
- package/dist/runtime/aframe.js +1 -272
- package/dist/runtime/bio-inspired-controller.js +1 -358
- package/dist/runtime/controller.js +1 -592
- package/dist/runtime/controller.worker.js +1 -93
- package/dist/runtime/index.js +1 -5
- package/dist/runtime/three.js +1 -304
- package/dist/runtime/track.js +1 -381
- package/package.json +9 -3
|
@@ -1,93 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Estimator } from "../core/estimation/estimator.js";
|
|
3
|
-
import { Tracker } from "../core/tracker/tracker.js";
|
|
4
|
-
import { DetectorLite } from "../core/detector/detector-lite.js";
|
|
5
|
-
let matchingDataList = null;
|
|
6
|
-
let debugMode = false;
|
|
7
|
-
let matcher = null;
|
|
8
|
-
let estimator = null;
|
|
9
|
-
let tracker = null;
|
|
10
|
-
let detector = null;
|
|
11
|
-
onmessage = (msg) => {
|
|
12
|
-
const { data } = msg;
|
|
13
|
-
switch (data.type) {
|
|
14
|
-
case "setup":
|
|
15
|
-
matchingDataList = data.matchingDataList;
|
|
16
|
-
debugMode = data.debugMode;
|
|
17
|
-
matcher = new Matcher(data.inputWidth, data.inputHeight, debugMode);
|
|
18
|
-
estimator = new Estimator(data.projectionTransform);
|
|
19
|
-
if (data.trackingDataList && data.markerDimensions) {
|
|
20
|
-
tracker = new Tracker(data.markerDimensions, data.trackingDataList, data.projectionTransform, data.inputWidth, data.inputHeight, debugMode);
|
|
21
|
-
}
|
|
22
|
-
detector = new DetectorLite(data.inputWidth, data.inputHeight, {
|
|
23
|
-
useLSH: true,
|
|
24
|
-
maxFeaturesPerBucket: 24
|
|
25
|
-
});
|
|
26
|
-
break;
|
|
27
|
-
case "match":
|
|
28
|
-
const interestedTargetIndexes = data.targetIndexes;
|
|
29
|
-
let matchedTargetIndex = -1;
|
|
30
|
-
let matchedModelViewTransform = null;
|
|
31
|
-
let matchedScreenCoords = null;
|
|
32
|
-
let matchedWorldCoords = null;
|
|
33
|
-
let matchedDebugExtra = null;
|
|
34
|
-
// New: If the worker received image data, run detector here too
|
|
35
|
-
let featurePoints = data.featurePoints;
|
|
36
|
-
if (data.inputData) {
|
|
37
|
-
const detectionResult = detector.detect(data.inputData, { octavesToProcess: data.octavesToProcess });
|
|
38
|
-
featurePoints = detectionResult.featurePoints;
|
|
39
|
-
}
|
|
40
|
-
for (let i = 0; i < interestedTargetIndexes.length; i++) {
|
|
41
|
-
const matchingIndex = interestedTargetIndexes[i];
|
|
42
|
-
const { keyframeIndex, screenCoords, worldCoords, debugExtra } = matcher.matchDetection(matchingDataList[matchingIndex], featurePoints, data.expectedScale);
|
|
43
|
-
matchedDebugExtra = debugExtra;
|
|
44
|
-
if (keyframeIndex !== -1) {
|
|
45
|
-
const modelViewTransform = estimator.estimate({ screenCoords, worldCoords });
|
|
46
|
-
if (modelViewTransform) {
|
|
47
|
-
matchedTargetIndex = matchingIndex;
|
|
48
|
-
matchedModelViewTransform = modelViewTransform;
|
|
49
|
-
matchedScreenCoords = screenCoords;
|
|
50
|
-
matchedWorldCoords = worldCoords;
|
|
51
|
-
}
|
|
52
|
-
break;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
postMessage({
|
|
56
|
-
type: "matchDone",
|
|
57
|
-
targetIndex: matchedTargetIndex,
|
|
58
|
-
modelViewTransform: matchedModelViewTransform,
|
|
59
|
-
screenCoords: matchedScreenCoords,
|
|
60
|
-
worldCoords: matchedWorldCoords,
|
|
61
|
-
featurePoints: featurePoints,
|
|
62
|
-
debugExtra: matchedDebugExtra,
|
|
63
|
-
});
|
|
64
|
-
break;
|
|
65
|
-
case "track":
|
|
66
|
-
const { inputData: trackInput, lastModelViewTransform, targetIndex } = data;
|
|
67
|
-
const trackResult = tracker.track(trackInput, lastModelViewTransform, targetIndex);
|
|
68
|
-
postMessage({
|
|
69
|
-
type: "trackDone",
|
|
70
|
-
targetIndex,
|
|
71
|
-
...trackResult
|
|
72
|
-
});
|
|
73
|
-
break;
|
|
74
|
-
case "trackUpdate":
|
|
75
|
-
const { modelViewTransform, worldCoords, screenCoords, stabilities } = data;
|
|
76
|
-
const finalModelViewTransform = estimator.refineEstimate({
|
|
77
|
-
initialModelViewTransform: modelViewTransform,
|
|
78
|
-
worldCoords,
|
|
79
|
-
screenCoords,
|
|
80
|
-
stabilities, // Stability-based weights
|
|
81
|
-
});
|
|
82
|
-
postMessage({
|
|
83
|
-
type: "trackUpdateDone",
|
|
84
|
-
modelViewTransform: finalModelViewTransform,
|
|
85
|
-
});
|
|
86
|
-
break;
|
|
87
|
-
case "dispose":
|
|
88
|
-
close();
|
|
89
|
-
break;
|
|
90
|
-
default:
|
|
91
|
-
throw new Error(`Invalid message type '${data.type}'`);
|
|
92
|
-
}
|
|
93
|
-
};
|
|
1
|
+
import{Matcher as e}from"../core/matching/matcher.js";import{Estimator as t}from"../core/estimation/estimator.js";import{Tracker as r}from"../core/tracker/tracker.js";import{DetectorLite as o}from"../core/detector/detector-lite.js";let s=null,a=!1,n=null,i=null,c=null,d=null;onmessage=l=>{const{data:m}=l;switch(m.type){case"setup":s=m.matchingDataList,a=m.debugMode,n=new e(m.inputWidth,m.inputHeight,a),i=new t(m.projectionTransform),m.trackingDataList&&m.markerDimensions&&(c=new r(m.markerDimensions,m.trackingDataList,m.projectionTransform,m.inputWidth,m.inputHeight,a)),d=new o(m.inputWidth,m.inputHeight,{useLSH:!0,maxFeaturesPerBucket:24});break;case"match":const l=m.targetIndexes;let p=-1,u=null,g=null,f=null,k=null,w=m.featurePoints;m.inputData&&(w=d.detect(m.inputData,{octavesToProcess:m.octavesToProcess}).featurePoints);for(let e=0;e<l.length;e++){const t=l[e],{keyframeIndex:r,screenCoords:o,worldCoords:a,debugExtra:c}=n.matchDetection(s[t],w,m.expectedScale);if(k=c,-1!==r){const e=i.estimate({screenCoords:o,worldCoords:a});e&&(p=t,u=e,g=o,f=a);break}}postMessage({type:"matchDone",targetIndex:p,modelViewTransform:u,screenCoords:g,worldCoords:f,featurePoints:w,debugExtra:k});break;case"track":const{inputData:h,lastModelViewTransform:D,targetIndex:b}=m,C=c.track(h,D,b);postMessage({type:"trackDone",targetIndex:b,...C});break;case"trackUpdate":const{modelViewTransform:x,worldCoords:T,screenCoords:y,stabilities:j}=m,I=i.refineEstimate({initialModelViewTransform:x,worldCoords:T,screenCoords:y,stabilities:j});postMessage({type:"trackUpdateDone",modelViewTransform:I});break;case"dispose":close();break;default:throw new Error(`Invalid message type '${m.type}'`)}};
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,5 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from "./bio-inspired-controller.js";
|
|
3
|
-
export * from "./track.js";
|
|
4
|
-
export * from "./three.js";
|
|
5
|
-
export * from "./aframe.js";
|
|
1
|
+
export*from"./controller.js";export*from"./bio-inspired-controller.js";export*from"./track.js";export*from"./three.js";export*from"./aframe.js";
|
package/dist/runtime/three.js
CHANGED
|
@@ -1,304 +1 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CSS3DRenderer } from "three/addons/renderers/CSS3DRenderer.js";
|
|
3
|
-
import { Controller } from "./controller.js";
|
|
4
|
-
import { UI } from "../ui/ui.js";
|
|
5
|
-
const cssScaleDownMatrix = new Matrix4();
|
|
6
|
-
cssScaleDownMatrix.compose(new Vector3(), new Quaternion(), new Vector3(0.001, 0.001, 0.001));
|
|
7
|
-
const invisibleMatrix = new Matrix4().set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
|
8
|
-
export class TaarThree {
|
|
9
|
-
constructor({ container, imageTargetSrc, maxTrack, uiLoading = "yes", uiScanning = "yes", uiError = "yes", filterMinCF = null, filterBeta = null, warmupTolerance = null, missTolerance = null, userDeviceId = null, environmentDeviceId = null, }) {
|
|
10
|
-
this.container = container;
|
|
11
|
-
this.imageTargetSrc = imageTargetSrc;
|
|
12
|
-
this.maxTrack = maxTrack;
|
|
13
|
-
this.filterMinCF = filterMinCF;
|
|
14
|
-
this.filterBeta = filterBeta;
|
|
15
|
-
this.warmupTolerance = warmupTolerance;
|
|
16
|
-
this.missTolerance = missTolerance;
|
|
17
|
-
this.ui = new UI({ uiLoading, uiScanning, uiError });
|
|
18
|
-
this.userDeviceId = userDeviceId;
|
|
19
|
-
this.environmentDeviceId = environmentDeviceId;
|
|
20
|
-
this.shouldFaceUser = false;
|
|
21
|
-
this.scene = new Scene();
|
|
22
|
-
this.cssScene = new Scene();
|
|
23
|
-
this.renderer = new WebGLRenderer({ antialias: true, alpha: true });
|
|
24
|
-
this.cssRenderer = new CSS3DRenderer({ antialias: true });
|
|
25
|
-
this.renderer.outputEncoding = sRGBEncoding;
|
|
26
|
-
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
27
|
-
this.camera = new PerspectiveCamera();
|
|
28
|
-
this.anchors = [];
|
|
29
|
-
this.renderer.domElement.style.position = "absolute";
|
|
30
|
-
this.cssRenderer.domElement.style.position = "absolute";
|
|
31
|
-
this.container.appendChild(this.renderer.domElement);
|
|
32
|
-
this.container.appendChild(this.cssRenderer.domElement);
|
|
33
|
-
window.addEventListener("resize", this.resize.bind(this));
|
|
34
|
-
}
|
|
35
|
-
async start() {
|
|
36
|
-
this.ui.showLoading();
|
|
37
|
-
await this._startVideo();
|
|
38
|
-
await this._startAR();
|
|
39
|
-
}
|
|
40
|
-
stop() {
|
|
41
|
-
this.controller.stopProcessVideo();
|
|
42
|
-
const tracks = this.video.srcObject.getTracks();
|
|
43
|
-
tracks.forEach(function (track) {
|
|
44
|
-
track.stop();
|
|
45
|
-
});
|
|
46
|
-
this.video.remove();
|
|
47
|
-
}
|
|
48
|
-
switchCamera() {
|
|
49
|
-
this.shouldFaceUser = !this.shouldFaceUser;
|
|
50
|
-
this.stop();
|
|
51
|
-
this.start();
|
|
52
|
-
}
|
|
53
|
-
addAnchor(targetIndex) {
|
|
54
|
-
const group = new Group();
|
|
55
|
-
group.visible = false;
|
|
56
|
-
group.matrixAutoUpdate = false;
|
|
57
|
-
const anchor = {
|
|
58
|
-
group,
|
|
59
|
-
targetIndex,
|
|
60
|
-
onTargetFound: null,
|
|
61
|
-
onTargetLost: null,
|
|
62
|
-
onTargetUpdate: null,
|
|
63
|
-
css: false,
|
|
64
|
-
visible: false,
|
|
65
|
-
};
|
|
66
|
-
this.anchors.push(anchor);
|
|
67
|
-
this.scene.add(group);
|
|
68
|
-
return anchor;
|
|
69
|
-
}
|
|
70
|
-
addCSSAnchor(targetIndex) {
|
|
71
|
-
const group = new Group();
|
|
72
|
-
group.visible = false;
|
|
73
|
-
group.matrixAutoUpdate = false;
|
|
74
|
-
const anchor = {
|
|
75
|
-
group,
|
|
76
|
-
targetIndex,
|
|
77
|
-
onTargetFound: null,
|
|
78
|
-
onTargetLost: null,
|
|
79
|
-
onTargetUpdate: null,
|
|
80
|
-
css: true,
|
|
81
|
-
visible: false,
|
|
82
|
-
};
|
|
83
|
-
this.anchors.push(anchor);
|
|
84
|
-
this.cssScene.add(group);
|
|
85
|
-
return anchor;
|
|
86
|
-
}
|
|
87
|
-
_startVideo() {
|
|
88
|
-
return new Promise((resolve) => {
|
|
89
|
-
this.video = document.createElement("video");
|
|
90
|
-
this.video.setAttribute("autoplay", "");
|
|
91
|
-
this.video.setAttribute("muted", "");
|
|
92
|
-
this.video.setAttribute("playsinline", "");
|
|
93
|
-
this.video.style.position = "absolute";
|
|
94
|
-
this.video.style.top = "0px";
|
|
95
|
-
this.video.style.left = "0px";
|
|
96
|
-
this.video.style.zIndex = "-2";
|
|
97
|
-
this.container.appendChild(this.video);
|
|
98
|
-
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
99
|
-
this.ui.showCompatibility();
|
|
100
|
-
reject();
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const constraints = {
|
|
104
|
-
audio: false,
|
|
105
|
-
video: {},
|
|
106
|
-
};
|
|
107
|
-
if (this.shouldFaceUser) {
|
|
108
|
-
if (this.userDeviceId) {
|
|
109
|
-
constraints.video.deviceId = { exact: this.userDeviceId };
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
constraints.video.facingMode = "user";
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
if (this.environmentDeviceId) {
|
|
117
|
-
constraints.video.deviceId = { exact: this.environmentDeviceId };
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
constraints.video.facingMode = "environment";
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
navigator.mediaDevices
|
|
124
|
-
.getUserMedia(constraints)
|
|
125
|
-
.then((stream) => {
|
|
126
|
-
this.video.addEventListener("loadedmetadata", () => {
|
|
127
|
-
this.video.setAttribute("width", this.video.videoWidth);
|
|
128
|
-
this.video.setAttribute("height", this.video.videoHeight);
|
|
129
|
-
resolve();
|
|
130
|
-
});
|
|
131
|
-
this.video.srcObject = stream;
|
|
132
|
-
})
|
|
133
|
-
.catch((err) => {
|
|
134
|
-
console.log("getUserMedia error", err);
|
|
135
|
-
reject();
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
_startAR() {
|
|
140
|
-
return new Promise(async (resolve) => {
|
|
141
|
-
const video = this.video;
|
|
142
|
-
this.controller = new Controller({
|
|
143
|
-
inputWidth: video.videoWidth,
|
|
144
|
-
inputHeight: video.videoHeight,
|
|
145
|
-
filterMinCF: this.filterMinCF,
|
|
146
|
-
filterBeta: this.filterBeta,
|
|
147
|
-
warmupTolerance: this.warmupTolerance,
|
|
148
|
-
missTolerance: this.missTolerance,
|
|
149
|
-
maxTrack: this.maxTrack,
|
|
150
|
-
onUpdate: (data) => {
|
|
151
|
-
if (data.type === "updateMatrix") {
|
|
152
|
-
const { targetIndex, worldMatrix } = data;
|
|
153
|
-
for (let i = 0; i < this.anchors.length; i++) {
|
|
154
|
-
if (this.anchors[i].targetIndex === targetIndex) {
|
|
155
|
-
if (this.anchors[i].css) {
|
|
156
|
-
this.anchors[i].group.children.forEach((obj) => {
|
|
157
|
-
obj.element.style.visibility = worldMatrix === null ? "hidden" : "visible";
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
this.anchors[i].group.visible = worldMatrix !== null;
|
|
162
|
-
}
|
|
163
|
-
if (worldMatrix !== null) {
|
|
164
|
-
let m = new Matrix4();
|
|
165
|
-
m.elements = [...worldMatrix];
|
|
166
|
-
m.multiply(this.postMatrixs[targetIndex]);
|
|
167
|
-
if (this.anchors[i].css) {
|
|
168
|
-
m.multiply(cssScaleDownMatrix);
|
|
169
|
-
}
|
|
170
|
-
this.anchors[i].group.matrix = m;
|
|
171
|
-
}
|
|
172
|
-
else {
|
|
173
|
-
this.anchors[i].group.matrix = invisibleMatrix;
|
|
174
|
-
}
|
|
175
|
-
if (this.anchors[i].visible && worldMatrix === null) {
|
|
176
|
-
this.anchors[i].visible = false;
|
|
177
|
-
if (this.anchors[i].onTargetLost) {
|
|
178
|
-
this.anchors[i].onTargetLost();
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (!this.anchors[i].visible && worldMatrix !== null) {
|
|
182
|
-
this.anchors[i].visible = true;
|
|
183
|
-
if (this.anchors[i].onTargetFound) {
|
|
184
|
-
this.anchors[i].onTargetFound();
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
if (this.anchors[i].onTargetUpdate) {
|
|
188
|
-
this.anchors[i].onTargetUpdate();
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
let isAnyVisible = this.anchors.reduce((acc, anchor) => {
|
|
193
|
-
return acc || anchor.visible;
|
|
194
|
-
}, false);
|
|
195
|
-
if (isAnyVisible) {
|
|
196
|
-
this.ui.hideScanning();
|
|
197
|
-
}
|
|
198
|
-
else {
|
|
199
|
-
this.ui.showScanning();
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
},
|
|
203
|
-
});
|
|
204
|
-
this.resize();
|
|
205
|
-
const { dimensions: imageTargetDimensions } = await this.controller.addImageTargets(this.imageTargetSrc);
|
|
206
|
-
this.postMatrixs = [];
|
|
207
|
-
for (let i = 0; i < imageTargetDimensions.length; i++) {
|
|
208
|
-
const position = new Vector3();
|
|
209
|
-
const quaternion = new Quaternion();
|
|
210
|
-
const scale = new Vector3();
|
|
211
|
-
const [markerWidth, markerHeight] = imageTargetDimensions[i];
|
|
212
|
-
position.x = markerWidth / 2;
|
|
213
|
-
position.y = markerWidth / 2 + (markerHeight - markerWidth) / 2;
|
|
214
|
-
scale.x = markerWidth;
|
|
215
|
-
scale.y = markerWidth;
|
|
216
|
-
scale.z = markerWidth;
|
|
217
|
-
const postMatrix = new Matrix4();
|
|
218
|
-
postMatrix.compose(position, quaternion, scale);
|
|
219
|
-
this.postMatrixs.push(postMatrix);
|
|
220
|
-
}
|
|
221
|
-
this.controller.dummyRun(this.video);
|
|
222
|
-
this.ui.hideLoading();
|
|
223
|
-
this.ui.showScanning();
|
|
224
|
-
this.controller.processVideo(this.video);
|
|
225
|
-
resolve();
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
resize() {
|
|
229
|
-
const { renderer, cssRenderer, camera, container, video } = this;
|
|
230
|
-
if (!video)
|
|
231
|
-
return;
|
|
232
|
-
this.video.setAttribute("width", this.video.videoWidth);
|
|
233
|
-
this.video.setAttribute("height", this.video.videoHeight);
|
|
234
|
-
let vw, vh; // display css width, height
|
|
235
|
-
const videoRatio = video.videoWidth / video.videoHeight;
|
|
236
|
-
const containerRatio = container.clientWidth / container.clientHeight;
|
|
237
|
-
if (videoRatio > containerRatio) {
|
|
238
|
-
vh = container.clientHeight;
|
|
239
|
-
vw = vh * videoRatio;
|
|
240
|
-
}
|
|
241
|
-
else {
|
|
242
|
-
vw = container.clientWidth;
|
|
243
|
-
vh = vw / videoRatio;
|
|
244
|
-
}
|
|
245
|
-
const proj = this.controller.getProjectionMatrix();
|
|
246
|
-
// TODO: move this logic to controller
|
|
247
|
-
// Handle when phone is rotated, video width and height are swapped
|
|
248
|
-
const inputRatio = this.controller.inputWidth / this.controller.inputHeight;
|
|
249
|
-
let inputAdjust;
|
|
250
|
-
if (inputRatio > containerRatio) {
|
|
251
|
-
inputAdjust = this.video.width / this.controller.inputWidth;
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
inputAdjust = this.video.height / this.controller.inputHeight;
|
|
255
|
-
}
|
|
256
|
-
let videoDisplayHeight;
|
|
257
|
-
let videoDisplayWidth;
|
|
258
|
-
if (inputRatio > containerRatio) {
|
|
259
|
-
videoDisplayHeight = container.clientHeight;
|
|
260
|
-
videoDisplayHeight *= inputAdjust;
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
videoDisplayWidth = container.clientWidth;
|
|
264
|
-
videoDisplayHeight =
|
|
265
|
-
(videoDisplayWidth / this.controller.inputWidth) * this.controller.inputHeight;
|
|
266
|
-
videoDisplayHeight *= inputAdjust;
|
|
267
|
-
}
|
|
268
|
-
let fovAdjust = container.clientHeight / videoDisplayHeight;
|
|
269
|
-
// const fov = 2 * Math.atan(1 / proj[5] / vh * container.clientHeight) * 180 / Math.PI; // vertical fov
|
|
270
|
-
const fov = (2 * Math.atan((1 / proj[5]) * fovAdjust) * 180) / Math.PI; // vertical fov
|
|
271
|
-
const near = proj[14] / (proj[10] - 1.0);
|
|
272
|
-
const far = proj[14] / (proj[10] + 1.0);
|
|
273
|
-
camera.fov = fov;
|
|
274
|
-
camera.near = near;
|
|
275
|
-
camera.far = far;
|
|
276
|
-
camera.aspect = container.clientWidth / container.clientHeight;
|
|
277
|
-
camera.updateProjectionMatrix();
|
|
278
|
-
video.style.top = -(vh - container.clientHeight) / 2 + "px";
|
|
279
|
-
video.style.left = -(vw - container.clientWidth) / 2 + "px";
|
|
280
|
-
video.style.width = vw + "px";
|
|
281
|
-
video.style.height = vh + "px";
|
|
282
|
-
const canvas = renderer.domElement;
|
|
283
|
-
const cssCanvas = cssRenderer.domElement;
|
|
284
|
-
canvas.style.position = "absolute";
|
|
285
|
-
canvas.style.left = 0;
|
|
286
|
-
canvas.style.top = 0;
|
|
287
|
-
canvas.style.width = container.clientWidth + "px";
|
|
288
|
-
canvas.style.height = container.clientHeight + "px";
|
|
289
|
-
cssCanvas.style.position = "absolute";
|
|
290
|
-
cssCanvas.style.left = 0;
|
|
291
|
-
cssCanvas.style.top = 0;
|
|
292
|
-
cssCanvas.style.width = container.clientWidth + "px";
|
|
293
|
-
cssCanvas.style.height = container.clientHeight + "px";
|
|
294
|
-
renderer.setSize(container.clientWidth, container.clientHeight);
|
|
295
|
-
cssRenderer.setSize(container.clientWidth, container.clientHeight);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (!window.TAAR) {
|
|
299
|
-
window.TAAR = {};
|
|
300
|
-
}
|
|
301
|
-
if (!window.TAAR.IMAGE) {
|
|
302
|
-
window.TAAR.IMAGE = {};
|
|
303
|
-
}
|
|
304
|
-
window.TAAR.IMAGE.TaarThree = TaarThree;
|
|
1
|
+
import{Matrix4 as e,Vector3 as t,Quaternion as i,Scene as s,WebGLRenderer as n,PerspectiveCamera as o,Group as r,sRGBEncoding as h}from"three";import{CSS3DRenderer as a}from"three/addons/renderers/CSS3DRenderer.js";import{Controller as l}from"./controller.js";import{UI as d}from"../ui/ui.js";const c=new e;c.compose(new t,new i,new t(.001,.001,.001));const u=(new e).set(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1);export class TaarThree{constructor({container:e,imageTargetSrc:t,maxTrack:i,uiLoading:r="yes",uiScanning:l="yes",uiError:c="yes",filterMinCF:u=null,filterBeta:v=null,warmupTolerance:p=null,missTolerance:g=null,userDeviceId:m=null,environmentDeviceId:w=null}){this.container=e,this.imageTargetSrc=t,this.maxTrack=i,this.filterMinCF=u,this.filterBeta=v,this.warmupTolerance=p,this.missTolerance=g,this.ui=new d({uiLoading:r,uiScanning:l,uiError:c}),this.userDeviceId=m,this.environmentDeviceId=w,this.shouldFaceUser=!1,this.scene=new s,this.cssScene=new s,this.renderer=new n({antialias:!0,alpha:!0}),this.cssRenderer=new a({antialias:!0}),this.renderer.outputEncoding=h,this.renderer.setPixelRatio(window.devicePixelRatio),this.camera=new o,this.anchors=[],this.renderer.domElement.style.position="absolute",this.cssRenderer.domElement.style.position="absolute",this.container.appendChild(this.renderer.domElement),this.container.appendChild(this.cssRenderer.domElement),window.addEventListener("resize",this.resize.bind(this))}async start(){this.ui.showLoading(),await this._startVideo(),await this._startAR()}stop(){this.controller.stopProcessVideo(),this.video.srcObject.getTracks().forEach(function(e){e.stop()}),this.video.remove()}switchCamera(){this.shouldFaceUser=!this.shouldFaceUser,this.stop(),this.start()}addAnchor(e){const t=new r;t.visible=!1,t.matrixAutoUpdate=!1;const i={group:t,targetIndex:e,onTargetFound:null,onTargetLost:null,onTargetUpdate:null,css:!1,visible:!1};return this.anchors.push(i),this.scene.add(t),i}addCSSAnchor(e){const t=new r;t.visible=!1,t.matrixAutoUpdate=!1;const i={group:t,targetIndex:e,onTargetFound:null,onTargetLost:null,onTargetUpdate:null,css:!0,visible:!1};return this.anchors.push(i),this.cssScene.add(t),i}_startVideo(){return new Promise(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)return this.ui.showCompatibility(),void reject();const t={audio:!1,video:{}};this.shouldFaceUser?this.userDeviceId?t.video.deviceId={exact:this.userDeviceId}:t.video.facingMode="user":this.environmentDeviceId?t.video.deviceId={exact:this.environmentDeviceId}:t.video.facingMode="environment",navigator.mediaDevices.getUserMedia(t).then(t=>{this.video.addEventListener("loadedmetadata",()=>{this.video.setAttribute("width",this.video.videoWidth),this.video.setAttribute("height",this.video.videoHeight),e()}),this.video.srcObject=t}).catch(e=>{console.log("getUserMedia error",e),reject()})})}_startAR(){return new Promise(async s=>{const n=this.video;this.controller=new l({inputWidth:n.videoWidth,inputHeight:n.videoHeight,filterMinCF:this.filterMinCF,filterBeta:this.filterBeta,warmupTolerance:this.warmupTolerance,missTolerance:this.missTolerance,maxTrack:this.maxTrack,onUpdate:t=>{if("updateMatrix"===t.type){const{targetIndex:i,worldMatrix:s}=t;for(let t=0;t<this.anchors.length;t++)if(this.anchors[t].targetIndex===i){if(this.anchors[t].css?this.anchors[t].group.children.forEach(e=>{e.element.style.visibility=null===s?"hidden":"visible"}):this.anchors[t].group.visible=null!==s,null!==s){let n=new e;n.elements=[...s],n.multiply(this.postMatrixs[i]),this.anchors[t].css&&n.multiply(c),this.anchors[t].group.matrix=n}else this.anchors[t].group.matrix=u;this.anchors[t].visible&&null===s&&(this.anchors[t].visible=!1,this.anchors[t].onTargetLost&&this.anchors[t].onTargetLost()),this.anchors[t].visible||null===s||(this.anchors[t].visible=!0,this.anchors[t].onTargetFound&&this.anchors[t].onTargetFound()),this.anchors[t].onTargetUpdate&&this.anchors[t].onTargetUpdate()}this.anchors.reduce((e,t)=>e||t.visible,!1)?this.ui.hideScanning():this.ui.showScanning()}}}),this.resize();const{dimensions:o}=await this.controller.addImageTargets(this.imageTargetSrc);this.postMatrixs=[];for(let s=0;s<o.length;s++){const n=new t,r=new i,h=new t,[a,l]=o[s];n.x=a/2,n.y=a/2+(l-a)/2,h.x=a,h.y=a,h.z=a;const d=new e;d.compose(n,r,h),this.postMatrixs.push(d)}this.controller.dummyRun(this.video),this.ui.hideLoading(),this.ui.showScanning(),this.controller.processVideo(this.video),s()})}resize(){const{renderer:e,cssRenderer:t,camera:i,container:s,video:n}=this;if(!n)return;let o,r;this.video.setAttribute("width",this.video.videoWidth),this.video.setAttribute("height",this.video.videoHeight);const h=n.videoWidth/n.videoHeight,a=s.clientWidth/s.clientHeight;h>a?(r=s.clientHeight,o=r*h):(o=s.clientWidth,r=o/h);const l=this.controller.getProjectionMatrix(),d=this.controller.inputWidth/this.controller.inputHeight;let c,u,v;c=d>a?this.video.width/this.controller.inputWidth:this.video.height/this.controller.inputHeight,d>a?(u=s.clientHeight,u*=c):(v=s.clientWidth,u=v/this.controller.inputWidth*this.controller.inputHeight,u*=c);let p=s.clientHeight/u;const g=2*Math.atan(1/l[5]*p)*180/Math.PI,m=l[14]/(l[10]-1),w=l[14]/(l[10]+1);i.fov=g,i.near=m,i.far=w,i.aspect=s.clientWidth/s.clientHeight,i.updateProjectionMatrix(),n.style.top=-(r-s.clientHeight)/2+"px",n.style.left=-(o-s.clientWidth)/2+"px",n.style.width=o+"px",n.style.height=r+"px";const T=e.domElement,x=t.domElement;T.style.position="absolute",T.style.left=0,T.style.top=0,T.style.width=s.clientWidth+"px",T.style.height=s.clientHeight+"px",x.style.position="absolute",x.style.left=0,x.style.top=0,x.style.width=s.clientWidth+"px",x.style.height=s.clientHeight+"px",e.setSize(s.clientWidth,s.clientHeight),t.setSize(s.clientWidth,s.clientHeight)}}window.TAAR||(window.TAAR={}),window.TAAR.IMAGE||(window.TAAR.IMAGE={}),window.TAAR.IMAGE.TaarThree=TaarThree;
|