MikaFil commited on
Commit
263ad84
·
verified ·
1 Parent(s): 085d305

Update viewer_ar_ios.js

Browse files
Files changed (1) hide show
  1. viewer_ar_ios.js +44 -33
viewer_ar_ios.js CHANGED
@@ -1,8 +1,7 @@
1
- <script>
2
  /* viewer_ar_ios.js — AR PlayCanvas + GLB/USDZ via config.json
3
  - Lit config.json (data-config) => { "glb_url": "...", "usdz_url": "..." }
4
  - iOS : AR Quick Look (USDZ) avec #allowsContentScaling=0 (pas de zoom)
5
- - Android/Desktop : WebXR AR (horizontaux uniquement) + slider yaw + blob shadow
6
  - Éclairage PBR par défaut (sans WebXR light estimation)
7
  - Monté dans un conteneur choisi (data-mount="#ar-mount") pour Squarespace
8
  */
@@ -10,7 +9,7 @@
10
  (function () {
11
  // ============ Utils: script tag / config / platform ============
12
  function getCurrentScript() {
13
- // robuste même si currentScript n'est pas dispo
14
  return document.currentScript || (function () {
15
  var scripts = document.getElementsByTagName('script');
16
  return scripts[scripts.length - 1] || null;
@@ -71,7 +70,7 @@
71
  if (!window.pc) window.pc = ns;
72
  return window.pc;
73
  }
74
- } catch (e) { /* continue */ }
75
  }
76
  throw new Error("ESM failed");
77
  }
@@ -92,7 +91,7 @@
92
  timeout(loadTimeoutMs)
93
  ]);
94
  if (window.pc && window.pc.Application) return window.pc;
95
- } catch (e) { /* continue */ }
96
  }
97
  throw new Error("UMD failed");
98
  }
@@ -100,15 +99,15 @@
100
  try {
101
  if (esmFirst) return await tryESM();
102
  return await tryUMD();
103
- } catch (e) {
104
  if (esmFirst) return await tryUMD();
105
  return await tryESM();
106
  }
107
  }
108
 
109
  // ============ UI / Overlay commun ============
110
- // (On garde un style minimal intégré pour le message ; si tu utilises un CSS externe,
111
- // tu peux déplacer ces règles dans ce fichier.)
112
  var css = [
113
  /* Toast (bas) */
114
  ".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}",
@@ -145,7 +144,7 @@
145
  }
146
  var overlayRoot = ensureOverlayRoot();
147
 
148
- // ------ Système de message : toast (bas) ou centré agrandi ------
149
  function getMessageEl() {
150
  var el = overlayRoot.querySelector(".pc-ar-msg");
151
  if (!el) {
@@ -175,7 +174,7 @@
175
  params.set('allowsContentScaling', '0');
176
  u.hash = params.toString();
177
  return u.toString();
178
- } catch (e) {
179
  return usdzUrl + (usdzUrl.indexOf('#') >= 0 ? '&' : '#') + 'allowsContentScaling=0';
180
  }
181
  }
@@ -244,7 +243,7 @@
244
  // Optionnel : ramener le viewport sur le viewer
245
  try {
246
  mountEl.scrollIntoView({ behavior: 'instant', block: 'start' });
247
- } catch (_) {}
248
 
249
  return canvas;
250
  }
@@ -362,28 +361,29 @@
362
  modelRoot.enabled = false;
363
  app.root.addChild(modelRoot);
364
 
365
- var modelLoaded = false, placedOnce = false;
 
366
 
367
  // ===== Ombre de contact “blob” =====
368
  var blobShadowEntity = null;
369
  var BLOB_SIZE = 0.4;
370
  var BLOB_OFFSET_Y = 0.005;
371
 
372
- function makeBlobTexture(app, size) {
373
- size = size || 256;
374
  var cvs = document.createElement('canvas');
375
- cvs.width = cvs.height = size;
376
  var ctx = cvs.getContext('2d');
377
- var r = size * 0.45;
378
- var grd = ctx.createRadialGradient(size/2, size/2, r*0.2, size/2, size/2, r);
379
  grd.addColorStop(0, 'rgba(0,0,0,0.5)');
380
  grd.addColorStop(1, 'rgba(0,0,0,0.0)');
381
  ctx.fillStyle = grd;
382
- ctx.fillRect(0, 0, size, size);
383
 
384
- var tex = new pc.Texture(app.graphicsDevice, {
385
- width: size,
386
- height: size,
387
  format: pc.PIXELFORMAT_R8_G8_B8_A8,
388
  mipmaps: true,
389
  magFilter: pc.FILTER_LINEAR,
@@ -420,7 +420,8 @@
420
  }
421
 
422
  // Euler de base (évite inversions)
423
- var baseEulerX = 0, baseEulerZ = 0;
 
424
 
425
  // Rotation via slider (0..360, 360 en haut / 0 en bas)
426
  var rotationYDeg = 0;
@@ -473,7 +474,7 @@
473
 
474
  modelLoaded = true;
475
 
476
- // >>> ICI : message centré et plus grand <<<
477
  messageCenterBig("Modèle chargé. Touchez l’écran pour démarrer l’AR.");
478
  });
