MikaFil commited on
Commit
51a6b8f
·
verified ·
1 Parent(s): 01af695

Update viewer.js

Browse files
Files changed (1) hide show
  1. viewer.js +166 -178
viewer.js CHANGED
@@ -1,5 +1,5 @@
1
  // viewer.js
2
- // Modern PlayCanvas 2.8.1+ with SOGS/GSplat
3
  import * as pc from 'https://cdn.jsdelivr.net/npm/playcanvas@2.8.1/build/playcanvas.module.js';
4
 
5
  export let app = null;
@@ -14,167 +14,166 @@ let minZoom, maxZoom, minAngle, maxAngle, minAzimuth, maxAzimuth, minPivotY, min
14
  let modelX, modelY, modelZ, modelScale, modelRotationX, modelRotationY, modelRotationZ;
15
 
16
  export async function initializeViewer(config, instanceId) {
17
- try {
18
- alert('viewer.js: initializeViewer called');
19
- if (viewerInitialized) {
20
- alert('viewer.js: already initialized');
21
- return;
22
- }
23
- if (!config) {
24
- alert('viewer.js: config is missing!');
25
- return;
26
- }
27
 
28
- // Params
29
- const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
30
- const isMobile = isIOS || /Android/i.test(navigator.userAgent);
 
31
 
32
- // URLs and config
33
- const sogsUrl = config.sogs_json_url;
34
- if (!sogsUrl) {
35
- alert('Missing SOGS (meta.json) URL in config.sogs_json_url.');
36
- return;
37
- }
38
- alert('sogsUrl: ' + sogsUrl);
39
-
40
- minZoom = parseFloat(config.minZoom || "1");
41
- maxZoom = parseFloat(config.maxZoom || "20");
42
- minAngle = parseFloat(config.minAngle || "-45");
43
- maxAngle = parseFloat(config.maxAngle || "90");
44
- minAzimuth = (config.minAzimuth !== undefined) ? parseFloat(config.minAzimuth) : -360;
45
- maxAzimuth = (config.maxAzimuth !== undefined) ? parseFloat(config.maxAzimuth) : 360;
46
- minPivotY = parseFloat(config.minPivotY || "0");
47
- minY = (config.minY !== undefined) ? parseFloat(config.minY) : 0;
48
-
49
- modelX = (config.modelX !== undefined) ? parseFloat(config.modelX) : 0;
50
- modelY = (config.modelY !== undefined) ? parseFloat(config.modelY) : 0;
51
- modelZ = (config.modelZ !== undefined) ? parseFloat(config.modelZ) : 0;
52
- modelScale = (config.modelScale !== undefined) ? parseFloat(config.modelScale) : 1;
53
- modelRotationX = (config.modelRotationX !== undefined) ? parseFloat(config.modelRotationX) : 0;
54
- modelRotationY = (config.modelRotationY !== undefined) ? parseFloat(config.modelRotationY) : 0;
55
- modelRotationZ = (config.modelRotationZ !== undefined) ? parseFloat(config.modelRotationZ) : 0;
56
-
57
- const cameraX = (config.cameraX !== undefined) ? parseFloat(config.cameraX) : 0;
58
- const cameraY = (config.cameraY !== undefined) ? parseFloat(config.cameraY) : 2;
59
- const cameraZ = (config.cameraZ !== undefined) ? parseFloat(config.cameraZ) : 5;
60
- const cameraXPhone = (config.cameraXPhone !== undefined) ? parseFloat(config.cameraXPhone) : cameraX;
61
- const cameraYPhone = (config.cameraYPhone !== undefined) ? parseFloat(config.cameraYPhone) : cameraY;
62
- const cameraZPhone = (config.cameraZPhone !== undefined) ? parseFloat(config.cameraZPhone) : (cameraZ * 1.5);
63
-
64
- chosenCameraX = isMobile ? cameraXPhone : cameraX;
65
- chosenCameraY = isMobile ? cameraYPhone : cameraY;
66
- chosenCameraZ = isMobile ? cameraZPhone : cameraZ;
67
-
68
- // DOM Elements
69
- const canvasId = 'canvas-' + instanceId;
70
- const progressDialog = document.getElementById('progress-dialog-' + instanceId);
71
- const viewerContainer = document.getElementById('viewer-container-' + instanceId);
72
-
73
- alert('viewer.js: DOM elements - canvasId: ' + canvasId);
74
-
75
- if (!viewerContainer) {
76
- alert('viewer.js: viewerContainer not found!');
77
- return;
78
- }
79
 
80
- // Remove old canvas if any
81
- let oldCanvas = document.getElementById(canvasId);
82
- if (oldCanvas) oldCanvas.remove();
83
-
84
- // Create and add canvas
85
- const canvas = document.createElement('canvas');
86
- canvas.id = canvasId;
87
- canvas.className = 'ply-canvas';
88
- canvas.style.width = "100%";
89
- canvas.style.height = "100%";
90
- canvas.setAttribute('tabindex', '0');
91
- viewerContainer.insertBefore(canvas, progressDialog);
92
- canvas.style.touchAction = "none";
93
- canvas.style.webkitTouchCallout = "none";
94
- canvas.addEventListener('gesturestart', e => e.preventDefault());
95
- canvas.addEventListener('gesturechange', e => e.preventDefault());
96
- canvas.addEventListener('gestureend', e => e.preventDefault());
97
- canvas.addEventListener('dblclick', e => e.preventDefault());
98
- canvas.addEventListener('touchstart', e => { if (e.touches.length > 1) e.preventDefault(); }, { passive: false });
99
- canvas.addEventListener('wheel', (e) => { e.preventDefault(); }, { passive: false });
100
-
101
- alert('viewer.js: Canvas created and inserted.');
102
-
103
- if (progressDialog) {
104
- progressDialog.style.display = 'block';
105
- } else {
106
- alert('viewer.js: progressDialog not found!');
107
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
- // --- PlayCanvas Graphics Device ---
110
- alert('viewer.js: creating graphics device...');
111
- const device = await pc.createGraphicsDevice(canvas, {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  deviceTypes: ["webgl2"],
113
  antialias: false,
114
  glslangUrl: "https://playcanvas.vercel.app/static/lib/glslang/glslang.js",
115
  twgslUrl: "https://playcanvas.vercel.app/static/lib/twgsl/twgsl.js"
116
  });
117
- device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
118
- alert('viewer.js: Graphics device created!');
119
-
120
- // --- PlayCanvas AppBase (modern, 2.8.1+) ---
121
- alert('viewer.js: Creating AppBase...');
122
- const appOpts = new pc.AppOptions();
123
- appOpts.graphicsDevice = device;
124
- appOpts.mouse = new pc.Mouse(canvas);
125
- appOpts.touch = new pc.TouchDevice(canvas);
126
- appOpts.componentSystems = [
127
- pc.RenderComponentSystem,
128
- pc.CameraComponentSystem,
129
- pc.LightComponentSystem,
130
- pc.ScriptComponentSystem,
131
- pc.GSplatComponentSystem
132
- ];
133
- appOpts.resourceHandlers = [
134
- pc.TextureHandler,
135
- pc.ContainerHandler,
136
- pc.ScriptHandler,
137
- pc.GSplatHandler
138
- ];
139
-
140
- app = new pc.AppBase(canvas);
141
- app.init(appOpts);
142
-
143
- alert('viewer.js: AppBase created and initialized!');
144
-
145
- // Fill/resize
146
- app.setCanvasFillMode(pc.FILLMODE_NONE);
147
- app.setCanvasResolution(pc.RESOLUTION_AUTO);
148
-
149
- resizeObserver = new ResizeObserver(entries => {
150
- entries.forEach(entry => {
151
- app.resizeCanvas(entry.contentRect.width, entry.contentRect.height);
152
- });
 
153
  });
154
- resizeObserver.observe(viewerContainer);
155
-
156
- window.addEventListener('resize', () => app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight));
157
- app.on('destroy', () => resizeObserver.disconnect());
158
-
159
- // --- ASSETS (GSplat + Orbit camera) ---
160
- alert('viewer.js: Creating GSplat and orbit assets...');
161
- const assets = {
162
- model: new pc.Asset('gsplat', 'gsplat', { url: sogsUrl }),
163
- orbit: new pc.Asset('orbit', 'script', { url: "https://mikafil-viewer-sgos.static.hf.space/orbit-camera.js" }),
164
- };
165
- for (const key in assets) app.assets.add(assets[key]);
166
-
167
- alert('viewer.js: Assets created, starting AssetListLoader...');
168
-
169
- const loader = new pc.AssetListLoader(Object.values(assets), app.assets);
170
-
171
- loader.load(() => {
172
- alert('viewer.js: AssetListLoader finished loading assets!');
173
- app.start();
174
- if (progressDialog) progressDialog.style.display = 'none';
175
 
 
 
 
 
 
176
  // --- Add GSplat Model ---
177
- alert('viewer.js: Creating modelEntity and adding gsplat...');
178
  modelEntity = new pc.Entity('model');
179
  modelEntity.addComponent('gsplat', { asset: assets.model });
180
  modelEntity.setLocalPosition(modelX, modelY, modelZ);
@@ -182,8 +181,8 @@ export async function initializeViewer(config, instanceId) {
182
  modelEntity.setLocalScale(modelScale, modelScale, modelScale);
183
  app.root.addChild(modelEntity);
184
 
 
185
  // --- Camera ---
186
- alert('viewer.js: Creating camera entity...');
187
  cameraEntity = new pc.Entity('camera');
188
  cameraEntity.addComponent('camera', {
189
  clearColor: new pc.Color(1, 1, 1, 1)
@@ -209,19 +208,18 @@ export async function initializeViewer(config, instanceId) {
209
  cameraEntity.script.create('orbitCameraInputTouch');
210
  app.root.addChild(cameraEntity);
211
 
212
- alert('viewer.js: Camera entity created and added.');
 
 
213
 
214
  app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
215
- app.once('update', () => {
216
- alert('viewer.js: calling resetViewerCamera');
217
- resetViewerCamera();
218
- });
219
 
220
  // --- Tooltips ---
221
  try {
222
  if (config.tooltips_url) {
 
223
  import('./tooltips.js').then(tooltipsModule => {
224
- alert('viewer.js: tooltips.js loaded!');
225
  tooltipsModule.initializeTooltips({
226
  app,
227
  cameraEntity,
@@ -230,40 +228,30 @@ export async function initializeViewer(config, instanceId) {
230
  defaultVisible: !!config.showTooltipsDefault,
231
  moveDuration: config.tooltipMoveDuration || 0.6
232
  });
 
233
  }).catch(e => {
234
- alert('viewer.js: Error loading tooltips.js: ' + e);
235
- console.error(e);
236
  });
237
  }
238
  } catch (e) {
239
- alert('viewer.js: Exception importing tooltips: ' + e);
240
  }
241
 
242
  viewerInitialized = true;
243
- alert('viewer.js: viewerInitialized = true!');
244
- });
245
-
246
- loader.on('error', function(err, asset) {
247
- alert('viewer.js: Asset loader error: ' + err + (asset ? ' for asset: ' + asset.name : ''));
248
- console.error('Asset loader error:', err, asset);
249
- });
250
-
251
- loader.on('progress', function(loaded, total) {
252
- console.log(`viewer.js: Asset loader progress: ${loaded} / ${total}`);
253
- });
254
 
255
- } catch (e) {
256
- alert('viewer.js: FATAL exception: ' + (e.message || e));
257
- console.error(e);
258
- }
 
259
  }
260
 
261
  // Reset camera helper
262
  export function resetViewerCamera() {
263
  try {
264
- alert('viewer.js: resetViewerCamera called');
265
  if (!cameraEntity || !modelEntity || !app) {
266
- alert('resetViewerCamera: cameraEntity/modelEntity/app missing');
267
  return;
268
  }
269
  const orbitCam = cameraEntity.script.orbitCamera;
@@ -307,7 +295,7 @@ export function resetViewerCamera() {
307
  if (orbitCam._updatePosition) orbitCam._updatePosition();
308
 
309
  tempEnt.destroy();
310
- alert('resetViewerCamera: success');
311
  } catch (e) {
312
  alert('resetViewerCamera: Exception: ' + (e.message || e));
313
  // Silent fail
 
1
  // viewer.js
2
+ // Modern PlayCanvas 2.8.1+ with SOGS/GSplat, full debug version
3
  import * as pc from 'https://cdn.jsdelivr.net/npm/playcanvas@2.8.1/build/playcanvas.module.js';
4
 
5
  export let app = null;
 
14
  let modelX, modelY, modelZ, modelScale, modelRotationX, modelRotationY, modelRotationZ;
15
 
16
  export async function initializeViewer(config, instanceId) {
17
+ alert('viewer.js: initializeViewer called');
18
+ console.log('viewer.js: initializeViewer called', config, instanceId);
 
 
 
 
 
 
 
 
19
 
20
+ if (viewerInitialized) {
21
+ alert('viewer.js: viewerInitialized already true, exiting.');
22
+ return;
23
+ }
24
 
25
+ // Params
26
+ alert('viewer.js: About to parse config');
27
+ const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
28
+ const isMobile = isIOS || /Android/i.test(navigator.userAgent);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
+ const sogsUrl = config.sogs_json_url;
31
+ alert('viewer.js: sogsUrl = ' + sogsUrl);
32
+
33
+ if (!sogsUrl) {
34
+ alert('Missing SOGS (meta.json) URL in config.sogs_json_url.');
35
+ return;
36
+ }
37
+
38
+ // Parse config
39
+ minZoom = parseFloat(config.minZoom || "1");
40
+ maxZoom = parseFloat(config.maxZoom || "20");
41
+ minAngle = parseFloat(config.minAngle || "-45");
42
+ maxAngle = parseFloat(config.maxAngle || "90");
43
+ minAzimuth = (config.minAzimuth !== undefined) ? parseFloat(config.minAzimuth) : -360;
44
+ maxAzimuth = (config.maxAzimuth !== undefined) ? parseFloat(config.maxAzimuth) : 360;
45
+ minPivotY = parseFloat(config.minPivotY || "0");
46
+ minY = (config.minY !== undefined) ? parseFloat(config.minY) : 0;
47
+
48
+ modelX = (config.modelX !== undefined) ? parseFloat(config.modelX) : 0;
49
+ modelY = (config.modelY !== undefined) ? parseFloat(config.modelY) : 0;
50
+ modelZ = (config.modelZ !== undefined) ? parseFloat(config.modelZ) : 0;
51
+ modelScale = (config.modelScale !== undefined) ? parseFloat(config.modelScale) : 1;
52
+ modelRotationX = (config.modelRotationX !== undefined) ? parseFloat(config.modelRotationX) : 0;
53
+ modelRotationY = (config.modelRotationY !== undefined) ? parseFloat(config.modelRotationY) : 0;
54
+ modelRotationZ = (config.modelRotationZ !== undefined) ? parseFloat(config.modelRotationZ) : 0;
55
+
56
+ const cameraX = (config.cameraX !== undefined) ? parseFloat(config.cameraX) : 0;
57
+ const cameraY = (config.cameraY !== undefined) ? parseFloat(config.cameraY) : 2;
58
+ const cameraZ = (config.cameraZ !== undefined) ? parseFloat(config.cameraZ) : 5;
59
+ const cameraXPhone = (config.cameraXPhone !== undefined) ? parseFloat(config.cameraXPhone) : cameraX;
60
+ const cameraYPhone = (config.cameraYPhone !== undefined) ? parseFloat(config.cameraYPhone) : cameraY;
61
+ const cameraZPhone = (config.cameraZPhone !== undefined) ? parseFloat(config.cameraZPhone) : (cameraZ * 1.5);
62
+
63
+ chosenCameraX = isMobile ? cameraXPhone : cameraX;
64
+ chosenCameraY = isMobile ? cameraYPhone : cameraY;
65
+ chosenCameraZ = isMobile ? cameraZPhone : cameraZ;
66
+
67
+ // DOM Elements
68
+ alert('viewer.js: About to get canvas/progress/dialog');
69
+ const canvasId = 'canvas-' + instanceId;
70
+ const progressDialog = document.getElementById('progress-dialog-' + instanceId);
71
+ const viewerContainer = document.getElementById('viewer-container-' + instanceId);
72
+ if (!progressDialog || !viewerContainer) {
73
+ alert('viewer.js: progressDialog or viewerContainer not found!');
74
+ return;
75
+ }
76
 
77
+ // Remove old canvas if any
78
+ let oldCanvas = document.getElementById(canvasId);
79
+ if (oldCanvas) {
80
+ alert('viewer.js: Removing old canvas');
81
+ oldCanvas.remove();
82
+ }
83
+
84
+ // Create and add canvas
85
+ alert('viewer.js: About to create canvas');
86
+ const canvas = document.createElement('canvas');
87
+ canvas.id = canvasId;
88
+ canvas.className = 'ply-canvas';
89
+ canvas.style.width = "100%";
90
+ canvas.style.height = "100%";
91
+ canvas.setAttribute('tabindex', '0');
92
+ viewerContainer.insertBefore(canvas, progressDialog);
93
+ canvas.style.touchAction = "none";
94
+ canvas.style.webkitTouchCallout = "none";
95
+ canvas.addEventListener('gesturestart', e => e.preventDefault());
96
+ canvas.addEventListener('gesturechange', e => e.preventDefault());
97
+ canvas.addEventListener('gestureend', e => e.preventDefault());
98
+ canvas.addEventListener('dblclick', e => e.preventDefault());
99
+ canvas.addEventListener('touchstart', e => { if (e.touches.length > 1) e.preventDefault(); }, { passive: false });
100
+ canvas.addEventListener('wheel', (e) => { e.preventDefault(); }, { passive: false });
101
+
102
+ progressDialog.style.display = 'block';
103
+
104
+ // --- PlayCanvas Graphics Device ---
105
+ alert('viewer.js: About to create PlayCanvas graphics device');
106
+ let device;
107
+ try {
108
+ device = await pc.createGraphicsDevice(canvas, {
109
  deviceTypes: ["webgl2"],
110
  antialias: false,
111
  glslangUrl: "https://playcanvas.vercel.app/static/lib/glslang/glslang.js",
112
  twgslUrl: "https://playcanvas.vercel.app/static/lib/twgsl/twgsl.js"
113
  });
114
+ } catch (e) {
115
+ alert('viewer.js: Failed to create graphics device: ' + e.message);
116
+ console.error(e);
117
+ return;
118
+ }
119
+ device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
120
+
121
+ // --- PlayCanvas AppBase (modern, 2.8.1+) ---
122
+ alert('viewer.js: About to create AppBase');
123
+ let appOpts = new pc.AppOptions();
124
+ appOpts.graphicsDevice = device;
125
+ appOpts.mouse = new pc.Mouse(canvas);
126
+ appOpts.touch = new pc.TouchDevice(canvas);
127
+ appOpts.componentSystems = [
128
+ pc.RenderComponentSystem,
129
+ pc.CameraComponentSystem,
130
+ pc.LightComponentSystem,
131
+ pc.ScriptComponentSystem,
132
+ pc.GSplatComponentSystem
133
+ ];
134
+ appOpts.resourceHandlers = [
135
+ pc.TextureHandler,
136
+ pc.ContainerHandler,
137
+ pc.ScriptHandler,
138
+ pc.GSplatHandler
139
+ ];
140
+
141
+ app = new pc.AppBase(canvas);
142
+ app.init(appOpts);
143
+
144
+ // Fill/resize
145
+ app.setCanvasFillMode(pc.FILLMODE_NONE);
146
+ app.setCanvasResolution(pc.RESOLUTION_AUTO);
147
+
148
+ resizeObserver = new ResizeObserver(entries => {
149
+ entries.forEach(entry => {
150
+ app.resizeCanvas(entry.contentRect.width, entry.contentRect.height);
151
  });
152
+ });
153
+ resizeObserver.observe(viewerContainer);
154
+
155
+ window.addEventListener('resize', () => app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight));
156
+ app.on('destroy', () => resizeObserver.disconnect());
157
+
158
+ // --- ASSETS (GSplat + Orbit camera) ---
159
+ alert('viewer.js: About to add assets');
160
+ const assets = {
161
+ model: new pc.Asset('gsplat', 'gsplat', { url: sogsUrl }),
162
+ orbit: new pc.Asset('orbit', 'script', { url: "https://mikafil-viewer-sgos.static.hf.space/orbit-camera.js" }),
163
+ // Optionally add other assets here if you want
164
+ };
165
+ for (const key in assets) {
166
+ app.assets.add(assets[key]);
167
+ alert('viewer.js: Asset added: ' + key);
168
+ }
 
 
 
 
169
 
170
+ alert('viewer.js: About to load assets');
171
+ const loader = new pc.AssetListLoader(Object.values(assets), app.assets);
172
+ loader.load(() => {
173
+ alert('viewer.js: Asset loader callback!');
174
+ try {
175
  // --- Add GSplat Model ---
176
+ alert('viewer.js: About to create model entity');
177
  modelEntity = new pc.Entity('model');
178
  modelEntity.addComponent('gsplat', { asset: assets.model });
179
  modelEntity.setLocalPosition(modelX, modelY, modelZ);
 
181
  modelEntity.setLocalScale(modelScale, modelScale, modelScale);
182
  app.root.addChild(modelEntity);
183
 
184
+ alert('viewer.js: Model entity added');
185
  // --- Camera ---
 
186
  cameraEntity = new pc.Entity('camera');
187
  cameraEntity.addComponent('camera', {
188
  clearColor: new pc.Color(1, 1, 1, 1)
 
208
  cameraEntity.script.create('orbitCameraInputTouch');
209
  app.root.addChild(cameraEntity);
210
 
211
+ alert('viewer.js: Camera entity added');
212
+ app.start();
213
+ progressDialog.style.display = 'none';
214
 
215
  app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
216
+ app.once('update', () => resetViewerCamera());
 
 
 
217
 
218
  // --- Tooltips ---
219
  try {
220
  if (config.tooltips_url) {
221
+ alert('viewer.js: Importing tooltips.js');
222
  import('./tooltips.js').then(tooltipsModule => {
 
223
  tooltipsModule.initializeTooltips({
224
  app,
225
  cameraEntity,
 
228
  defaultVisible: !!config.showTooltipsDefault,
229
  moveDuration: config.tooltipMoveDuration || 0.6
230
  });
231
+ alert('viewer.js: Tooltips initialized');
232
  }).catch(e => {
233
+ alert('viewer.js: Error importing tooltips.js: ' + (e.message || e));
 
234
  });
235
  }
236
  } catch (e) {
237
+ alert('viewer.js: Exception during tooltips import: ' + (e.message || e));
238
  }
239
 
240
  viewerInitialized = true;
241
+ alert('viewer.js: Viewer fully initialized!');
 
 
 
 
 
 
 
 
 
 
242
 
243
+ } catch(e) {
244
+ alert('viewer.js: Exception in asset loader callback: ' + (e.message || e));
245
+ console.error(e);
246
+ }
247
+ });
248
  }
249
 
250
  // Reset camera helper
251
  export function resetViewerCamera() {
252
  try {
 
253
  if (!cameraEntity || !modelEntity || !app) {
254
+ alert('resetViewerCamera: Required objects missing!');
255
  return;
256
  }
257
  const orbitCam = cameraEntity.script.orbitCamera;
 
295
  if (orbitCam._updatePosition) orbitCam._updatePosition();
296
 
297
  tempEnt.destroy();
298
+ alert('resetViewerCamera: Camera reset!');
299
  } catch (e) {
300
  alert('resetViewerCamera: Exception: ' + (e.message || e));
301
  // Silent fail