@srsergio/taptapp-ar 1.0.15 → 1.0.17
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/controller.js +1 -1
- package/dist/compiler/detector/detector-lite.js +3 -3
- package/dist/compiler/simple-ar.d.ts +2 -1
- package/dist/compiler/simple-ar.js +30 -19
- package/package.json +1 -1
- package/src/compiler/controller.js +1 -1
- package/src/compiler/detector/detector-lite.js +2 -2
- package/src/compiler/simple-ar.js +35 -19
|
@@ -283,7 +283,7 @@ class Controller {
|
|
|
283
283
|
clone = this.getRotatedZ90Matrix(clone);
|
|
284
284
|
}
|
|
285
285
|
this.onUpdate &&
|
|
286
|
-
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone });
|
|
286
|
+
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
|
|
287
287
|
}
|
|
288
288
|
}
|
|
289
289
|
this.onUpdate && this.onUpdate({ type: "processDone" });
|
|
@@ -14,7 +14,7 @@ import { gpuCompute } from "../utils/gpu-compute.js";
|
|
|
14
14
|
const PYRAMID_MIN_SIZE = 8;
|
|
15
15
|
const PYRAMID_MAX_OCTAVE = 5;
|
|
16
16
|
const NUM_BUCKETS_PER_DIMENSION = 8;
|
|
17
|
-
const MAX_FEATURES_PER_BUCKET =
|
|
17
|
+
const MAX_FEATURES_PER_BUCKET = 10; // Aumentado de 3 a 10 para mayor densidad de puntos tracking
|
|
18
18
|
const ORIENTATION_NUM_BINS = 36;
|
|
19
19
|
const FREAK_EXPANSION_FACTOR = 7.0;
|
|
20
20
|
// Global GPU mode flag
|
|
@@ -241,8 +241,8 @@ export class DetectorLite {
|
|
|
241
241
|
for (let y = 1; y < height - 1; y++) {
|
|
242
242
|
for (let x = 1; x < width - 1; x++) {
|
|
243
243
|
const val = curr.data[y * width + x];
|
|
244
|
-
if (Math.abs(val) < 0.
|
|
245
|
-
continue; // Threshold
|
|
244
|
+
if (Math.abs(val) < 0.01)
|
|
245
|
+
continue; // Threshold reducido de 0.015 a 0.01 para mayor sensibilidad
|
|
246
246
|
let isMaxima = true;
|
|
247
247
|
let isMinima = true;
|
|
248
248
|
// Check 3x3 neighborhood in current scale
|
|
@@ -47,6 +47,7 @@ export class SimpleAR {
|
|
|
47
47
|
* Initialize and start AR tracking
|
|
48
48
|
*/
|
|
49
49
|
start(): Promise<this>;
|
|
50
|
+
markerDimensions: any;
|
|
50
51
|
/**
|
|
51
52
|
* Stop AR tracking and release resources
|
|
52
53
|
*/
|
|
@@ -55,6 +56,6 @@ export class SimpleAR {
|
|
|
55
56
|
_startCamera(): Promise<void>;
|
|
56
57
|
_initController(): void;
|
|
57
58
|
_handleUpdate(data: any): void;
|
|
58
|
-
_positionOverlay(
|
|
59
|
+
_positionOverlay(mVT: any, targetIndex: any): void;
|
|
59
60
|
}
|
|
60
61
|
import { Controller } from "./controller.js";
|
|
@@ -41,7 +41,8 @@ class SimpleAR {
|
|
|
41
41
|
this._initController();
|
|
42
42
|
// 4. Load targets (supports single URL or array of URLs)
|
|
43
43
|
const targets = Array.isArray(this.targetSrc) ? this.targetSrc : [this.targetSrc];
|
|
44
|
-
await this.controller.addImageTargets(targets);
|
|
44
|
+
const result = await this.controller.addImageTargets(targets);
|
|
45
|
+
this.markerDimensions = result.dimensions; // [ [w1, h1], [w2, h2], ... ]
|
|
45
46
|
this.controller.processVideo(this.video);
|
|
46
47
|
return this;
|
|
47
48
|
}
|
|
@@ -59,6 +60,7 @@ class SimpleAR {
|
|
|
59
60
|
this.video = null;
|
|
60
61
|
}
|
|
61
62
|
this.isTracking = false;
|
|
63
|
+
this.markerDimensions = [];
|
|
62
64
|
}
|
|
63
65
|
_createVideo() {
|
|
64
66
|
this.video = document.createElement('video');
|
|
@@ -101,7 +103,7 @@ class SimpleAR {
|
|
|
101
103
|
_handleUpdate(data) {
|
|
102
104
|
if (data.type !== 'updateMatrix')
|
|
103
105
|
return;
|
|
104
|
-
const { targetIndex, worldMatrix } = data;
|
|
106
|
+
const { targetIndex, worldMatrix, modelViewTransform } = data;
|
|
105
107
|
if (worldMatrix) {
|
|
106
108
|
// Target found
|
|
107
109
|
if (!this.isTracking) {
|
|
@@ -110,7 +112,7 @@ class SimpleAR {
|
|
|
110
112
|
this.onFound && this.onFound({ targetIndex });
|
|
111
113
|
}
|
|
112
114
|
this.lastMatrix = worldMatrix;
|
|
113
|
-
this._positionOverlay(
|
|
115
|
+
this._positionOverlay(modelViewTransform, targetIndex);
|
|
114
116
|
this.onUpdateCallback && this.onUpdateCallback({ targetIndex, worldMatrix });
|
|
115
117
|
}
|
|
116
118
|
else {
|
|
@@ -122,9 +124,10 @@ class SimpleAR {
|
|
|
122
124
|
}
|
|
123
125
|
}
|
|
124
126
|
}
|
|
125
|
-
_positionOverlay(
|
|
126
|
-
if (!this.overlay)
|
|
127
|
+
_positionOverlay(mVT, targetIndex) {
|
|
128
|
+
if (!this.overlay || !this.markerDimensions[targetIndex])
|
|
127
129
|
return;
|
|
130
|
+
const [markerW, markerH] = this.markerDimensions[targetIndex];
|
|
128
131
|
const containerRect = this.container.getBoundingClientRect();
|
|
129
132
|
const videoW = this.video.videoWidth;
|
|
130
133
|
const videoH = this.video.videoHeight;
|
|
@@ -133,14 +136,12 @@ class SimpleAR {
|
|
|
133
136
|
const videoAspect = videoW / videoH;
|
|
134
137
|
let displayW, displayH, offsetX, offsetY;
|
|
135
138
|
if (containerAspect > videoAspect) {
|
|
136
|
-
// Container is wider - video fills width, crops height
|
|
137
139
|
displayW = containerRect.width;
|
|
138
140
|
displayH = containerRect.width / videoAspect;
|
|
139
141
|
offsetX = 0;
|
|
140
142
|
offsetY = (containerRect.height - displayH) / 2;
|
|
141
143
|
}
|
|
142
144
|
else {
|
|
143
|
-
// Container is taller - video fills height, crops width
|
|
144
145
|
displayH = containerRect.height;
|
|
145
146
|
displayW = containerRect.height * videoAspect;
|
|
146
147
|
offsetX = (containerRect.width - displayW) / 2;
|
|
@@ -148,18 +149,28 @@ class SimpleAR {
|
|
|
148
149
|
}
|
|
149
150
|
const scaleX = displayW / videoW;
|
|
150
151
|
const scaleY = displayH / videoH;
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
const tx =
|
|
154
|
-
const ty =
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
//
|
|
162
|
-
|
|
152
|
+
// Project the center of the marker (markerW/2, markerH/2, 0) into camera space
|
|
153
|
+
// Marker coordinates are pixels from top-left.
|
|
154
|
+
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
155
|
+
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
156
|
+
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
157
|
+
// focal length (roughly 45 degrees FOV match Controller.js)
|
|
158
|
+
const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
159
|
+
// Perspective projection to screen space
|
|
160
|
+
const screenX = offsetX + (videoW / 2 + (tx * f / -tz)) * scaleX;
|
|
161
|
+
const screenY = offsetY + (videoH / 2 - (ty * f / -tz)) * scaleY;
|
|
162
|
+
// Use the first row of mVT to determine rotation and base scale component
|
|
163
|
+
// Since marker coordinates are in pixels, mVT[0][0] and mVT[0][1] are unitless scale factors
|
|
164
|
+
const rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
165
|
+
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
166
|
+
// Perspective scale: how much larger/smaller the object is based on distance (tz)
|
|
167
|
+
// Correct scale should make a marker-width sized element cover the marker.
|
|
168
|
+
const perspectiveScale = (f / -tz) * scaleX;
|
|
169
|
+
// The overlay element has its own width in CSS pixels (e.g. 200px)
|
|
170
|
+
const overlayCSSWidth = parseFloat(this.overlay.style.width) || 200;
|
|
171
|
+
// Final scale = (Target Width in Pixels on screen) / (Overlay CSS Width)
|
|
172
|
+
// matrixScale is usually ~1.0 if tracking is rigid
|
|
173
|
+
const finalScale = (matrixScale * markerW * perspectiveScale) / overlayCSSWidth;
|
|
163
174
|
// Apply transform
|
|
164
175
|
this.overlay.style.position = 'absolute';
|
|
165
176
|
this.overlay.style.transformOrigin = 'center center';
|
package/package.json
CHANGED
|
@@ -348,7 +348,7 @@ class Controller {
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
this.onUpdate &&
|
|
351
|
-
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone });
|
|
351
|
+
this.onUpdate({ type: "updateMatrix", targetIndex: i, worldMatrix: clone, modelViewTransform: trackingState.currentModelViewTransform });
|
|
352
352
|
}
|
|
353
353
|
}
|
|
354
354
|
|
|
@@ -16,7 +16,7 @@ import { gpuCompute } from "../utils/gpu-compute.js";
|
|
|
16
16
|
const PYRAMID_MIN_SIZE = 8;
|
|
17
17
|
const PYRAMID_MAX_OCTAVE = 5;
|
|
18
18
|
const NUM_BUCKETS_PER_DIMENSION = 8;
|
|
19
|
-
const MAX_FEATURES_PER_BUCKET =
|
|
19
|
+
const MAX_FEATURES_PER_BUCKET = 10; // Aumentado de 3 a 10 para mayor densidad de puntos tracking
|
|
20
20
|
const ORIENTATION_NUM_BINS = 36;
|
|
21
21
|
const FREAK_EXPANSION_FACTOR = 7.0;
|
|
22
22
|
|
|
@@ -282,7 +282,7 @@ export class DetectorLite {
|
|
|
282
282
|
for (let x = 1; x < width - 1; x++) {
|
|
283
283
|
const val = curr.data[y * width + x];
|
|
284
284
|
|
|
285
|
-
if (Math.abs(val) < 0.
|
|
285
|
+
if (Math.abs(val) < 0.01) continue; // Threshold reducido de 0.015 a 0.01 para mayor sensibilidad
|
|
286
286
|
|
|
287
287
|
let isMaxima = true;
|
|
288
288
|
let isMinima = true;
|
|
@@ -55,7 +55,9 @@ class SimpleAR {
|
|
|
55
55
|
|
|
56
56
|
// 4. Load targets (supports single URL or array of URLs)
|
|
57
57
|
const targets = Array.isArray(this.targetSrc) ? this.targetSrc : [this.targetSrc];
|
|
58
|
-
await this.controller.addImageTargets(targets);
|
|
58
|
+
const result = await this.controller.addImageTargets(targets);
|
|
59
|
+
this.markerDimensions = result.dimensions; // [ [w1, h1], [w2, h2], ... ]
|
|
60
|
+
|
|
59
61
|
this.controller.processVideo(this.video);
|
|
60
62
|
|
|
61
63
|
return this;
|
|
@@ -75,6 +77,7 @@ class SimpleAR {
|
|
|
75
77
|
this.video = null;
|
|
76
78
|
}
|
|
77
79
|
this.isTracking = false;
|
|
80
|
+
this.markerDimensions = [];
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
_createVideo() {
|
|
@@ -121,7 +124,7 @@ class SimpleAR {
|
|
|
121
124
|
_handleUpdate(data) {
|
|
122
125
|
if (data.type !== 'updateMatrix') return;
|
|
123
126
|
|
|
124
|
-
const { targetIndex, worldMatrix } = data;
|
|
127
|
+
const { targetIndex, worldMatrix, modelViewTransform } = data;
|
|
125
128
|
|
|
126
129
|
if (worldMatrix) {
|
|
127
130
|
// Target found
|
|
@@ -132,7 +135,7 @@ class SimpleAR {
|
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
this.lastMatrix = worldMatrix;
|
|
135
|
-
this._positionOverlay(
|
|
138
|
+
this._positionOverlay(modelViewTransform, targetIndex);
|
|
136
139
|
this.onUpdateCallback && this.onUpdateCallback({ targetIndex, worldMatrix });
|
|
137
140
|
|
|
138
141
|
} else {
|
|
@@ -145,9 +148,10 @@ class SimpleAR {
|
|
|
145
148
|
}
|
|
146
149
|
}
|
|
147
150
|
|
|
148
|
-
_positionOverlay(
|
|
149
|
-
if (!this.overlay) return;
|
|
151
|
+
_positionOverlay(mVT, targetIndex) {
|
|
152
|
+
if (!this.overlay || !this.markerDimensions[targetIndex]) return;
|
|
150
153
|
|
|
154
|
+
const [markerW, markerH] = this.markerDimensions[targetIndex];
|
|
151
155
|
const containerRect = this.container.getBoundingClientRect();
|
|
152
156
|
const videoW = this.video.videoWidth;
|
|
153
157
|
const videoH = this.video.videoHeight;
|
|
@@ -159,13 +163,11 @@ class SimpleAR {
|
|
|
159
163
|
let displayW, displayH, offsetX, offsetY;
|
|
160
164
|
|
|
161
165
|
if (containerAspect > videoAspect) {
|
|
162
|
-
// Container is wider - video fills width, crops height
|
|
163
166
|
displayW = containerRect.width;
|
|
164
167
|
displayH = containerRect.width / videoAspect;
|
|
165
168
|
offsetX = 0;
|
|
166
169
|
offsetY = (containerRect.height - displayH) / 2;
|
|
167
170
|
} else {
|
|
168
|
-
// Container is taller - video fills height, crops width
|
|
169
171
|
displayH = containerRect.height;
|
|
170
172
|
displayW = containerRect.height * videoAspect;
|
|
171
173
|
offsetX = (containerRect.width - displayW) / 2;
|
|
@@ -175,20 +177,34 @@ class SimpleAR {
|
|
|
175
177
|
const scaleX = displayW / videoW;
|
|
176
178
|
const scaleY = displayH / videoH;
|
|
177
179
|
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
const tx =
|
|
181
|
-
const ty =
|
|
182
|
-
const
|
|
183
|
-
|
|
180
|
+
// Project the center of the marker (markerW/2, markerH/2, 0) into camera space
|
|
181
|
+
// Marker coordinates are pixels from top-left.
|
|
182
|
+
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
183
|
+
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
184
|
+
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
185
|
+
|
|
186
|
+
// focal length (roughly 45 degrees FOV match Controller.js)
|
|
187
|
+
const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
188
|
+
|
|
189
|
+
// Perspective projection to screen space
|
|
190
|
+
const screenX = offsetX + (videoW / 2 + (tx * f / -tz)) * scaleX;
|
|
191
|
+
const screenY = offsetY + (videoH / 2 - (ty * f / -tz)) * scaleY;
|
|
192
|
+
|
|
193
|
+
// Use the first row of mVT to determine rotation and base scale component
|
|
194
|
+
// Since marker coordinates are in pixels, mVT[0][0] and mVT[0][1] are unitless scale factors
|
|
195
|
+
const rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
196
|
+
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
197
|
+
|
|
198
|
+
// Perspective scale: how much larger/smaller the object is based on distance (tz)
|
|
199
|
+
// Correct scale should make a marker-width sized element cover the marker.
|
|
200
|
+
const perspectiveScale = (f / -tz) * scaleX;
|
|
184
201
|
|
|
185
|
-
//
|
|
186
|
-
const
|
|
187
|
-
const screenY = offsetY + (videoH / 2 - ty) * scaleY;
|
|
202
|
+
// The overlay element has its own width in CSS pixels (e.g. 200px)
|
|
203
|
+
const overlayCSSWidth = parseFloat(this.overlay.style.width) || 200;
|
|
188
204
|
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
const finalScale = matrixScale *
|
|
205
|
+
// Final scale = (Target Width in Pixels on screen) / (Overlay CSS Width)
|
|
206
|
+
// matrixScale is usually ~1.0 if tracking is rigid
|
|
207
|
+
const finalScale = (matrixScale * markerW * perspectiveScale) / overlayCSSWidth;
|
|
192
208
|
|
|
193
209
|
// Apply transform
|
|
194
210
|
this.overlay.style.position = 'absolute';
|