MikaFil commited on
Commit
1e036fa
·
verified ·
1 Parent(s): c908cc8

Update viewer.js

Browse files
Files changed (1) hide show
  1. viewer.js +159 -142
viewer.js CHANGED
@@ -1,6 +1,6 @@
1
  // viewer.js
2
  // ==============================
3
- // PlayCanvas viewer: iOS/Safari canvas/render loop debug/fix edition
4
  // ==============================
5
 
6
  let pc; // will hold the PlayCanvas module once imported
@@ -114,7 +114,7 @@ export async function initializeViewer(config, instanceId) {
114
 
115
  try {
116
  // 6. Setup device & app
117
- if (isIOS || isSafari) alert("Attempting WebGL2 context creation...");
118
  const device = await pc.createGraphicsDevice(canvas, {
119
  deviceTypes: ["webgl2"],
120
  glslangUrl: "https://playcanvas.vercel.app/static/lib/glslang/glslang.js",
@@ -181,7 +181,7 @@ export async function initializeViewer(config, instanceId) {
181
  const loader = new pc.AssetListLoader(Object.values(assets), app.assets);
182
  let lastProg = 0;
183
  assets.model.on('load', () => {
184
- if (isIOS || isSafari) alert("PLY asset loaded!");
185
  progressDialog.style.display = 'none';
186
  });
187
  assets.model.on('error', err => {
@@ -202,152 +202,166 @@ export async function initializeViewer(config, instanceId) {
202
  }, 100);
203
 
204
  loader.load(async () => {
205
- if (isIOS || isSafari) alert("Asset loaded .load() finished, starting PlayCanvas app...");
206
- app.start();
207
- app.scene.envAtlas = assets.hdr.resource;
208
-
209
- // Model entity
210
- modelEntity = new pc.Entity('model');
211
- modelEntity.addComponent('gsplat', { asset: assets.model });
212
- modelEntity.setLocalPosition(modelX, modelY, modelZ);
213
- modelEntity.setLocalEulerAngles(modelRotationX, modelRotationY, modelRotationZ);
214
- modelEntity.setLocalScale(modelScale, modelScale, modelScale);
215
- app.root.addChild(modelEntity);
216
-
217
- // Light
218
- const dirLight = new pc.Entity('Cascaded Light');
219
- dirLight.addComponent('light', {
220
- type: 'directional',
221
- color: pc.Color.WHITE,
222
- shadowBias: 0.3,
223
- normalOffsetBias: 0.2,
224
- intensity: 1.0,
225
- soft: true,
226
- shadowResolution: 4096,
227
- penumbraSize: 7,
228
- penumbraFalloff: 1.5,
229
- shadowSamples: 128,
230
- shadowBlockerSamples: 16,
231
- castShadows: true,
232
- shadowType: pc.SHADOW_PCSS_32F,
233
- shadowDistance: 1000
234
- });
235
- dirLight.setLocalEulerAngles(0, 0, 0);
236
- app.root.addChild(dirLight);
237
-
238
- // Gallery GLB
239
- const galleryEntity = assets.galerie.resource.instantiateRenderEntity();
240
- app.root.addChild(galleryEntity);
241
-
242
- // Camera setup
243
- cameraEntity = new pc.Entity('camera');
244
- cameraEntity.addComponent('camera', {
245
- clearColor: config.canvas_background
246
- ? parseInt(config.canvas_background.substr(1, 2), 16) / 255
247
- : 0,
248
- });
249
- cameraEntity.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
250
- cameraEntity.lookAt(modelEntity.getPosition());
251
-
252
- cameraEntity.addComponent('script');
253
- cameraEntity.script.create('orbitCamera', {
254
- attributes: {
255
- inertiaFactor: 0.2,
256
- focusEntity: modelEntity,
257
- distanceMax: maxZoom,
258
- distanceMin: minZoom,
259
- pitchAngleMax: maxAngle,
260
- pitchAngleMin: minAngle,
261
- yawAngleMax: maxAzimuth,
262
- yawAngleMin: minAzimuth,
263
- minPivotY: minPivotY,
264
- frameOnStart: false
265
- }
266
- });
267
- cameraEntity.script.create('orbitCameraInputMouse', {
268
- attributes: {
269
- orbitSensitivity: isMobile ? 0.6 : 0.3,
270
- distanceSensitivity: isMobile ? 0.5 : 0.4
271
- }
272
- });
273
- if (cameraEntity.script.orbitCameraInputMouse) {
274
- cameraEntity.script.orbitCameraInputMouse.onMouseWheel = function() {};
275
- }
276
- cameraEntity.script.create('orbitCameraInputTouch', {
277
- attributes: {
278
- orbitSensitivity: 0.6,
279
- distanceSensitivity: 0.5
280
- }
281
- });
282
- app.root.addChild(cameraEntity);
283
-
284
- // Camera reset/scene visible
285
- app.once('update', () => {
286
- resetViewerCamera();
287
- if (isIOS || isSafari) alert("Camera reset to defaults");
288
- });
289
-
290
- // --- MAIN: Insert debug 'prerender' hook (fires before *every* frame render) ---
291
- let prerenderAlerted = false;
292
- app.on('prerender', function () {
293
- if ((isIOS || isSafari) && !prerenderAlerted) {
294
- prerenderAlerted = true;
295
- // Additional test: dump framebuffer size and context info
296
- const gl = app.graphicsDevice.gl;
297
- let glInfo = "";
298
- try {
299
- glInfo = gl ? "WebGL context exists, viewport: " + gl.drawingBufferWidth + "x" + gl.drawingBufferHeight : "No GL context";
300
- } catch (e) {}
301
- alert("[viewer.js] prerender: FIRST draw! " + glInfo);
302
- console.log("[viewer.js] prerender: FIRST draw!", glInfo);
303
- }
304
- });
305
-
306
- app.on('update', dt => {
307
- if (cameraEntity) {
308
- const pos = cameraEntity.getPosition();
309
- if (pos.y < minY) {
310
- cameraEntity.setPosition(pos.x, minY, pos.z);
311
  }
 
 
 
312
  }
313
- });
314
-
315
- // --- iOS/Safari workaround: force resize after delay in case initial canvas size is 0x0 ---
316
- if (isIOS || isSafari) {
317
- setTimeout(() => {
318
- try {
319
- canvas.width = viewerContainer.clientWidth || 320;
320
- canvas.height = viewerContainer.clientHeight || 240;
321
- app.resizeCanvas(canvas.width, canvas.height);
322
- console.log("[viewer.js] iOS canvas forced resize:", canvas.width, canvas.height);
323
- } catch (e) {
324
- console.warn("[viewer.js] iOS resize workaround failed:", e);
325
  }
326
- }, 350);
327
- } else {
328
- app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
329
- }
330
 
331
- // Tooltips
332
- try {
333
- const tooltipsModule = await import('./tooltips.js');
334
- tooltipsModule.initializeTooltips({
335
- app,
336
- cameraEntity,
337
- modelEntity,
338
- tooltipsUrl: config.tooltips_url,
339
- defaultVisible: !!config.showTooltipsDefault,
340
- moveDuration: config.tooltipMoveDuration || 0.6
341
  });
342
- if (isIOS || isSafari) alert("Tooltips loaded");
343
- } catch (e) {
344
- console.error("Error loading tooltips.js:", e);
345
- }
346
 
347
- progressDialog.style.display = 'none';
348
- viewerInitialized = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
349
 
350
- if (isIOS || isSafari) alert("Viewer is fully initialized!");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
351
  });
352
 
353
  } catch (error) {
@@ -398,7 +412,9 @@ export function resetViewerCamera() {
398
  orbitCam._updatePosition && orbitCam._updatePosition();
399
 
400
  tempEnt.destroy();
 
401
  } catch (e) {
 
402
  console.error("Error resetting camera:", e);
403
  }
404
  }
@@ -414,6 +430,7 @@ export function cleanupViewer() {
414
  modelEntity = null;
415
  viewerInitialized = false;
416
 
 
417
  if (resizeObserver) {
418
  resizeObserver.disconnect();
419
  resizeObserver = null;
 
1
  // viewer.js
2
  // ==============================
3
+ // PlayCanvas viewer: iOS/Safari deep step-by-step debug edition
4
  // ==============================
5
 
6
  let pc; // will hold the PlayCanvas module once imported
 
114
 
115
  try {
116
  // 6. Setup device & app
117
+ if (isIOS || isSafari) alert("Attemptiong WebGL2 context creation...");
118
  const device = await pc.createGraphicsDevice(canvas, {
119
  deviceTypes: ["webgl2"],
120
  glslangUrl: "https://playcanvas.vercel.app/static/lib/glslang/glslang.js",
 
181
  const loader = new pc.AssetListLoader(Object.values(assets), app.assets);
182
  let lastProg = 0;
183
  assets.model.on('load', () => {
184
+ if (isIOS || isSafari) alert("[viewer.js] model asset loaded");
185
  progressDialog.style.display = 'none';
186
  });
187
  assets.model.on('error', err => {
 
202
  }, 100);
203
 
204
  loader.load(async () => {
205
+ try {
206
+ if (isIOS || isSafari) alert("[viewer.js] loader.load callback: assets ready!");
207
+
208
+ app.start();
209
+ if (isIOS || isSafari) alert("[viewer.js] app.start() called");
210
+
211
+ app.scene.envAtlas = assets.hdr.resource;
212
+ if (isIOS || isSafari) alert("[viewer.js] HDR environment applied");
213
+
214
+ // Model entity
215
+ modelEntity = new pc.Entity('model');
216
+ modelEntity.addComponent('gsplat', { asset: assets.model });
217
+ modelEntity.setLocalPosition(modelX, modelY, modelZ);
218
+ modelEntity.setLocalEulerAngles(modelRotationX, modelRotationY, modelRotationZ);
219
+ modelEntity.setLocalScale(modelScale, modelScale, modelScale);
220
+ app.root.addChild(modelEntity);
221
+ if (isIOS || isSafari) alert("[viewer.js] Model entity created and added to scene");
222
+
223
+ // Light
224
+ const dirLight = new pc.Entity('Cascaded Light');
225
+ dirLight.addComponent('light', {
226
+ type: 'directional',
227
+ color: pc.Color.WHITE,
228
+ shadowBias: 0.3,
229
+ normalOffsetBias: 0.2,
230
+ intensity: 1.0,
231
+ soft: true,
232
+ shadowResolution: 4096,
233
+ penumbraSize: 7,
234
+ penumbraFalloff: 1.5,
235
+ shadowSamples: 128,
236
+ shadowBlockerSamples: 16,
237
+ castShadows: true,
238
+ shadowType: pc.SHADOW_PCSS_32F,
239
+ shadowDistance: 1000
240
+ });
241
+ dirLight.setLocalEulerAngles(0, 0, 0);
242
+ app.root.addChild(dirLight);
243
+ if (isIOS || isSafari) alert("[viewer.js] Directional light added");
244
+
245
+ // Gallery GLB
246
+ const galleryEntity = assets.galerie.resource.instantiateRenderEntity();
247
+ app.root.addChild(galleryEntity);
248
+ if (isIOS || isSafari) alert("[viewer.js] Gallery (GLB) entity added");
249
+
250
+ // Camera setup
251
+ cameraEntity = new pc.Entity('camera');
252
+ cameraEntity.addComponent('camera', {
253
+ clearColor: config.canvas_background
254
+ ? parseInt(config.canvas_background.substr(1, 2), 16) / 255
255
+ : 0,
256
+ });
257
+ cameraEntity.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
258
+ cameraEntity.lookAt(modelEntity.getPosition());
259
+
260
+ cameraEntity.addComponent('script');
261
+ cameraEntity.script.create('orbitCamera', {
262
+ attributes: {
263
+ inertiaFactor: 0.2,
264
+ focusEntity: modelEntity,
265
+ distanceMax: maxZoom,
266
+ distanceMin: minZoom,
267
+ pitchAngleMax: maxAngle,
268
+ pitchAngleMin: minAngle,
269
+ yawAngleMax: maxAzimuth,
270
+ yawAngleMin: minAzimuth,
271
+ minPivotY: minPivotY,
272
+ frameOnStart: false
273
+ }
274
+ });
275
+ cameraEntity.script.create('orbitCameraInputMouse', {
276
+ attributes: {
277
+ orbitSensitivity: isMobile ? 0.6 : 0.3,
278
+ distanceSensitivity: isMobile ? 0.5 : 0.4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  }
280
+ });
281
+ if (cameraEntity.script.orbitCameraInputMouse) {
282
+ cameraEntity.script.orbitCameraInputMouse.onMouseWheel = function() {};
283
  }
284
+ cameraEntity.script.create('orbitCameraInputTouch', {
285
+ attributes: {
286
+ orbitSensitivity: 0.6,
287
+ distanceSensitivity: 0.5
 
 
 
 
 
 
 
 
288
  }
289
+ });
290
+ app.root.addChild(cameraEntity);
291
+ if (isIOS || isSafari) alert("[viewer.js] Camera entity created, configured and added to scene");
 
292
 
293
+ // Camera reset/scene visible
294
+ app.once('update', () => {
295
+ resetViewerCamera();
296
+ if (isIOS || isSafari) alert("[viewer.js] Camera reset to defaults after first update");
 
 
 
 
 
 
297
  });
 
 
 
 
298
 
299
+ // --- MAIN: Insert debug 'prerender' hook (fires before *every* frame render) ---
300
+ let prerenderAlerted = false;
301
+ app.on('prerender', function () {
302
+ if ((isIOS || isSafari) && !prerenderAlerted) {
303
+ prerenderAlerted = true;
304
+ const gl = app.graphicsDevice.gl;
305
+ let glInfo = "";
306
+ try {
307
+ glInfo = gl ? "WebGL context exists, viewport: " + gl.drawingBufferWidth + "x" + gl.drawingBufferHeight : "No GL context";
308
+ } catch (e) {}
309
+ alert("[viewer.js] prerender: FIRST draw! " + glInfo);
310
+ console.log("[viewer.js] prerender: FIRST draw!", glInfo);
311
+ }
312
+ });
313
+
314
+ app.on('update', dt => {
315
+ if (cameraEntity) {
316
+ const pos = cameraEntity.getPosition();
317
+ if (pos.y < minY) {
318
+ cameraEntity.setPosition(pos.x, minY, pos.z);
319
+ }
320
+ }
321
+ });
322
 
323
+ // --- iOS/Safari workaround: force resize after delay in case initial canvas size is 0x0 ---
324
+ if (isIOS || isSafari) {
325
+ setTimeout(() => {
326
+ try {
327
+ canvas.width = viewerContainer.clientWidth || 320;
328
+ canvas.height = viewerContainer.clientHeight || 240;
329
+ app.resizeCanvas(canvas.width, canvas.height);
330
+ console.log("[viewer.js] iOS canvas forced resize:", canvas.width, canvas.height);
331
+ } catch (e) {
332
+ console.warn("[viewer.js] iOS resize workaround failed:", e);
333
+ }
334
+ }, 350);
335
+ } else {
336
+ app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
337
+ }
338
+
339
+ // Tooltips
340
+ try {
341
+ const tooltipsModule = await import('./tooltips.js');
342
+ tooltipsModule.initializeTooltips({
343
+ app,
344
+ cameraEntity,
345
+ modelEntity,
346
+ tooltipsUrl: config.tooltips_url,
347
+ defaultVisible: !!config.showTooltipsDefault,
348
+ moveDuration: config.tooltipMoveDuration || 0.6
349
+ });
350
+ if (isIOS || isSafari) alert("[viewer.js] Tooltips loaded");
351
+ } catch (e) {
352
+ if (isIOS || isSafari) alert("[viewer.js] Error loading tooltips.js: " + e);
353
+ console.error("Error loading tooltips.js:", e);
354
+ }
355
+
356
+ progressDialog.style.display = 'none';
357
+ viewerInitialized = true;
358
+ if (isIOS || isSafari) alert("[viewer.js] Viewer is fully initialized!");
359
+
360
+ } catch (innerErr) {
361
+ alert("[viewer.js] ERROR during scene setup: " + (innerErr && innerErr.message ? innerErr.message : innerErr));
362
+ console.error("[viewer.js] Scene setup error:", innerErr);
363
+ throw innerErr;
364
+ }
365
  });
366
 
367
  } catch (error) {
 
412
  orbitCam._updatePosition && orbitCam._updatePosition();
413
 
414
  tempEnt.destroy();
415
+ if (isIOSorSafari()) alert("[viewer.js] Camera reset to defaults");
416
  } catch (e) {
417
+ alert("[viewer.js] Error resetting camera: " + e);
418
  console.error("Error resetting camera:", e);
419
  }
420
  }
 
430
  modelEntity = null;
431
  viewerInitialized = false;
432
 
433
+ // Disconnect the ResizeObserver to avoid leaks
434
  if (resizeObserver) {
435
  resizeObserver.disconnect();
436
  resizeObserver = null;