Update viewer_ar_ios.js
Browse files- viewer_ar_ios.js +58 -48
viewer_ar_ios.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
| 1 |
-
/* viewer_ar_ios.js — AR PlayCanvas + GLB/USDZ via config.json
|
| 2 |
-
- Lit config.json (data-config) => { "glb_url": "...", "usdz_url": "..." }
|
| 3 |
-
- iOS : AR Quick Look (USDZ)
|
| 4 |
-
- Android/Desktop : WebXR AR
|
| 5 |
-
|
| 6 |
-
|
|
|
|
| 7 |
*/
|
| 8 |
|
| 9 |
(function () {
|
|
@@ -111,29 +112,14 @@
|
|
| 111 |
// ==========================
|
| 112 |
// Overlay / UI (styles intégrés)
|
| 113 |
// ==========================
|
| 114 |
-
// - #ar-overlay-root : overlay global (DOM overlay XR + toasts)
|
| 115 |
-
// - #ar-start-button : bouton Android/Desktop
|
| 116 |
-
// - #ar-ios-quicklook-button : bouton iOS (rel="ar" + <img> requis pour Quick Look)
|
| 117 |
-
// - .ar-rotation-panel : panneau rotation
|
| 118 |
-
// - #ar-rotation-* : slider yaw
|
| 119 |
-
|
| 120 |
var css = [
|
| 121 |
-
/* Conteneur overlay global */
|
| 122 |
"#ar-overlay-root{position:fixed;inset:0;z-index:10001;pointer-events:none}",
|
| 123 |
-
|
| 124 |
-
/* Toasts */
|
| 125 |
".pc-ar-msg{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10002;padding:10px 14px;background:rgba(0,0,0,.65);color:#fff;border-radius:12px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.3;text-align:center;max-width:min(90vw,640px);box-shadow:0 6px 20px rgba(0,0,0,.25);backdrop-filter:blur(4px);pointer-events:none}",
|
| 126 |
".pc-ar-msg.pc-ar-msg--centerBig{top:50%;bottom:auto;transform:translate(-50%,-50%);font-size:20px;padding:16px 22px;max-width:min(90vw,760px)}",
|
| 127 |
-
|
| 128 |
-
/* ----- Bouton Android/Desktop : centré + légèrement plus grand ----- */
|
| 129 |
-
"#ar-start-button{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:10003;pointer-events:auto;border:none;border-radius:16px;padding:16px 24px;font-size:18px;line-height:1;background:#000;color:#fff;box-shadow:0 10px 28px rgba(0,0,0,.28);cursor:pointer;min-width:200px;text-align:center}",
|
| 130 |
"#ar-start-button[disabled]{opacity:.5;cursor:not-allowed}",
|
| 131 |
-
|
| 132 |
-
/* ----- Bouton iOS Quick Look : centré + <img> (exigé par Quick Look) ----- */
|
| 133 |
"#ar-ios-quicklook-button{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:10003;pointer-events:auto;display:inline-block;text-decoration:none}",
|
| 134 |
"#ar-ios-quicklook-button img{display:block;height:60px;width:auto;box-shadow:0 10px 28px rgba(0,0,0,.28);border-radius:14px}",
|
| 135 |
-
|
| 136 |
-
/* ----- Panneau rotation ----- */
|
| 137 |
".ar-rotation-panel{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:rgba(0,0,0,0.55);color:#fff;padding:12px 10px;border-radius:16px;width:56px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:8px;box-shadow:0 6px 18px rgba(0,0,0,.25);backdrop-filter:blur(6px);touch-action:none}",
|
| 138 |
".ar-rotation-panel .label{font-size:12px;text-align:center;opacity:.95}",
|
| 139 |
"#ar-rotation-track{position:relative;width:48px;height:200px;display:flex;align-items:center;justify-content:center;touch-action:none;overflow:visible;pointer-events:auto}",
|
|
@@ -183,7 +169,7 @@
|
|
| 183 |
}
|
| 184 |
}
|
| 185 |
|
| 186 |
-
// iOS :
|
| 187 |
function ensureQuickLookButton(USDZ_URL) {
|
| 188 |
var btn = document.getElementById("ar-ios-quicklook-button");
|
| 189 |
if (btn) return btn;
|
|
@@ -193,7 +179,6 @@
|
|
| 193 |
anchor.setAttribute("rel", "ar");
|
| 194 |
anchor.setAttribute("href", buildQuickLookHref(USDZ_URL));
|
| 195 |
|
| 196 |
-
// Bouton visuel en SVG embarqué, libellé "Lancer l’AR"
|
| 197 |
var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="240" height="60">' +
|
| 198 |
'<rect rx="14" ry="14" width="240" height="60" fill="black"/>' +
|
| 199 |
'<text x="120" y="37" font-size="18" text-anchor="middle" fill="white" font-family="system-ui, -apple-system, Segoe UI, Roboto">Lancer l’AR</text>' +
|
|
@@ -227,7 +212,7 @@
|
|
| 227 |
}
|
| 228 |
|
| 229 |
// ==========================
|
| 230 |
-
// Montage du canvas
|
| 231 |
// ==========================
|
| 232 |
function ensureCanvas() {
|
| 233 |
var scriptEl = getCurrentScript();
|
|
@@ -299,18 +284,23 @@
|
|
| 299 |
cfg.usdz_url :
|
| 300 |
null;
|
| 301 |
|
| 302 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
if (isIOS()) {
|
| 304 |
if (USDZ_URL) {
|
| 305 |
ensureQuickLookButton(USDZ_URL);
|
| 306 |
-
message("Modèle chargé. Appuyez sur « Lancer l’AR
|
|
|
|
| 307 |
} else {
|
| 308 |
message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
|
| 309 |
}
|
| 310 |
return;
|
| 311 |
}
|
| 312 |
|
| 313 |
-
// Android/Desktop →
|
| 314 |
try {
|
| 315 |
await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
|
| 316 |
} catch (e) {
|
|
@@ -318,13 +308,13 @@
|
|
| 318 |
message("Impossible de charger PlayCanvas (réseau/CDN). Réessaie plus tard.");
|
| 319 |
return;
|
| 320 |
}
|
| 321 |
-
initARApp(GLB_URL);
|
| 322 |
})();
|
| 323 |
|
| 324 |
// ==========================
|
| 325 |
// Application WebXR (Android/Desktop)
|
| 326 |
// ==========================
|
| 327 |
-
function initARApp(GLB_URL) {
|
| 328 |
var pc = window.pc;
|
| 329 |
|
| 330 |
var canvas = ensureCanvas();
|
|
@@ -386,7 +376,7 @@
|
|
| 386 |
app.root.addChild(modelRoot);
|
| 387 |
var modelLoaded = false, placedOnce = false;
|
| 388 |
|
| 389 |
-
// Ombre blob
|
| 390 |
var blob = null;
|
| 391 |
var BLOB_SIZE = 0.4;
|
| 392 |
var BLOB_OFFSET_Y = 0.005;
|
|
@@ -496,6 +486,24 @@
|
|
| 496 |
|
| 497 |
if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
|
| 498 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 499 |
// Slider (pointer capture)
|
| 500 |
var uiInteracting = false;
|
| 501 |
var draggingTrack = false;
|
|
@@ -557,24 +565,16 @@
|
|
| 557 |
// Bouton start Android/Desktop
|
| 558 |
var startBtn = ensureARStartButton(activateAR);
|
| 559 |
|
| 560 |
-
// Pas de démarrage par tap/clic sur le canvas
|
| 561 |
app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
|
| 562 |
|
| 563 |
-
// Hit-test (
|
| 564 |
-
var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
|
| 565 |
-
function isHorizontalUpFacing(rot, minDot) {
|
| 566 |
-
minDot = (typeof minDot === "number") ? minDot : 0.75;
|
| 567 |
-
rot.transformVector(TMP_IN, TMP_OUT);
|
| 568 |
-
return TMP_OUT.y >= minDot;
|
| 569 |
-
}
|
| 570 |
-
|
| 571 |
app.xr.hitTest.on("available", function () {
|
| 572 |
app.xr.hitTest.start({
|
| 573 |
entityTypes: [pc.XRTRACKABLE_POINT, pc.XRTRACKABLE_PLANE],
|
| 574 |
callback: function (err, hitSource) {
|
| 575 |
if (err) { message("Le AR hit test n’a pas pu démarrer."); return; }
|
| 576 |
hitSource.on("result", function (pos, rot) {
|
| 577 |
-
if (!
|
| 578 |
|
| 579 |
reticle.enabled = true;
|
| 580 |
reticle.setPosition(pos);
|
|
@@ -584,23 +584,31 @@
|
|
| 584 |
modelRoot.enabled = true;
|
| 585 |
modelRoot.setPosition(pos);
|
| 586 |
|
| 587 |
-
|
|
|
|
|
|
|
|
|
|
| 588 |
|
|
|
|
| 589 |
var e = new pc.Vec3();
|
| 590 |
rot.getEulerAngles(e);
|
| 591 |
var y0 = ((e.y % 360) + 360) % 360;
|
|
|
|
|
|
|
| 592 |
applyRotationY(y0);
|
| 593 |
|
| 594 |
placedOnce = true;
|
| 595 |
rotInput.disabled = false;
|
| 596 |
-
message(
|
|
|
|
|
|
|
| 597 |
}
|
| 598 |
});
|
| 599 |
}
|
| 600 |
});
|
| 601 |
});
|
| 602 |
|
| 603 |
-
// Drag XR continu
|
| 604 |
var isDragging = false;
|
| 605 |
app.xr.input.on("add", function (inputSource) {
|
| 606 |
inputSource.on("selectstart", function () {
|
|
@@ -615,9 +623,9 @@
|
|
| 615 |
|
| 616 |
transientSource.on("result", function (pos, rot) {
|
| 617 |
if (!isDragging) return;
|
| 618 |
-
if (!
|
| 619 |
modelRoot.setPosition(pos);
|
| 620 |
-
updateBlobPositionUnder(pos, rot);
|
| 621 |
});
|
| 622 |
|
| 623 |
transientSource.once("remove", function () { isDragging = false; });
|
|
@@ -645,7 +653,7 @@
|
|
| 645 |
if (reticle.enabled) {
|
| 646 |
var p = reticle.getPosition();
|
| 647 |
modelRoot.setPosition(p);
|
| 648 |
-
updateBlobPositionUnder(p, null);
|
| 649 |
}
|
| 650 |
} else if (rotateMode && modelRoot.enabled) {
|
| 651 |
var dx = e.x - lastMouseX;
|
|
@@ -667,7 +675,9 @@
|
|
| 667 |
// Événements AR (feedback + visibilité bouton)
|
| 668 |
app.xr.on("start", function () {
|
| 669 |
if (startBtn) startBtn.style.display = "none";
|
| 670 |
-
message(
|
|
|
|
|
|
|
| 671 |
reticle.enabled = true;
|
| 672 |
});
|
| 673 |
app.xr.on("end", function () {
|
|
|
|
| 1 |
+
/* viewer_ar_ios.js — AR PlayCanvas + GLB/USDZ via config.json (+ support murs via "sol": false)
|
| 2 |
+
- Lit config.json (data-config) => { "glb_url": "...", "usdz_url": "...", "sol": true|false }
|
| 3 |
+
- iOS : AR Quick Look (USDZ) — on ne peut PAS forcer mur/sol, mais l’utilisateur peut glisser l’objet sur un mur
|
| 4 |
+
- Android/Desktop : WebXR AR
|
| 5 |
+
* sol=true => plans horizontaux (sol)
|
| 6 |
+
* sol=false => plans verticaux (murs)
|
| 7 |
+
+ bouton "Lancer l’AR" (centré) + curseur rotation (yaw)
|
| 8 |
*/
|
| 9 |
|
| 10 |
(function () {
|
|
|
|
| 112 |
// ==========================
|
| 113 |
// Overlay / UI (styles intégrés)
|
| 114 |
// ==========================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
var css = [
|
|
|
|
| 116 |
"#ar-overlay-root{position:fixed;inset:0;z-index:10001;pointer-events:none}",
|
|
|
|
|
|
|
| 117 |
".pc-ar-msg{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10002;padding:10px 14px;background:rgba(0,0,0,.65);color:#fff;border-radius:12px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;font-size:14px;line-height:1.3;text-align:center;max-width:min(90vw,640px);box-shadow:0 6px 20px rgba(0,0,0,.25);backdrop-filter:blur(4px);pointer-events:none}",
|
| 118 |
".pc-ar-msg.pc-ar-msg--centerBig{top:50%;bottom:auto;transform:translate(-50%,-50%);font-size:20px;padding:16px 22px;max-width:min(90vw,760px)}",
|
| 119 |
+
"#ar-start-button{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:10003;pointer-events:auto;border:none;border-radius:16px;padding:16px 24px;font-size:18px;background:#000;color:#fff;box-shadow:0 10px 28px rgba(0,0,0,.28);cursor:pointer;min-width:200px;text-align:center}",
|
|
|
|
|
|
|
| 120 |
"#ar-start-button[disabled]{opacity:.5;cursor:not-allowed}",
|
|
|
|
|
|
|
| 121 |
"#ar-ios-quicklook-button{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:10003;pointer-events:auto;display:inline-block;text-decoration:none}",
|
| 122 |
"#ar-ios-quicklook-button img{display:block;height:60px;width:auto;box-shadow:0 10px 28px rgba(0,0,0,.28);border-radius:14px}",
|
|
|
|
|
|
|
| 123 |
".ar-rotation-panel{position:absolute;right:12px;top:50%;transform:translateY(-50%);background:rgba(0,0,0,0.55);color:#fff;padding:12px 10px;border-radius:16px;width:56px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;pointer-events:auto;display:flex;flex-direction:column;align-items:center;gap:8px;box-shadow:0 6px 18px rgba(0,0,0,.25);backdrop-filter:blur(6px);touch-action:none}",
|
| 124 |
".ar-rotation-panel .label{font-size:12px;text-align:center;opacity:.95}",
|
| 125 |
"#ar-rotation-track{position:relative;width:48px;height:200px;display:flex;align-items:center;justify-content:center;touch-action:none;overflow:visible;pointer-events:auto}",
|
|
|
|
| 169 |
}
|
| 170 |
}
|
| 171 |
|
| 172 |
+
// iOS : bouton Quick Look (l’utilisateur peut glisser l’objet sur un mur si souhaité)
|
| 173 |
function ensureQuickLookButton(USDZ_URL) {
|
| 174 |
var btn = document.getElementById("ar-ios-quicklook-button");
|
| 175 |
if (btn) return btn;
|
|
|
|
| 179 |
anchor.setAttribute("rel", "ar");
|
| 180 |
anchor.setAttribute("href", buildQuickLookHref(USDZ_URL));
|
| 181 |
|
|
|
|
| 182 |
var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="240" height="60">' +
|
| 183 |
'<rect rx="14" ry="14" width="240" height="60" fill="black"/>' +
|
| 184 |
'<text x="120" y="37" font-size="18" text-anchor="middle" fill="white" font-family="system-ui, -apple-system, Segoe UI, Roboto">Lancer l’AR</text>' +
|
|
|
|
| 212 |
}
|
| 213 |
|
| 214 |
// ==========================
|
| 215 |
+
// Montage du canvas
|
| 216 |
// ==========================
|
| 217 |
function ensureCanvas() {
|
| 218 |
var scriptEl = getCurrentScript();
|
|
|
|
| 284 |
cfg.usdz_url :
|
| 285 |
null;
|
| 286 |
|
| 287 |
+
// NEW: lecture de "sol" (par défaut true)
|
| 288 |
+
var PLACE_ON_FLOOR = true;
|
| 289 |
+
if (cfg && typeof cfg.sol === "boolean") PLACE_ON_FLOOR = !!cfg.sol;
|
| 290 |
+
|
| 291 |
+
// iOS → Quick Look (on ne peut pas imposer mur/sol)
|
| 292 |
if (isIOS()) {
|
| 293 |
if (USDZ_URL) {
|
| 294 |
ensureQuickLookButton(USDZ_URL);
|
| 295 |
+
message("Modèle chargé. Appuyez sur « Lancer l’AR » puis placez-le " +
|
| 296 |
+
(PLACE_ON_FLOOR ? "sur le sol." : "sur un mur (faites-le glisser)."));
|
| 297 |
} else {
|
| 298 |
message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
|
| 299 |
}
|
| 300 |
return;
|
| 301 |
}
|
| 302 |
|
| 303 |
+
// Android/Desktop → WebXR
|
| 304 |
try {
|
| 305 |
await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
|
| 306 |
} catch (e) {
|
|
|
|
| 308 |
message("Impossible de charger PlayCanvas (réseau/CDN). Réessaie plus tard.");
|
| 309 |
return;
|
| 310 |
}
|
| 311 |
+
initARApp(GLB_URL, PLACE_ON_FLOOR);
|
| 312 |
})();
|
| 313 |
|
| 314 |
// ==========================
|
| 315 |
// Application WebXR (Android/Desktop)
|
| 316 |
// ==========================
|
| 317 |
+
function initARApp(GLB_URL, PLACE_ON_FLOOR) {
|
| 318 |
var pc = window.pc;
|
| 319 |
|
| 320 |
var canvas = ensureCanvas();
|
|
|
|
| 376 |
app.root.addChild(modelRoot);
|
| 377 |
var modelLoaded = false, placedOnce = false;
|
| 378 |
|
| 379 |
+
// Ombre blob (uniquement pour le sol)
|
| 380 |
var blob = null;
|
| 381 |
var BLOB_SIZE = 0.4;
|
| 382 |
var BLOB_OFFSET_Y = 0.005;
|
|
|
|
| 486 |
|
| 487 |
if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
|
| 488 |
|
| 489 |
+
// ----- Détection d’orientation de plan -----
|
| 490 |
+
var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
|
| 491 |
+
// Sol : normal ≈ +Y
|
| 492 |
+
function isHorizontalUpFacing(rot, minDot) {
|
| 493 |
+
minDot = (typeof minDot === "number") ? minDot : 0.75;
|
| 494 |
+
rot.transformVector(TMP_IN, TMP_OUT);
|
| 495 |
+
return TMP_OUT.y >= minDot;
|
| 496 |
+
}
|
| 497 |
+
// Mur : normal ≈ horizontale (|y| petit)
|
| 498 |
+
function isVerticalFacing(rot, maxAbsY) {
|
| 499 |
+
maxAbsY = (typeof maxAbsY === "number") ? maxAbsY : 0.35; // tolérance
|
| 500 |
+
rot.transformVector(TMP_IN, TMP_OUT);
|
| 501 |
+
return Math.abs(TMP_OUT.y) <= maxAbsY;
|
| 502 |
+
}
|
| 503 |
+
function planeMatchesMode(rot) {
|
| 504 |
+
return PLACE_ON_FLOOR ? isHorizontalUpFacing(rot) : isVerticalFacing(rot);
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
// Slider (pointer capture)
|
| 508 |
var uiInteracting = false;
|
| 509 |
var draggingTrack = false;
|
|
|
|
| 565 |
// Bouton start Android/Desktop
|
| 566 |
var startBtn = ensureARStartButton(activateAR);
|
| 567 |
|
|
|
|
| 568 |
app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
|
| 569 |
|
| 570 |
+
// Hit-test (sol ⇧ vs mur ⇨)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 571 |
app.xr.hitTest.on("available", function () {
|
| 572 |
app.xr.hitTest.start({
|
| 573 |
entityTypes: [pc.XRTRACKABLE_POINT, pc.XRTRACKABLE_PLANE],
|
| 574 |
callback: function (err, hitSource) {
|
| 575 |
if (err) { message("Le AR hit test n’a pas pu démarrer."); return; }
|
| 576 |
hitSource.on("result", function (pos, rot) {
|
| 577 |
+
if (!planeMatchesMode(rot)) return;
|
| 578 |
|
| 579 |
reticle.enabled = true;
|
| 580 |
reticle.setPosition(pos);
|
|
|
|
| 584 |
modelRoot.enabled = true;
|
| 585 |
modelRoot.setPosition(pos);
|
| 586 |
|
| 587 |
+
// Ombre : seulement pour le sol
|
| 588 |
+
if (PLACE_ON_FLOOR) {
|
| 589 |
+
blob = createBlobShadowAt(pos, rot);
|
| 590 |
+
}
|
| 591 |
|
| 592 |
+
// Aligner l’orientation “yaw” avec le plan détecté (sol ou mur)
|
| 593 |
var e = new pc.Vec3();
|
| 594 |
rot.getEulerAngles(e);
|
| 595 |
var y0 = ((e.y % 360) + 360) % 360;
|
| 596 |
+
// sur mur : garder l’objet droit (pas d’inclinaison X/Z)
|
| 597 |
+
if (!PLACE_ON_FLOOR) { baseEulerX = 0; baseEulerZ = 0; }
|
| 598 |
applyRotationY(y0);
|
| 599 |
|
| 600 |
placedOnce = true;
|
| 601 |
rotInput.disabled = false;
|
| 602 |
+
message(PLACE_ON_FLOOR ?
|
| 603 |
+
"Objet placé. Glissez pour déplacer, tournez-le avec le slider →" :
|
| 604 |
+
"Objet placé contre le mur. Glissez pour déplacer sur le mur, tournez-le avec le slider →");
|
| 605 |
}
|
| 606 |
});
|
| 607 |
}
|
| 608 |
});
|
| 609 |
});
|
| 610 |
|
| 611 |
+
// Drag XR continu (suivant le mode)
|
| 612 |
var isDragging = false;
|
| 613 |
app.xr.input.on("add", function (inputSource) {
|
| 614 |
inputSource.on("selectstart", function () {
|
|
|
|
| 623 |
|
| 624 |
transientSource.on("result", function (pos, rot) {
|
| 625 |
if (!isDragging) return;
|
| 626 |
+
if (!planeMatchesMode(rot)) return;
|
| 627 |
modelRoot.setPosition(pos);
|
| 628 |
+
if (PLACE_ON_FLOOR) updateBlobPositionUnder(pos, rot);
|
| 629 |
});
|
| 630 |
|
| 631 |
transientSource.once("remove", function () { isDragging = false; });
|
|
|
|
| 653 |
if (reticle.enabled) {
|
| 654 |
var p = reticle.getPosition();
|
| 655 |
modelRoot.setPosition(p);
|
| 656 |
+
if (PLACE_ON_FLOOR) updateBlobPositionUnder(p, null);
|
| 657 |
}
|
| 658 |
} else if (rotateMode && modelRoot.enabled) {
|
| 659 |
var dx = e.x - lastMouseX;
|
|
|
|
| 675 |
// Événements AR (feedback + visibilité bouton)
|
| 676 |
app.xr.on("start", function () {
|
| 677 |
if (startBtn) startBtn.style.display = "none";
|
| 678 |
+
message(PLACE_ON_FLOOR ?
|
| 679 |
+
"Session AR démarrée. Visez le sol pour détecter un plan…" :
|
| 680 |
+
"Session AR démarrée. Visez un mur pour détecter un plan vertical…");
|
| 681 |
reticle.enabled = true;
|
| 682 |
});
|
| 683 |
app.xr.on("end", function () {
|