@srsergio/taptapp-ar 1.0.22 → 1.0.24
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 +27 -26
- package/package.json +1 -1
- package/src/compiler/simple-ar.js +28 -30
|
@@ -131,18 +131,16 @@ class SimpleAR {
|
|
|
131
131
|
return;
|
|
132
132
|
const [markerW, markerH] = this.markerDimensions[targetIndex];
|
|
133
133
|
const containerRect = this.container.getBoundingClientRect();
|
|
134
|
-
// Video
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// Detect if
|
|
138
|
-
// Browser displays video vertically but videoWidth > videoHeight
|
|
134
|
+
// 1. Raw Video Dimensions (Sensor Frame)
|
|
135
|
+
const videoW = this.video.videoWidth;
|
|
136
|
+
const videoH = this.video.videoHeight;
|
|
137
|
+
// 2. Detect if screen orientation is different from video buffer
|
|
139
138
|
const isPortrait = containerRect.height > containerRect.width;
|
|
140
139
|
const isVideoLandscape = videoW > videoH;
|
|
141
140
|
const needsRotation = isPortrait && isVideoLandscape;
|
|
142
|
-
//
|
|
141
|
+
// Effective dimensions of the display buffer
|
|
143
142
|
const effectiveBufferW = needsRotation ? videoH : videoW;
|
|
144
143
|
const effectiveBufferH = needsRotation ? videoW : videoH;
|
|
145
|
-
// Calculate display area considering object-fit: cover
|
|
146
144
|
const containerAspect = containerRect.width / containerRect.height;
|
|
147
145
|
const bufferAspect = effectiveBufferW / effectiveBufferH;
|
|
148
146
|
let displayW, displayH, offsetX, offsetY;
|
|
@@ -160,17 +158,19 @@ class SimpleAR {
|
|
|
160
158
|
}
|
|
161
159
|
const scaleX = displayW / effectiveBufferW;
|
|
162
160
|
const scaleY = displayH / effectiveBufferH;
|
|
163
|
-
//
|
|
161
|
+
// 3. Focal Length (MUST match Controller.js)
|
|
162
|
+
// Controller uses inputHeight / 2 (sensor's vertical dimension) as the baseline.
|
|
163
|
+
const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
164
|
+
// 4. Project marker center into camera space
|
|
164
165
|
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
165
166
|
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
166
167
|
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
167
|
-
//
|
|
168
|
-
const f = effectiveBufferH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
169
|
-
// Normalized Device Coordinates (NDC) to Screen space
|
|
168
|
+
// 5. Map Camera coordinates to Screen coordinates
|
|
170
169
|
let screenX, screenY;
|
|
171
170
|
if (needsRotation) {
|
|
172
|
-
//
|
|
173
|
-
//
|
|
171
|
+
// Mapping Sensor coordinates to Rotated Screen coordinates
|
|
172
|
+
// Sensor +X -> Screen +Y
|
|
173
|
+
// Sensor +Y -> Screen -X (relative to logical center)
|
|
174
174
|
screenX = offsetX + (effectiveBufferW / 2 + (ty * f / tz)) * scaleX;
|
|
175
175
|
screenY = offsetY + (effectiveBufferH / 2 - (tx * f / tz)) * scaleY;
|
|
176
176
|
}
|
|
@@ -178,22 +178,23 @@ class SimpleAR {
|
|
|
178
178
|
screenX = offsetX + (effectiveBufferW / 2 + (tx * f / tz)) * scaleX;
|
|
179
179
|
screenY = offsetY + (effectiveBufferH / 2 + (ty * f / tz)) * scaleY;
|
|
180
180
|
}
|
|
181
|
-
// Rotation:
|
|
181
|
+
// 6. Rotation: sync with CSS transform
|
|
182
|
+
//atan2 gives angle of world X-axis in camera space.
|
|
182
183
|
let rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
183
|
-
if (needsRotation)
|
|
184
|
-
rotation -= Math.PI / 2;
|
|
184
|
+
if (needsRotation) {
|
|
185
|
+
rotation -= Math.PI / 2; // Mapping Sensor frame to Portrait Screen frame
|
|
186
|
+
}
|
|
187
|
+
// 7. Scale calculation (Robust Method)
|
|
188
|
+
// Instead of detecting intrinsic width (unstable), we force a base CSS width
|
|
189
|
+
// and calculate the scale to match the marker's projected screen width.
|
|
190
|
+
const BASE_CSS_WIDTH = 1000;
|
|
185
191
|
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
186
192
|
const perspectiveScale = (f / tz) * scaleX;
|
|
187
|
-
//
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
? (matrixScale * markerW * perspectiveScale) / intrinsicWidth
|
|
193
|
-
: 1.0;
|
|
194
|
-
const finalScale = baseScale * this.scaleMultiplier;
|
|
195
|
-
// Apply transform
|
|
196
|
-
this.overlay.style.width = 'auto';
|
|
193
|
+
// Target pixel width on screen = markerW * matrixScale * perspectiveScale
|
|
194
|
+
const targetScreenWidth = markerW * matrixScale * perspectiveScale;
|
|
195
|
+
const finalScale = (targetScreenWidth / BASE_CSS_WIDTH) * this.scaleMultiplier;
|
|
196
|
+
// Apply
|
|
197
|
+
this.overlay.style.width = `${BASE_CSS_WIDTH}px`;
|
|
197
198
|
this.overlay.style.height = 'auto';
|
|
198
199
|
this.overlay.style.position = 'absolute';
|
|
199
200
|
this.overlay.style.transformOrigin = 'center center';
|
package/package.json
CHANGED
|
@@ -156,26 +156,23 @@ class SimpleAR {
|
|
|
156
156
|
const [markerW, markerH] = this.markerDimensions[targetIndex];
|
|
157
157
|
const containerRect = this.container.getBoundingClientRect();
|
|
158
158
|
|
|
159
|
-
// Video
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
// 1. Raw Video Dimensions (Sensor Frame)
|
|
160
|
+
const videoW = this.video.videoWidth;
|
|
161
|
+
const videoH = this.video.videoHeight;
|
|
162
162
|
|
|
163
|
-
// Detect if
|
|
164
|
-
// Browser displays video vertically but videoWidth > videoHeight
|
|
163
|
+
// 2. Detect if screen orientation is different from video buffer
|
|
165
164
|
const isPortrait = containerRect.height > containerRect.width;
|
|
166
165
|
const isVideoLandscape = videoW > videoH;
|
|
167
166
|
const needsRotation = isPortrait && isVideoLandscape;
|
|
168
167
|
|
|
169
|
-
//
|
|
168
|
+
// Effective dimensions of the display buffer
|
|
170
169
|
const effectiveBufferW = needsRotation ? videoH : videoW;
|
|
171
170
|
const effectiveBufferH = needsRotation ? videoW : videoH;
|
|
172
171
|
|
|
173
|
-
// Calculate display area considering object-fit: cover
|
|
174
172
|
const containerAspect = containerRect.width / containerRect.height;
|
|
175
173
|
const bufferAspect = effectiveBufferW / effectiveBufferH;
|
|
176
174
|
|
|
177
175
|
let displayW, displayH, offsetX, offsetY;
|
|
178
|
-
|
|
179
176
|
if (containerAspect > bufferAspect) {
|
|
180
177
|
displayW = containerRect.width;
|
|
181
178
|
displayH = containerRect.width / bufferAspect;
|
|
@@ -191,20 +188,21 @@ class SimpleAR {
|
|
|
191
188
|
const scaleX = displayW / effectiveBufferW;
|
|
192
189
|
const scaleY = displayH / effectiveBufferH;
|
|
193
190
|
|
|
194
|
-
//
|
|
191
|
+
// 3. Focal Length (MUST match Controller.js)
|
|
192
|
+
// Controller uses inputHeight / 2 (sensor's vertical dimension) as the baseline.
|
|
193
|
+
const f = videoH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
194
|
+
|
|
195
|
+
// 4. Project marker center into camera space
|
|
195
196
|
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
196
197
|
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
197
198
|
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
198
199
|
|
|
199
|
-
//
|
|
200
|
-
const f = effectiveBufferH / 2 / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
201
|
-
|
|
202
|
-
// Normalized Device Coordinates (NDC) to Screen space
|
|
200
|
+
// 5. Map Camera coordinates to Screen coordinates
|
|
203
201
|
let screenX, screenY;
|
|
204
|
-
|
|
205
202
|
if (needsRotation) {
|
|
206
|
-
//
|
|
207
|
-
//
|
|
203
|
+
// Mapping Sensor coordinates to Rotated Screen coordinates
|
|
204
|
+
// Sensor +X -> Screen +Y
|
|
205
|
+
// Sensor +Y -> Screen -X (relative to logical center)
|
|
208
206
|
screenX = offsetX + (effectiveBufferW / 2 + (ty * f / tz)) * scaleX;
|
|
209
207
|
screenY = offsetY + (effectiveBufferH / 2 - (tx * f / tz)) * scaleY;
|
|
210
208
|
} else {
|
|
@@ -212,26 +210,26 @@ class SimpleAR {
|
|
|
212
210
|
screenY = offsetY + (effectiveBufferH / 2 + (ty * f / tz)) * scaleY;
|
|
213
211
|
}
|
|
214
212
|
|
|
215
|
-
// Rotation:
|
|
213
|
+
// 6. Rotation: sync with CSS transform
|
|
214
|
+
//atan2 gives angle of world X-axis in camera space.
|
|
216
215
|
let rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
217
|
-
if (needsRotation)
|
|
216
|
+
if (needsRotation) {
|
|
217
|
+
rotation -= Math.PI / 2; // Mapping Sensor frame to Portrait Screen frame
|
|
218
|
+
}
|
|
218
219
|
|
|
220
|
+
// 7. Scale calculation (Robust Method)
|
|
221
|
+
// Instead of detecting intrinsic width (unstable), we force a base CSS width
|
|
222
|
+
// and calculate the scale to match the marker's projected screen width.
|
|
223
|
+
const BASE_CSS_WIDTH = 1000;
|
|
219
224
|
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
220
225
|
const perspectiveScale = (f / tz) * scaleX;
|
|
221
226
|
|
|
222
|
-
//
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
: (this.overlay instanceof HTMLImageElement ? this.overlay.naturalWidth : 0);
|
|
226
|
-
|
|
227
|
-
const baseScale = intrinsicWidth > 0
|
|
228
|
-
? (matrixScale * markerW * perspectiveScale) / intrinsicWidth
|
|
229
|
-
: 1.0;
|
|
230
|
-
|
|
231
|
-
const finalScale = baseScale * this.scaleMultiplier;
|
|
227
|
+
// Target pixel width on screen = markerW * matrixScale * perspectiveScale
|
|
228
|
+
const targetScreenWidth = markerW * matrixScale * perspectiveScale;
|
|
229
|
+
const finalScale = (targetScreenWidth / BASE_CSS_WIDTH) * this.scaleMultiplier;
|
|
232
230
|
|
|
233
|
-
// Apply
|
|
234
|
-
this.overlay.style.width =
|
|
231
|
+
// Apply
|
|
232
|
+
this.overlay.style.width = `${BASE_CSS_WIDTH}px`;
|
|
235
233
|
this.overlay.style.height = 'auto';
|
|
236
234
|
this.overlay.style.position = 'absolute';
|
|
237
235
|
this.overlay.style.transformOrigin = 'center center';
|