479
 
@@ -490,7 +491,7 @@
490
  var y = (e.clientY != null) ? e.clientY : ((e.touches && e.touches[0] && e.touches[0].clientY) || 0);
491
  var ratio = (y - rect.top) / rect.height;
492
  var t = Math.max(0, Math.min(1, ratio));
493
- return (1 - t) * 360;
494
  }
495
 
496
  function onPointerDownCapture(e) {
@@ -499,7 +500,7 @@
499
  isTrackDragging = true;
500
  activePointerId = (e.pointerId != null) ? e.pointerId : 1;
501
  if (rotTrack.setPointerCapture) {
502
- try { rotTrack.setPointerCapture(activePointerId); } catch (er) {}
503
  }
504
  applyRotationY(degFromPointer(e));
505
  e.preventDefault();
@@ -516,7 +517,7 @@
516
  isTrackDragging = false;
517
  isUIInteracting = false;
518
  if (rotTrack.releasePointerCapture) {
519
- try { rotTrack.releasePointerCapture(activePointerId); } catch (er) {}
520
  }
521
  activePointerId = null;
522
  e.preventDefault();
@@ -556,11 +557,12 @@
556
  app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
557
 
558
  // Hit-test HORIZONTAL uniquement
559
- var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
 
560
  function isHorizontalUpFacing(rot, minDot) {
561
- minDot = (typeof minDot === "number") ? minDot : 0.75;
562
  rot.transformVector(TMP_IN, TMP_OUT);
563
- return TMP_OUT.y >= minDot;
564
  }
565
 
566
  // Hit Test global
@@ -627,7 +629,8 @@
627
  });
628
 
629
  // Desktop : rotation souris (ignore si UI)
630
- var isRotateMode = false, lastMouseX = 0;
 
631
  var ROTATE_SENSITIVITY = 0.25;
632
  app.mouse.on("mousedown", function (e) {
633
  if (!app.xr.active || !placedOnce || isUIInteracting) return;
@@ -664,8 +667,17 @@
664
  }, { passive: true });
665
 
666
  // AR events
667
- app.xr.on("start", function () { messageToast("Session AR démarrée. Visez le sol pour détecter un plan…"); reticle.enabled = true; });
668
- app.xr.on("end", function () { messageToast("Session AR terminée."); reticle.enabled = false; isModelDragging = false; isRotateMode = false; rotRangeInput.disabled = true; });
 
 
 
 
 
 
 
 
 
669
  app.xr.on("available:" + pc.XRTYPE_AR, function (a) {
670
  if (!a) messageToast("AR immersive indisponible.");
671
  else if (!app.xr.hitTest.supported) messageToast("AR Hit Test non supporté.");
@@ -677,4 +689,3 @@
677
  else messageToast("Chargement du modèle…");
678
  }
679
  })();
680
- </script>
 
 
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) avec #allowsContentScaling=0 (pas de zoom)
4
+ - Android/Desktop : WebXR AR (plans HORIZONTAUX uniquement) + slider yaw + blob shadow
5
  - Éclairage PBR par défaut (sans WebXR light estimation)
6
  - Monté dans un conteneur choisi (data-mount="#ar-mount") pour Squarespace
7
  */
 
9
  (function () {
10
  // ============ Utils: script tag / config / platform ============
11
  function getCurrentScript() {
12
+ // Robuste même si document.currentScript n'est pas dispo
13
  return document.currentScript || (function () {
14
  var scripts = document.getElementsByTagName('script');
15
  return scripts[scripts.length - 1] || null;
 
70
  if (!window.pc) window.pc = ns;
71
  return window.pc;
72
  }
73
+ } catch (_e) { /* continue */ }
74
  }
75
  throw new Error("ESM failed");
76
  }
 
91
  timeout(loadTimeoutMs)
92
  ]);
93
  if (window.pc && window.pc.Application) return window.pc;
94
+ } catch (_e) { /* continue */ }
95
  }
96
  throw new Error("UMD failed");
97
  }
 
99
  try {
100
  if (esmFirst) return await tryESM();
101
  return await tryUMD();
102
+ } catch (_e) {
103
  if (esmFirst) return await tryUMD();
104
  return await tryESM();
105
  }
106
  }
107
 
108
  // ============ UI / Overlay commun ============
109
+ // Style minimal intégré : toasts + variante centrée pour le message initial.
110
+ // (Si tu utilises un CSS externe, tu peux déplacer ces règles dans ce fichier.)
111
  var css = [
112
  /* Toast (bas) */
113
  ".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}",
 
144
  }
145
  var overlayRoot = ensureOverlayRoot();
146
 
147
+ // ------ Système de message : toast (bas) OU centré agrandi ------
148
  function getMessageEl() {
149
  var el = overlayRoot.querySelector(".pc-ar-msg");
150
  if (!el) {
 
174
  params.set('allowsContentScaling', '0');
175
  u.hash = params.toString();
176
  return u.toString();
177
+ } catch (_e) {
178
  return usdzUrl + (usdzUrl.indexOf('#') >= 0 ? '&' : '#') + 'allowsContentScaling=0';
179
  }
180
  }
 
