Update viewer_ar_ios.js
Browse files- viewer_ar_ios.js +42 -75
viewer_ar_ios.js
CHANGED
|
@@ -1,23 +1,23 @@
|
|
| 1 |
-
/*
|
| 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 (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 |
*/
|
| 8 |
|
| 9 |
(function () {
|
| 10 |
-
// =====
|
| 11 |
-
function getCurrentScript() {
|
| 12 |
-
// robuste même si currentScript n'est pas dispo
|
| 13 |
-
return document.currentScript || (function () {
|
| 14 |
-
var scripts = document.getElementsByTagName('script');
|
| 15 |
-
return scripts[scripts.length - 1] || null;
|
| 16 |
-
})();
|
| 17 |
-
}
|
| 18 |
-
|
| 19 |
function findConfigUrl() {
|
| 20 |
-
var el =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
if (!el) return null;
|
| 22 |
var url = el.getAttribute('data-config');
|
| 23 |
return url || null;
|
|
@@ -46,7 +46,7 @@
|
|
| 46 |
}
|
| 47 |
}
|
| 48 |
|
| 49 |
-
// =====
|
| 50 |
var PC_VERSION = "2.11.7";
|
| 51 |
var PC_URLS = {
|
| 52 |
esm: ["https://cdn.jsdelivr.net/npm/playcanvas@" + PC_VERSION + "/build/playcanvas.min.mjs"],
|
|
@@ -105,10 +105,10 @@
|
|
| 105 |
}
|
| 106 |
}
|
| 107 |
|
| 108 |
-
// =====
|
| 109 |
var css = [
|
| 110 |
-
".pc-ar-msg{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:
|
| 111 |
-
"#xr-overlay-root{position:fixed;inset:0;z-index:
|
| 112 |
|
| 113 |
".ar-ui{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}",
|
| 114 |
".ar-ui .label{font-size:12px;text-align:center;opacity:.95}",
|
|
@@ -119,7 +119,7 @@
|
|
| 119 |
".ar-ui .val{font-size:12px;opacity:.95}",
|
| 120 |
|
| 121 |
/* iOS Quick Look button */
|
| 122 |
-
"#ios-quicklook-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:
|
| 123 |
"#ios-quicklook-btn img{display:block;height:44px;width:auto}"
|
| 124 |
].join("\n");
|
| 125 |
var styleTag = document.createElement("style");
|
|
@@ -147,7 +147,7 @@
|
|
| 147 |
el.textContent = msg;
|
| 148 |
}
|
| 149 |
|
| 150 |
-
//
|
| 151 |
function buildQuickLookHref(usdzUrl) {
|
| 152 |
try {
|
| 153 |
var u = new URL(usdzUrl, window.location.href);
|
|
@@ -168,7 +168,7 @@
|
|
| 168 |
var anchor = document.createElement("a");
|
| 169 |
anchor.id = "ios-quicklook-btn";
|
| 170 |
anchor.setAttribute("rel", "ar");
|
| 171 |
-
anchor.setAttribute("href", buildQuickLookHref(USDZ_URL));
|
| 172 |
|
| 173 |
var img = document.createElement("img");
|
| 174 |
img.alt = "Voir en AR";
|
|
@@ -181,53 +181,16 @@
|
|
| 181 |
return anchor;
|
| 182 |
}
|
| 183 |
|
| 184 |
-
// ============ Canvas monté dans un conteneur contrôlé (Squarespace) ============
|
| 185 |
function ensureCanvas() {
|
| 186 |
-
var
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
if (!mountEl) {
|
| 194 |
-
// fallback : tout en haut du body (pour éviter "sous le footer")
|
| 195 |
-
mountEl = document.createElement('div');
|
| 196 |
-
mountEl.id = 'ar-mount-fallback';
|
| 197 |
-
document.body.insertBefore(mountEl, document.body.firstChild);
|
| 198 |
}
|
| 199 |
-
|
| 200 |
-
// Style du conteneur
|
| 201 |
-
var mountStyle = mountEl.style;
|
| 202 |
-
if (!mountStyle.position) mountStyle.position = 'relative';
|
| 203 |
-
mountStyle.width = mountStyle.width || '100%';
|
| 204 |
-
mountStyle.minHeight = mountStyle.minHeight || desiredHeight;
|
| 205 |
-
mountStyle.touchAction = mountStyle.touchAction || 'manipulation';
|
| 206 |
-
mountStyle.webkitTapHighlightColor = 'transparent';
|
| 207 |
-
|
| 208 |
-
// Réutilise ou crée le canvas
|
| 209 |
-
var canvas = mountEl.querySelector('#application-canvas');
|
| 210 |
-
if (!canvas) {
|
| 211 |
-
canvas = document.createElement('canvas');
|
| 212 |
-
canvas.id = 'application-canvas';
|
| 213 |
-
mountEl.appendChild(canvas);
|
| 214 |
-
}
|
| 215 |
-
|
| 216 |
-
// Le canvas remplit le conteneur
|
| 217 |
-
var cs = canvas.style;
|
| 218 |
-
cs.position = 'absolute';
|
| 219 |
-
cs.left = '0';
|
| 220 |
-
cs.top = '0';
|
| 221 |
-
cs.width = '100%';
|
| 222 |
-
cs.height = '100%';
|
| 223 |
-
cs.display = 'block';
|
| 224 |
-
|
| 225 |
-
// Optionnel : ramener le viewport sur le viewer
|
| 226 |
-
try {
|
| 227 |
-
mountEl.scrollIntoView({ behavior: 'instant', block: 'start' });
|
| 228 |
-
} catch (_) {}
|
| 229 |
-
|
| 230 |
-
return canvas;
|
| 231 |
}
|
| 232 |
|
| 233 |
function ensureSliderUI() {
|
|
@@ -247,8 +210,9 @@
|
|
| 247 |
return p;
|
| 248 |
}
|
| 249 |
|
| 250 |
-
// =====
|
| 251 |
(async function () {
|
|
|
|
| 252 |
var cfgUrl = findConfigUrl();
|
| 253 |
var cfg = await loadConfigJson(cfgUrl);
|
| 254 |
var GLB_URL = (cfg && typeof cfg.glb_url === "string" && cfg.glb_url) ?
|
|
@@ -258,6 +222,7 @@
|
|
| 258 |
cfg.usdz_url :
|
| 259 |
null;
|
| 260 |
|
|
|
|
| 261 |
if (isIOS()) {
|
| 262 |
if (USDZ_URL) {
|
| 263 |
ensureQuickLookButton(USDZ_URL);
|
|
@@ -265,9 +230,11 @@
|
|
| 265 |
} else {
|
| 266 |
message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
|
| 267 |
}
|
|
|
|
| 268 |
return;
|
| 269 |
}
|
| 270 |
|
|
|
|
| 271 |
try {
|
| 272 |
await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
|
| 273 |
} catch (e) {
|
|
@@ -278,7 +245,7 @@
|
|
| 278 |
initARApp(GLB_URL);
|
| 279 |
})();
|
| 280 |
|
| 281 |
-
// =====
|
| 282 |
function initARApp(GLB_URL) {
|
| 283 |
var pc = window.pc;
|
| 284 |
var canvas = ensureCanvas();
|
|
@@ -299,13 +266,12 @@
|
|
| 299 |
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
|
| 300 |
app.setCanvasResolution(pc.RESOLUTION_AUTO);
|
| 301 |
app.graphicsDevice.maxPixelRatio = window.devicePixelRatio || 1;
|
| 302 |
-
|
| 303 |
var onResize = function () { app.resizeCanvas(); };
|
| 304 |
window.addEventListener("resize", onResize);
|
| 305 |
app.on("destroy", function () { window.removeEventListener("resize", onResize); });
|
| 306 |
app.start();
|
| 307 |
|
| 308 |
-
// Rendu / PBR defaults
|
| 309 |
app.scene.gammaCorrection = pc.GAMMA_SRGB;
|
| 310 |
app.scene.toneMapping = pc.TONEMAP_ACES;
|
| 311 |
app.scene.exposure = 1;
|
|
@@ -395,10 +361,10 @@
|
|
| 395 |
return e;
|
| 396 |
}
|
| 397 |
|
| 398 |
-
// Euler
|
| 399 |
var baseEulerX = 0, baseEulerZ = 0;
|
| 400 |
|
| 401 |
-
// Rotation via slider
|
| 402 |
var rotationYDeg = 0;
|
| 403 |
function clamp360(d) { return Math.max(0, Math.min(360, d)); }
|
| 404 |
|
|
@@ -421,14 +387,14 @@
|
|
| 421 |
if (rotLikePlane) blob.setRotation(rotLikePlane);
|
| 422 |
}
|
| 423 |
|
| 424 |
-
// Chargement GLB (
|
| 425 |
app.assets.loadFromUrl(GLB_URL, "container", function (err, asset) {
|
| 426 |
if (err) { console.error(err); message("Échec du chargement du modèle GLB."); return; }
|
| 427 |
var instance = asset.resource.instantiateRenderEntity({ castShadows: true, receiveShadows: false });
|
| 428 |
modelRoot.addChild(instance);
|
| 429 |
modelRoot.setLocalScale(1, 1, 1);
|
| 430 |
|
| 431 |
-
// Fix matériaux
|
| 432 |
var renders = instance.findComponents('render');
|
| 433 |
for (var ri = 0; ri < renders.length; ri++) {
|
| 434 |
var r = renders[ri];
|
|
@@ -453,7 +419,7 @@
|
|
| 453 |
|
| 454 |
if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
|
| 455 |
|
| 456 |
-
// Slider fiable
|
| 457 |
var uiInteracting = false;
|
| 458 |
var draggingWrap = false;
|
| 459 |
var activePointerId = null;
|
|
@@ -528,7 +494,7 @@
|
|
| 528 |
}
|
| 529 |
app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
|
| 530 |
|
| 531 |
-
// Hit-test HORIZONTAL uniquement
|
| 532 |
var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
|
| 533 |
function isHorizontalUpFacing(rot, minDot) {
|
| 534 |
minDot = (typeof minDot === "number") ? minDot : 0.75;
|
|
@@ -648,3 +614,4 @@
|
|
| 648 |
else message("Chargement du modèle…");
|
| 649 |
}
|
| 650 |
})();
|
|
|
|
|
|
| 1 |
+
/* script_ar.js — AR PlayCanvas + GLB/USDZ via config.json
|
| 2 |
- Lit config.json (data-config) => { "glb_url": "...", "usdz_url": "..." }
|
| 3 |
+
- iOS : fallback AR Quick Look (USDZ) avec #allowsContentScaling=0 (pas de zoom)
|
| 4 |
- Android/Desktop : WebXR AR (horizontaux uniquement) + slider yaw + blob shadow
|
| 5 |
- Éclairage PBR par défaut (sans WebXR light estimation)
|
|
|
|
| 6 |
*/
|
| 7 |
|
| 8 |
(function () {
|
| 9 |
+
// ===== Utils: config + platform =====
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
function findConfigUrl() {
|
| 11 |
+
var el = document.currentScript || null;
|
| 12 |
+
if (!el) {
|
| 13 |
+
var scripts = document.getElementsByTagName('script');
|
| 14 |
+
for (var i = scripts.length - 1; i >= 0; i--) {
|
| 15 |
+
if (scripts[i].getAttribute && scripts[i].getAttribute('data-config')) {
|
| 16 |
+
el = scripts[i];
|
| 17 |
+
break;
|
| 18 |
+
}
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
if (!el) return null;
|
| 22 |
var url = el.getAttribute('data-config');
|
| 23 |
return url || null;
|
|
|
|
| 46 |
}
|
| 47 |
}
|
| 48 |
|
| 49 |
+
// ===== PlayCanvas version fixée (Android/Desktop) =====
|
| 50 |
var PC_VERSION = "2.11.7";
|
| 51 |
var PC_URLS = {
|
| 52 |
esm: ["https://cdn.jsdelivr.net/npm/playcanvas@" + PC_VERSION + "/build/playcanvas.min.mjs"],
|
|
|
|
| 105 |
}
|
| 106 |
}
|
| 107 |
|
| 108 |
+
// ===== UI / Overlay commun =====
|
| 109 |
var css = [
|
| 110 |
+
".pc-ar-msg{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:2;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}",
|
| 111 |
+
"#xr-overlay-root{position:fixed;inset:0;z-index:9999;pointer-events:none}",
|
| 112 |
|
| 113 |
".ar-ui{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}",
|
| 114 |
".ar-ui .label{font-size:12px;text-align:center;opacity:.95}",
|
|
|
|
| 119 |
".ar-ui .val{font-size:12px;opacity:.95}",
|
| 120 |
|
| 121 |
/* iOS Quick Look button */
|
| 122 |
+
"#ios-quicklook-btn{position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:10001;display:inline-block;pointer-events:auto}",
|
| 123 |
"#ios-quicklook-btn img{display:block;height:44px;width:auto}"
|
| 124 |
].join("\n");
|
| 125 |
var styleTag = document.createElement("style");
|
|
|
|
| 147 |
el.textContent = msg;
|
| 148 |
}
|
| 149 |
|
| 150 |
+
// Construit l'URL Quick Look avec allowsContentScaling=0
|
| 151 |
function buildQuickLookHref(usdzUrl) {
|
| 152 |
try {
|
| 153 |
var u = new URL(usdzUrl, window.location.href);
|
|
|
|
| 168 |
var anchor = document.createElement("a");
|
| 169 |
anchor.id = "ios-quicklook-btn";
|
| 170 |
anchor.setAttribute("rel", "ar");
|
| 171 |
+
anchor.setAttribute("href", buildQuickLookHref(USDZ_URL)); // << blocage du scaling
|
| 172 |
|
| 173 |
var img = document.createElement("img");
|
| 174 |
img.alt = "Voir en AR";
|
|
|
|
| 181 |
return anchor;
|
| 182 |
}
|
| 183 |
|
|
|
|
| 184 |
function ensureCanvas() {
|
| 185 |
+
var c = document.getElementById("application-canvas");
|
| 186 |
+
if (!c) {
|
| 187 |
+
c = document.createElement("canvas");
|
| 188 |
+
c.id = "application-canvas";
|
| 189 |
+
c.style.width = "100%";
|
| 190 |
+
c.style.height = "100%";
|
| 191 |
+
document.body.appendChild(c);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 192 |
}
|
| 193 |
+
return c;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
}
|
| 195 |
|
| 196 |
function ensureSliderUI() {
|
|
|
|
| 210 |
return p;
|
| 211 |
}
|
| 212 |
|
| 213 |
+
// ===== Boot : charge config, route iOS vs Android/Desktop =====
|
| 214 |
(async function () {
|
| 215 |
+
// 1) Lire config.json
|
| 216 |
var cfgUrl = findConfigUrl();
|
| 217 |
var cfg = await loadConfigJson(cfgUrl);
|
| 218 |
var GLB_URL = (cfg && typeof cfg.glb_url === "string" && cfg.glb_url) ?
|
|
|
|
| 222 |
cfg.usdz_url :
|
| 223 |
null;
|
| 224 |
|
| 225 |
+
// 2) iOS → AR Quick Look (fallback)
|
| 226 |
if (isIOS()) {
|
| 227 |
if (USDZ_URL) {
|
| 228 |
ensureQuickLookButton(USDZ_URL);
|
|
|
|
| 230 |
} else {
|
| 231 |
message("iOS détecté, mais aucun 'usdz_url' dans config.json.");
|
| 232 |
}
|
| 233 |
+
// Option : lancer un viewer 3D non-AR ici si désiré.
|
| 234 |
return;
|
| 235 |
}
|
| 236 |
|
| 237 |
+
// 3) Android/Desktop → charger PlayCanvas et lancer l'app WebXR
|
| 238 |
try {
|
| 239 |
await loadPlayCanvasRobust({ esmFirst: true, loadTimeoutMs: 15000 });
|
| 240 |
} catch (e) {
|
|
|
|
| 245 |
initARApp(GLB_URL);
|
| 246 |
})();
|
| 247 |
|
| 248 |
+
// ===== App Android/Desktop (WebXR) =====
|
| 249 |
function initARApp(GLB_URL) {
|
| 250 |
var pc = window.pc;
|
| 251 |
var canvas = ensureCanvas();
|
|
|
|
| 266 |
app.setCanvasFillMode(pc.FILLMODE_FILL_WINDOW);
|
| 267 |
app.setCanvasResolution(pc.RESOLUTION_AUTO);
|
| 268 |
app.graphicsDevice.maxPixelRatio = window.devicePixelRatio || 1;
|
|
|
|
| 269 |
var onResize = function () { app.resizeCanvas(); };
|
| 270 |
window.addEventListener("resize", onResize);
|
| 271 |
app.on("destroy", function () { window.removeEventListener("resize", onResize); });
|
| 272 |
app.start();
|
| 273 |
|
| 274 |
+
// ===== Rendu / PBR defaults =====
|
| 275 |
app.scene.gammaCorrection = pc.GAMMA_SRGB;
|
| 276 |
app.scene.toneMapping = pc.TONEMAP_ACES;
|
| 277 |
app.scene.exposure = 1;
|
|
|
|
| 361 |
return e;
|
| 362 |
}
|
| 363 |
|
| 364 |
+
// Euler base
|
| 365 |
var baseEulerX = 0, baseEulerZ = 0;
|
| 366 |
|
| 367 |
+
// Rotation via slider
|
| 368 |
var rotationYDeg = 0;
|
| 369 |
function clamp360(d) { return Math.max(0, Math.min(360, d)); }
|
| 370 |
|
|
|
|
| 387 |
if (rotLikePlane) blob.setRotation(rotLikePlane);
|
| 388 |
}
|
| 389 |
|
| 390 |
+
// Chargement GLB (config.json)
|
| 391 |
app.assets.loadFromUrl(GLB_URL, "container", function (err, asset) {
|
| 392 |
if (err) { console.error(err); message("Échec du chargement du modèle GLB."); return; }
|
| 393 |
var instance = asset.resource.instantiateRenderEntity({ castShadows: true, receiveShadows: false });
|
| 394 |
modelRoot.addChild(instance);
|
| 395 |
modelRoot.setLocalScale(1, 1, 1);
|
| 396 |
|
| 397 |
+
// Fix matériaux
|
| 398 |
var renders = instance.findComponents('render');
|
| 399 |
for (var ri = 0; ri < renders.length; ri++) {
|
| 400 |
var r = renders[ri];
|
|
|
|
| 419 |
|
| 420 |
if (!app.xr.supported) { message("WebXR n’est pas supporté sur cet appareil."); return; }
|
| 421 |
|
| 422 |
+
// ===== Slider fiable : Pointer Events en CAPTURE =====
|
| 423 |
var uiInteracting = false;
|
| 424 |
var draggingWrap = false;
|
| 425 |
var activePointerId = null;
|
|
|
|
| 494 |
}
|
| 495 |
app.keyboard.on("keydown", function (evt) { if (evt.key === pc.KEY_ESCAPE && app.xr.active) app.xr.end(); });
|
| 496 |
|
| 497 |
+
// ====== Hit-test HORIZONTAL uniquement ======
|
| 498 |
var TMP_IN = new pc.Vec3(0, 1, 0), TMP_OUT = new pc.Vec3();
|
| 499 |
function isHorizontalUpFacing(rot, minDot) {
|
| 500 |
minDot = (typeof minDot === "number") ? minDot : 0.75;
|
|
|
|
| 614 |
else message("Chargement du modèle…");
|
| 615 |
}
|
| 616 |
})();
|
| 617 |
+
|