@srsergio/taptapp-ar 1.0.23 → 1.0.25
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/simple-ar.js +30 -56
- package/package.json +1 -1
- package/src/compiler/simple-ar.js +34 -62
|
@@ -131,82 +131,56 @@ class SimpleAR {
|
|
|
131
131
|
return;
|
|
132
132
|
const [markerW, markerH] = this.markerDimensions[targetIndex];
|
|
133
133
|
const containerRect = this.container.getBoundingClientRect();
|
|
134
|
-
// 1. Raw Video Dimensions (Sensor Frame)
|
|
135
134
|
const videoW = this.video.videoWidth;
|
|
136
135
|
const videoH = this.video.videoHeight;
|
|
137
|
-
// 2. Detect if screen orientation is different from video buffer
|
|
138
136
|
const isPortrait = containerRect.height > containerRect.width;
|
|
139
137
|
const isVideoLandscape = videoW > videoH;
|
|
140
138
|
const needsRotation = isPortrait && isVideoLandscape;
|
|
141
|
-
//
|
|
142
|
-
const effectiveBufferW = needsRotation ? videoH : videoW;
|
|
143
|
-
const effectiveBufferH = needsRotation ? videoW : videoH;
|
|
144
|
-
const containerAspect = containerRect.width / containerRect.height;
|
|
145
|
-
const bufferAspect = effectiveBufferW / effectiveBufferH;
|
|
146
|
-
let displayW, displayH, offsetX, offsetY;
|
|
147
|
-
if (containerAspect > bufferAspect) {
|
|
148
|
-
displayW = containerRect.width;
|
|
149
|
-
displayH = containerRect.width / bufferAspect;
|
|
150
|
-
offsetX = 0;
|
|
151
|
-
offsetY = (containerRect.height - displayH) / 2;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
displayH = containerRect.height;
|
|
155
|
-
displayW = containerRect.height * bufferAspect;
|
|
156
|
-
offsetX = (containerRect.width - displayW) / 2;
|
|
157
|
-
offsetY = 0;
|
|
158
|
-
}
|
|
159
|
-
const scaleX = displayW / effectiveBufferW;
|
|
160
|
-
const scaleY = displayH / effectiveBufferH;
|
|
161
|
-
// 3. Focal Length (MUST match Controller.js projection)
|
|
162
|
-
// Controller.js uses inputHeight / 2 as the vertical reference.
|
|
139
|
+
// The tracker uses 1280x720. Focal length is based on 720 (sensor height).
|
|
163
140
|
const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
164
|
-
//
|
|
141
|
+
// Project Center of the marker into camera space
|
|
165
142
|
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
166
143
|
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
167
144
|
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
168
|
-
|
|
169
|
-
let screenX, screenY;
|
|
145
|
+
let screenX, screenY, rotation, perspectiveScale;
|
|
170
146
|
if (needsRotation) {
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
147
|
+
// PORTRAIT MOBILE:
|
|
148
|
+
// Browser rotates 1280 (W) -> vertical, 720 (H) -> horizontal
|
|
149
|
+
const scale = containerRect.height / videoW;
|
|
150
|
+
const displayW = videoH * scale;
|
|
151
|
+
const offsetX = (containerRect.width - displayW) / 2;
|
|
152
|
+
// Mapping: Buffer +X (Right) -> Screen +Y (Down), Buffer +Y (Down) -> Screen -X (Left)
|
|
153
|
+
screenX = offsetX + (displayW / 2 - (ty * f / tz) * scale);
|
|
154
|
+
screenY = (containerRect.height / 2 + (tx * f / tz) * scale);
|
|
155
|
+
rotation = Math.atan2(mVT[1][0], mVT[0][0]) - Math.PI / 2;
|
|
156
|
+
perspectiveScale = scale;
|
|
176
157
|
}
|
|
177
158
|
else {
|
|
178
|
-
|
|
179
|
-
|
|
159
|
+
// LANDSCAPE / LAPTOP:
|
|
160
|
+
const scale = containerRect.width / videoW;
|
|
161
|
+
const displayH = videoH * scale;
|
|
162
|
+
const offsetY = (containerRect.height - displayH) / 2;
|
|
163
|
+
screenX = (containerRect.width / 2 + (tx * f / tz) * scale);
|
|
164
|
+
screenY = offsetY + (displayH / 2 + (ty * f / tz) * scale);
|
|
165
|
+
rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
166
|
+
perspectiveScale = scale;
|
|
180
167
|
}
|
|
181
|
-
//
|
|
182
|
-
//atan2 gives angle of world X-axis in camera space.
|
|
183
|
-
let rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
184
|
-
if (needsRotation) {
|
|
185
|
-
rotation += Math.PI / 2; // Compensate for the 90deg rotation of the video element
|
|
186
|
-
}
|
|
187
|
-
// 7. Scale calculation
|
|
168
|
+
// Final Scale
|
|
188
169
|
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
: (this.overlay instanceof HTMLImageElement ? this.overlay.naturalWidth : 0);
|
|
193
|
-
const baseScale = intrinsicWidth > 0
|
|
194
|
-
? (matrixScale * markerW * perspectiveScale) / intrinsicWidth
|
|
195
|
-
: 1.0;
|
|
196
|
-
const finalScale = baseScale * this.scaleMultiplier;
|
|
197
|
-
// Apply transform
|
|
198
|
-
this.overlay.style.width = 'auto';
|
|
170
|
+
const finalScale = (f / tz) * perspectiveScale * matrixScale * this.scaleMultiplier;
|
|
171
|
+
// Apply
|
|
172
|
+
this.overlay.style.width = `${markerW}px`;
|
|
199
173
|
this.overlay.style.height = 'auto';
|
|
200
174
|
this.overlay.style.position = 'absolute';
|
|
201
175
|
this.overlay.style.transformOrigin = 'center center';
|
|
202
176
|
this.overlay.style.left = '0';
|
|
203
177
|
this.overlay.style.top = '0';
|
|
204
178
|
this.overlay.style.transform = `
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
179
|
+
translate(${screenX}px, ${screenY}px)
|
|
180
|
+
translate(-50%, -50%)
|
|
181
|
+
scale(${finalScale})
|
|
182
|
+
rotate(${rotation}rad)
|
|
183
|
+
`;
|
|
210
184
|
}
|
|
211
185
|
}
|
|
212
186
|
export { SimpleAR };
|
package/package.json
CHANGED
|
@@ -156,94 +156,66 @@ class SimpleAR {
|
|
|
156
156
|
const [markerW, markerH] = this.markerDimensions[targetIndex];
|
|
157
157
|
const containerRect = this.container.getBoundingClientRect();
|
|
158
158
|
|
|
159
|
-
// 1. Raw Video Dimensions (Sensor Frame)
|
|
160
159
|
const videoW = this.video.videoWidth;
|
|
161
160
|
const videoH = this.video.videoHeight;
|
|
162
161
|
|
|
163
|
-
// 2. Detect if screen orientation is different from video buffer
|
|
164
162
|
const isPortrait = containerRect.height > containerRect.width;
|
|
165
163
|
const isVideoLandscape = videoW > videoH;
|
|
166
164
|
const needsRotation = isPortrait && isVideoLandscape;
|
|
167
165
|
|
|
168
|
-
//
|
|
169
|
-
const effectiveBufferW = needsRotation ? videoH : videoW;
|
|
170
|
-
const effectiveBufferH = needsRotation ? videoW : videoH;
|
|
171
|
-
|
|
172
|
-
const containerAspect = containerRect.width / containerRect.height;
|
|
173
|
-
const bufferAspect = effectiveBufferW / effectiveBufferH;
|
|
174
|
-
|
|
175
|
-
let displayW, displayH, offsetX, offsetY;
|
|
176
|
-
if (containerAspect > bufferAspect) {
|
|
177
|
-
displayW = containerRect.width;
|
|
178
|
-
displayH = containerRect.width / bufferAspect;
|
|
179
|
-
offsetX = 0;
|
|
180
|
-
offsetY = (containerRect.height - displayH) / 2;
|
|
181
|
-
} else {
|
|
182
|
-
displayH = containerRect.height;
|
|
183
|
-
displayW = containerRect.height * bufferAspect;
|
|
184
|
-
offsetX = (containerRect.width - displayW) / 2;
|
|
185
|
-
offsetY = 0;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const scaleX = displayW / effectiveBufferW;
|
|
189
|
-
const scaleY = displayH / effectiveBufferH;
|
|
190
|
-
|
|
191
|
-
// 3. Focal Length (MUST match Controller.js projection)
|
|
192
|
-
// Controller.js uses inputHeight / 2 as the vertical reference.
|
|
166
|
+
// The tracker uses 1280x720. Focal length is based on 720 (sensor height).
|
|
193
167
|
const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
194
168
|
|
|
195
|
-
//
|
|
169
|
+
// Project Center of the marker into camera space
|
|
196
170
|
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
197
171
|
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
198
172
|
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
199
173
|
|
|
200
|
-
|
|
201
|
-
|
|
174
|
+
let screenX, screenY, rotation, perspectiveScale;
|
|
175
|
+
|
|
202
176
|
if (needsRotation) {
|
|
203
|
-
//
|
|
204
|
-
//
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
177
|
+
// PORTRAIT MOBILE:
|
|
178
|
+
// Browser rotates 1280 (W) -> vertical, 720 (H) -> horizontal
|
|
179
|
+
const scale = containerRect.height / videoW;
|
|
180
|
+
const displayW = videoH * scale;
|
|
181
|
+
const offsetX = (containerRect.width - displayW) / 2;
|
|
182
|
+
|
|
183
|
+
// Mapping: Buffer +X (Right) -> Screen +Y (Down), Buffer +Y (Down) -> Screen -X (Left)
|
|
184
|
+
screenX = offsetX + (displayW / 2 - (ty * f / tz) * scale);
|
|
185
|
+
screenY = (containerRect.height / 2 + (tx * f / tz) * scale);
|
|
186
|
+
|
|
187
|
+
rotation = Math.atan2(mVT[1][0], mVT[0][0]) - Math.PI / 2;
|
|
188
|
+
perspectiveScale = scale;
|
|
208
189
|
} else {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
190
|
+
// LANDSCAPE / LAPTOP:
|
|
191
|
+
const scale = containerRect.width / videoW;
|
|
192
|
+
const displayH = videoH * scale;
|
|
193
|
+
const offsetY = (containerRect.height - displayH) / 2;
|
|
212
194
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
195
|
+
screenX = (containerRect.width / 2 + (tx * f / tz) * scale);
|
|
196
|
+
screenY = offsetY + (displayH / 2 + (ty * f / tz) * scale);
|
|
197
|
+
|
|
198
|
+
rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
199
|
+
perspectiveScale = scale;
|
|
218
200
|
}
|
|
219
201
|
|
|
220
|
-
//
|
|
202
|
+
// Final Scale
|
|
221
203
|
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
const intrinsicWidth = (this.overlay instanceof HTMLVideoElement)
|
|
225
|
-
? this.overlay.videoWidth
|
|
226
|
-
: (this.overlay instanceof HTMLImageElement ? this.overlay.naturalWidth : 0);
|
|
204
|
+
const finalScale = (f / tz) * perspectiveScale * matrixScale * this.scaleMultiplier;
|
|
227
205
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
: 1.0;
|
|
231
|
-
|
|
232
|
-
const finalScale = baseScale * this.scaleMultiplier;
|
|
233
|
-
|
|
234
|
-
// Apply transform
|
|
235
|
-
this.overlay.style.width = 'auto';
|
|
206
|
+
// Apply
|
|
207
|
+
this.overlay.style.width = `${markerW}px`;
|
|
236
208
|
this.overlay.style.height = 'auto';
|
|
237
209
|
this.overlay.style.position = 'absolute';
|
|
238
210
|
this.overlay.style.transformOrigin = 'center center';
|
|
239
211
|
this.overlay.style.left = '0';
|
|
240
212
|
this.overlay.style.top = '0';
|
|
241
213
|
this.overlay.style.transform = `
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
214
|
+
translate(${screenX}px, ${screenY}px)
|
|
215
|
+
translate(-50%, -50%)
|
|
216
|
+
scale(${finalScale})
|
|
217
|
+
rotate(${rotation}rad)
|
|
218
|
+
`;
|
|
247
219
|
}
|
|
248
220
|
}
|
|
249
221
|
|