243
  // Optionnel : ramener le viewport sur le viewer
244
  try {
245
  mountEl.scrollIntoView({ behavior: 'instant', block: 'start' });
246
+ } catch (_e) {}
247
 
248
  return canvas;
249
  }
 
361
  modelRoot.enabled = false;
362
  app.root.addChild(modelRoot);
363
 
364
+ var modelLoaded = false;
365
+ var placedOnce = false;
366
 
367
  // ===== Ombre de contact “blob” =====
368
  var blobShadowEntity = null;
369
  var BLOB_SIZE = 0.4;
370
  var BLOB_OFFSET_Y = 0.005;
371
 
372
+ function makeBlobTexture(appRef, size) {
373
+ var s = size || 256;
374
  var cvs = document.createElement('canvas');
375
+ cvs.width = cvs.height = s;
376
  var ctx = cvs.getContext('2d');
377
+ var r = s * 0.45;
378
+ var grd = ctx.createRadialGradient(s / 2, s / 2, r * 0.2, s / 2, s / 2, r);
379
  grd.addColorStop(0, 'rgba(0,0,0,0.5)');
380
  grd.addColorStop(1, 'rgba(0,0,0,0.0)');
381
  ctx.fillStyle = grd;
382
+ ctx.fillRect(0, 0, s, s);
383
 
384
+ var tex = new pc.Texture(appRef.graphicsDevice, {
385
+ width: s,
386
+ height: s,
387
  format: pc.PIXELFORMAT_R8_G8_B8_A8,
388
  mipmaps: true,
389
  magFilter: pc.FILTER_LINEAR,
 
420
  }
421
 
422
  // Euler de base (évite inversions)
423
+ var baseEulerX = 0;
424
+ var baseEulerZ = 0;
425
 
426
  // Rotation via slider (0..360, 360 en haut / 0 en bas)
427
  var rotationYDeg = 0;
 
474
 
475
  modelLoaded = true;
476
 
477
+ // >>> Message centré & un peu plus grand pour l’invite initiale
478
  messageCenterBig("Modèle chargé. Touchez l’écran pour démarrer l’AR.");
479
  });
480
 
 
491
  var y = (e.clientY != null) ? e.clientY : ((e.touches && e.touches[0] && e.touches[0].clientY) || 0);
492
  var ratio = (y - rect.top) / rect.height;
493
  var t = Math.max(0, Math.min(1, ratio));
494
+ return (1 - t) * 360; // 360 en haut, 0 en bas
495
  }
496
 
497
  function onPointerDownCapture(e) {
 
500
  isTrackDragging = true;
501
  activePointerId = (e.pointerId != null) ? e.pointerId : 1;
502
  if (rotTrack.setPointerCapture) {
503
+ try { rotTrack.setPointerCapture(activePointerId); } catch (_er) {}
504
  }
505
  applyRotationY(degFromPointer(e));
506
  e.preventDefault();
 
517
  isTrackDragging = false;
518
  isUIInteracting = false;
519
  if (rotTrack.releasePointerCapture) {
520
+ try { rotTrack.releasePointerCapture(activePointerId); } catch (_er) {}
521
  }
522
  activePointerId = null;
523
  e.preventDefault();
 
557
  app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
558
 
559
  // Hit-test HORIZONTAL uniquement
560
+ var TMP_IN = new pc.Vec3(0, 1, 0);
561
+ var TMP_OUT = new pc.Vec3();
562
  function isHorizontalUpFacing(rot, minDot) {
563
+ var md = (typeof minDot === "number") ? minDot : 0.75;
564
  rot.transformVector(TMP_IN, TMP_OUT);
565
+ return TMP_OUT.y >= md; // normale proche de +Y
566
  }
567
 
568
  // Hit Test global
 
629
  });
630
 
631
  // Desktop : rotation souris (ignore si UI)
632
+ var isRotateMode = false;
633
+ var lastMouseX = 0;
634
  var ROTATE_SENSITIVITY = 0.25;
635
  app.mouse.on("mousedown", function (e) {
636
  if (!app.xr.active || !placedOnce || isUIInteracting) return;
 
667
  }, { passive: true });
668
 
669
  // AR events
670
+ app.xr.on("start", function () {
671
+ messageToast("Session AR démarrée. Visez le sol pour détecter un plan…");
672
+ reticle.enabled = true;
673
+ });
674
+ app.xr.on("end", function () {
675
+ messageToast("Session AR terminée.");
676
+ reticle.enabled = false;
677
+ isModelDragging = false;
678
+ isRotateMode = false;
679
+ rotRangeInput.disabled = true;
680
+ });
681
  app.xr.on("available:" + pc.XRTYPE_AR, function (a) {
682
  if (!a) messageToast("AR immersive indisponible.");
683
  else if (!app.xr.hitTest.supported) messageToast("AR Hit Test non supporté.");
 
689
  else messageToast("Chargement du modèle…");
690
  }
691
  })();