MikaFil commited on
Commit
2980252
·
verified ·
1 Parent(s): 82916aa

Update viewer.js

Browse files
Files changed (1) hide show
  1. viewer.js +92 -91
viewer.js CHANGED
@@ -1,7 +1,7 @@
1
  // viewer.js
2
  // ==============================
3
 
4
- let pc;
5
  export let app = null;
6
  let cameraEntity = null;
7
  let modelEntity = null;
@@ -19,10 +19,10 @@ export async function initializeViewer(config, instanceId) {
19
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
20
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
21
 
22
- // SOGS usage: we expect config.sogs_json_url
23
  sogsJsonUrl = config.sogs_json_url;
24
  if (!sogsJsonUrl) {
25
- throw new Error('Missing config.sogs_json_url for optimized SOGS/webp loading.');
 
26
  }
27
 
28
  minZoom = parseFloat(config.minZoom || "1");
@@ -76,10 +76,7 @@ export async function initializeViewer(config, instanceId) {
76
  canvas.addEventListener('gestureend', e => e.preventDefault());
77
  canvas.addEventListener('dblclick', e => e.preventDefault());
78
  canvas.addEventListener('touchstart', e => { if (e.touches.length > 1) e.preventDefault(); }, { passive: false });
79
-
80
- canvas.addEventListener('wheel', (e) => {
81
- e.preventDefault();
82
- }, { passive: false });
83
 
84
  progressDialog.style.display = 'block';
85
 
@@ -129,30 +126,36 @@ export async function initializeViewer(config, instanceId) {
129
  window.addEventListener('resize', () => app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight));
130
  app.on('destroy', () => resizeObserver.disconnect());
131
 
132
- // Load orbit camera scripts
133
  const orbitAsset = new pc.Asset('orbit', 'script', { url: "https://mikafil-viewer-gs.static.hf.space/orbit-camera.js" });
134
  app.assets.add(orbitAsset);
 
 
 
135
 
136
- // Load SOGS json (contains metadata and webp references)
137
  let sogsData, sogsTextures = {};
138
  try {
139
  const jsonResp = await fetch(sogsJsonUrl);
140
  sogsData = await jsonResp.json();
141
- if (!Array.isArray(sogsData.images)) throw new Error('sogs_json missing .images array');
142
- // Preload all webp textures as PlayCanvas textures
143
- for (let i = 0; i < sogsData.images.length; ++i) {
144
- const imageInfo = sogsData.images[i];
145
- let url = imageInfo.path || imageInfo.url;
146
- if (!/^https?:\/\//.test(url) && sogsJsonUrl) {
147
- // resolve relative to sogsJsonUrl
148
- const baseUrl = sogsJsonUrl.split('/').slice(0, -1).join('/');
149
- url = `${baseUrl}/${url}`;
150
- }
151
- // Load texture asset synchronously (block start until all images ready)
152
- sogsTextures[imageInfo.name || `img${i}`] = await new Promise((resolve, reject) => {
153
- const asset = new pc.Asset(imageInfo.name || `img${i}`, 'texture', { url });
 
 
 
154
  app.assets.add(asset);
155
- asset.ready(resolve.bind(null, asset.resource));
156
  asset.on('error', reject);
157
  app.assets.load(asset);
158
  });
@@ -163,80 +166,78 @@ export async function initializeViewer(config, instanceId) {
163
  throw e;
164
  }
165
 
166
- // Continue once orbit script is loaded
167
- orbitAsset.ready(async () => {
168
- app.start();
169
- progressDialog.style.display = 'none';
170
-
171
- // Add the SOGS/webp point cloud as a "gsplat" entity/component
172
- modelEntity = new pc.Entity('model');
173
-
174
- // Here you would use your SOGS-compatible GSplat renderer component.
175
- // Let's define a placeholder `gsplat` script which you must replace
176
- // with your PlayCanvas SOGS/gsplat renderer.
177
- modelEntity.addComponent('script');
178
- modelEntity.script.create('gsplat', {
179
- attributes: {
180
- sogsData: sogsData,
181
- textures: sogsTextures
182
- }
183
- });
184
-
185
- modelEntity.setLocalPosition(modelX, modelY, modelZ);
186
- modelEntity.setLocalEulerAngles(modelRotationX, modelRotationY, modelRotationZ);
187
- modelEntity.setLocalScale(modelScale, modelScale, modelScale);
188
- app.root.addChild(modelEntity);
189
 
190
- // Camera entity
191
- cameraEntity = new pc.Entity('camera');
192
- cameraEntity.addComponent('camera', { clearColor: new pc.Color(1, 1, 1, 1) }); // White BG
193
- cameraEntity.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
194
- cameraEntity.lookAt(modelEntity.getPosition());
195
- cameraEntity.addComponent('script');
196
-
197
- cameraEntity.script.create('orbitCamera', {
198
- attributes: {
199
- focusEntity: modelEntity,
200
- inertiaFactor: 0.2,
201
- distanceMax: maxZoom,
202
- distanceMin: minZoom,
203
- pitchAngleMax: maxAngle,
204
- pitchAngleMin: minAngle,
205
- yawAngleMax: maxAzimuth,
206
- yawAngleMin: minAzimuth,
207
- minY: minY,
208
- frameOnStart: false
209
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  });
211
- cameraEntity.script.create('orbitCameraInputMouse');
212
- cameraEntity.script.create('orbitCameraInputTouch');
213
- app.root.addChild(cameraEntity);
214
-
215
- app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
216
- app.once('update', () => resetViewerCamera());
217
-
218
- // Optional: tooltips
219
- try {
220
- if (config.tooltips_url) {
221
- import('./tooltips.js').then(tooltipsModule => {
222
- tooltipsModule.initializeTooltips({
223
- app,
224
- cameraEntity,
225
- modelEntity,
226
- tooltipsUrl: config.tooltips_url,
227
- defaultVisible: !!config.showTooltipsDefault,
228
- moveDuration: config.tooltipMoveDuration || 0.6
229
- });
230
- }).catch(e => {});
231
- }
232
- } catch (e) {}
233
-
234
- viewerInitialized = true;
235
  });
236
  app.assets.load(orbitAsset);
237
  }
238
 
239
- // Reset camera helper, unchanged from PLY version
240
  export function resetViewerCamera() {
241
  try {
242
  if (!cameraEntity || !modelEntity || !app) return;
 
1
  // viewer.js
2
  // ==============================
3
 
4
+ let pc;
5
  export let app = null;
6
  let cameraEntity = null;
7
  let modelEntity = null;
 
19
  const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);
20
  const isMobile = isIOS || /Android/i.test(navigator.userAgent);
21
 
 
22
  sogsJsonUrl = config.sogs_json_url;
23
  if (!sogsJsonUrl) {
24
+ alert('Missing config.sogs_json_url for SOGS/webp loading.');
25
+ return;
26
  }
27
 
28
  minZoom = parseFloat(config.minZoom || "1");
 
76
  canvas.addEventListener('gestureend', e => e.preventDefault());
77
  canvas.addEventListener('dblclick', e => e.preventDefault());
78
  canvas.addEventListener('touchstart', e => { if (e.touches.length > 1) e.preventDefault(); }, { passive: false });
79
+ canvas.addEventListener('wheel', (e) => { e.preventDefault(); }, { passive: false });
 
 
 
80
 
81
  progressDialog.style.display = 'block';
82
 
 
126
  window.addEventListener('resize', () => app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight));
127
  app.on('destroy', () => resizeObserver.disconnect());
128
 
129
+ // Load orbit camera scripts and gsplat script
130
  const orbitAsset = new pc.Asset('orbit', 'script', { url: "https://mikafil-viewer-gs.static.hf.space/orbit-camera.js" });
131
  app.assets.add(orbitAsset);
132
+ const gsplatAsset = new pc.Asset('gsplat', 'script', { url: "gsplat.js" }); // If using relative URL
133
+
134
+ app.assets.add(gsplatAsset);
135
 
136
+ // Fetch SOGS meta.json and webp textures
137
  let sogsData, sogsTextures = {};
138
  try {
139
  const jsonResp = await fetch(sogsJsonUrl);
140
  sogsData = await jsonResp.json();
141
+
142
+ // Parse meta to get file list
143
+ let meta = sogsData;
144
+ let filesSet = new Set();
145
+ if (meta.means && meta.means.files) meta.means.files.forEach(f => filesSet.add(f));
146
+ if (meta.scales && meta.scales.files) meta.scales.files.forEach(f => filesSet.add(f));
147
+ if (meta.quats && meta.quats.files) meta.quats.files.forEach(f => filesSet.add(f));
148
+ if (meta.sh0 && meta.sh0.files) meta.sh0.files.forEach(f => filesSet.add(f));
149
+
150
+ // For each, fetch as a Texture
151
+ let baseUrl = sogsJsonUrl.split('/').slice(0, -1).join('/');
152
+ for (let fname of filesSet) {
153
+ let url = fname.startsWith('http') ? fname : `${baseUrl}/${fname}`;
154
+ // Use PlayCanvas Texture Asset
155
+ sogsTextures[fname] = await new Promise((resolve, reject) => {
156
+ const asset = new pc.Asset(fname, 'texture', { url });
157
  app.assets.add(asset);
158
+ asset.ready(() => resolve(asset.resource));
159
  asset.on('error', reject);
160
  app.assets.load(asset);
161
  });
 
166
  throw e;
167
  }
168
 
169
+ // Continue after both scripts loaded
170
+ orbitAsset.ready(() => {
171
+ gsplatAsset.ready(() => {
172
+ app.start();
173
+ progressDialog.style.display = 'none';
174
+
175
+ // Add GSplat entity and script
176
+ modelEntity = new pc.Entity('model');
177
+ modelEntity.addComponent('script');
178
+ modelEntity.script.create('gsplat', {
179
+ attributes: {
180
+ sogsData: sogsData,
181
+ textures: sogsTextures
182
+ }
183
+ });
 
 
 
 
 
 
 
 
184
 
185
+ modelEntity.setLocalPosition(modelX, modelY, modelZ);
186
+ modelEntity.setLocalEulerAngles(modelRotationX, modelRotationY, modelRotationZ);
187
+ modelEntity.setLocalScale(modelScale, modelScale, modelScale);
188
+ app.root.addChild(modelEntity);
189
+
190
+ // Camera entity
191
+ cameraEntity = new pc.Entity('camera');
192
+ cameraEntity.addComponent('camera', { clearColor: new pc.Color(1, 1, 1, 1) });
193
+ cameraEntity.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
194
+ cameraEntity.lookAt(modelEntity.getPosition());
195
+ cameraEntity.addComponent('script');
196
+ cameraEntity.script.create('orbitCamera', {
197
+ attributes: {
198
+ focusEntity: modelEntity,
199
+ inertiaFactor: 0.2,
200
+ distanceMax: maxZoom,
201
+ distanceMin: minZoom,
202
+ pitchAngleMax: maxAngle,
203
+ pitchAngleMin: minAngle,
204
+ yawAngleMax: maxAzimuth,
205
+ yawAngleMin: minAzimuth,
206
+ minY: minY,
207
+ frameOnStart: false
208
+ }
209
+ });
210
+ cameraEntity.script.create('orbitCameraInputMouse');
211
+ cameraEntity.script.create('orbitCameraInputTouch');
212
+ app.root.addChild(cameraEntity);
213
+
214
+ app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight);
215
+ app.once('update', () => resetViewerCamera());
216
+
217
+ // Optional: tooltips
218
+ try {
219
+ if (config.tooltips_url) {
220
+ import('./tooltips.js').then(tooltipsModule => {
221
+ tooltipsModule.initializeTooltips({
222
+ app,
223
+ cameraEntity,
224
+ modelEntity,
225
+ tooltipsUrl: config.tooltips_url,
226
+ defaultVisible: !!config.showTooltipsDefault,
227
+ moveDuration: config.tooltipMoveDuration || 0.6
228
+ });
229
+ }).catch(e => {});
230
+ }
231
+ } catch (e) {}
232
+
233
+ viewerInitialized = true;
234
  });
235
+ app.assets.load(gsplatAsset);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  });
237
  app.assets.load(orbitAsset);
238
  }
239
 
240
+ // Reset camera helper
241
  export function resetViewerCamera() {
242
  try {
243
  if (!cameraEntity || !modelEntity || !app) return;