MikaFil commited on
Commit
ff4db59
·
verified ·
1 Parent(s): 298ba5f

Update viewer.js

Browse files
Files changed (1) hide show
  1. viewer.js +43 -64
viewer.js CHANGED
@@ -1,7 +1,6 @@
1
  // viewer.js
2
  // ==============================
3
 
4
- let pc;
5
  export let app = null;
6
  let cameraEntity = null;
7
  let modelEntity = null;
@@ -14,10 +13,9 @@ let modelX, modelY, modelZ, modelScale, modelRotationX, modelRotationY, modelRot
14
  let sogsUrl, glbUrl, canvasBg;
15
 
16
  function getDeviceTypes() {
17
- // From PlayCanvas example
18
  const ua = navigator.userAgent;
19
  if (/iPad|iPhone|iPod/.test(ua) || (ua.includes("Macintosh") && "ontouchend" in document)) {
20
- return ['webgl2', 'webgl1']; // On iOS, sometimes WebGL2 fails, fallback to WebGL1
21
  }
22
  return ['webgl2', 'webgl1'];
23
  }
@@ -64,7 +62,6 @@ export async function initializeViewer(config, instanceId) {
64
 
65
  const canvasId = 'canvas-' + instanceId;
66
  const progressDialog = document.getElementById('progress-dialog-' + instanceId);
67
- const progressIndicator= document.getElementById('progress-indicator-' + instanceId);
68
  const viewerContainer = document.getElementById('viewer-container-' + instanceId);
69
 
70
  let oldCanvas = document.getElementById(canvasId);
@@ -78,10 +75,7 @@ export async function initializeViewer(config, instanceId) {
78
  canvas.setAttribute('tabindex', '0');
79
  viewerContainer.insertBefore(canvas, progressDialog);
80
 
81
- // Apply background color from config if present
82
  canvas.style.background = canvasBg;
83
-
84
- // iOS quirks: allow all gestures, prevent double tap zoom etc.
85
  canvas.style.touchAction = "none";
86
  canvas.style.webkitTouchCallout = "none";
87
  canvas.addEventListener('gesturestart', e => e.preventDefault());
@@ -89,23 +83,19 @@ export async function initializeViewer(config, instanceId) {
89
  canvas.addEventListener('gestureend', e => e.preventDefault());
90
  canvas.addEventListener('dblclick', e => e.preventDefault());
91
  canvas.addEventListener('touchstart', e => { if (e.touches.length > 1) e.preventDefault(); }, { passive: false });
92
-
93
- // Mouse wheel suppression
94
- canvas.addEventListener('wheel', (e) => {
95
- e.preventDefault();
96
- }, { passive: false });
97
 
98
  progressDialog.style.display = 'block';
99
  alert("Canvas created. Loading PlayCanvas...");
100
 
101
- if (!pc) {
102
- // USE JSDELIVR CDN! THIS IS WHAT THE PLAYCANVAS SOGS DEMO USES!
103
- pc = await import("https://cdn.jsdelivr.net/npm/playcanvas@2.8.0/+esm");
104
- window.pc = pc;
105
- }
106
  alert("PlayCanvas imported.");
 
 
 
107
 
108
- // Device type logic for iOS fallback
109
  const gfxOptions = {
110
  deviceTypes: getDeviceTypes(),
111
  glslangUrl: "https://mikafil-viewer-sgos.static.hf.space/static/lib/glslang/glslang.js",
@@ -116,47 +106,43 @@ export async function initializeViewer(config, instanceId) {
116
  device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
117
  alert("Graphics device created.");
118
 
119
- // Use AppBase (as example) instead of Application
120
- app = new pc.AppBase(canvas);
121
- // Use PlayCanvas-style AppOptions
122
- const createOptions = new pc.AppOptions();
123
- createOptions.graphicsDevice = device;
124
- createOptions.mouse = new pc.Mouse(document.body); // this is crucial for iOS
125
- createOptions.touch = new pc.TouchDevice(document.body);
126
- createOptions.componentSystems = [
127
- pc.RenderComponentSystem,
128
- pc.CameraComponentSystem,
129
- pc.LightComponentSystem,
130
- pc.ScriptComponentSystem,
131
- pc.GSplatComponentSystem,
132
- pc.CollisionComponentSystem,
133
- pc.RigidbodyComponentSystem
134
- ];
135
- createOptions.resourceHandlers = [
136
- pc.TextureHandler,
137
- pc.ContainerHandler,
138
- pc.ScriptHandler,
139
- pc.GSplatHandler
140
- ];
141
-
142
- app.init(createOptions);
143
  alert("App created.");
144
 
145
- // Fill mode and resize logic
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
- // Prepare asset loading (SOGS as 'gsplat')
160
  const assets = {
161
  sogs: new pc.Asset('gsplat', 'gsplat', { url: sogsUrl }),
162
  orbit: new pc.Asset('script', 'script', { url: "https://mikafil-viewer-sgos.static.hf.space/orbit-camera.js" }),
@@ -169,8 +155,6 @@ export async function initializeViewer(config, instanceId) {
169
 
170
  assetListLoader.load(() => {
171
  alert("Asset loader started.");
172
-
173
- // SOGS
174
  if (!assets.sogs.resource) {
175
  alert("SOGS asset failed to load.");
176
  return;
@@ -182,14 +166,12 @@ export async function initializeViewer(config, instanceId) {
182
  modelEntity.setLocalScale(modelScale, modelScale, modelScale);
183
  app.root.addChild(modelEntity);
184
 
185
- // Orbit camera
186
  if (!assets.orbit.resource) {
187
  alert("orbit-camera.js asset failed to load!");
188
  return;
189
  }
190
  alert("orbit-camera.js asset ready.");
191
 
192
- // GLB
193
  if (assets.glb && assets.glb.resource && assets.glb.resource.instantiateRenderEntity) {
194
  const glbEntity = assets.glb.resource.instantiateRenderEntity();
195
  app.root.addChild(glbEntity);
@@ -198,7 +180,6 @@ export async function initializeViewer(config, instanceId) {
198
  alert("GLB not provided or failed to load.");
199
  }
200
 
201
- // CAMERA entity
202
  cameraEntity = new pc.Entity('camera');
203
  // Parse and apply background color
204
  let bg = [1, 1, 1, 1];
@@ -272,8 +253,6 @@ export async function initializeViewer(config, instanceId) {
272
  }
273
  }
274
 
275
-
276
- // Resets the viewer camera (as in your PLY example)
277
  export function resetViewerCamera() {
278
  try {
279
  if (!cameraEntity || !modelEntity || !app) return;
@@ -281,12 +260,12 @@ export function resetViewerCamera() {
281
  if (!orbitCam) return;
282
 
283
  const modelPos = modelEntity.getPosition();
284
- const tempEnt = new pc.Entity();
285
  tempEnt.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
286
  tempEnt.lookAt(modelPos);
287
 
288
- const dist = new pc.Vec3().sub2(
289
- new pc.Vec3(chosenCameraX, chosenCameraY, chosenCameraZ),
290
  modelPos
291
  ).length();
292
 
@@ -298,15 +277,15 @@ export function resetViewerCamera() {
298
  orbitCam._distance = dist;
299
 
300
  const rot = tempEnt.getRotation();
301
- const fwd = new pc.Vec3();
302
- rot.transformVector(pc.Vec3.FORWARD, fwd);
303
-
304
- const yaw = Math.atan2(-fwd.x, -fwd.z) * pc.math.RAD_TO_DEG;
305
- const yawQuat = new pc.Quat().setFromEulerAngles(0, -yaw, 0);
306
- const rotNoYaw = new pc.Quat().mul2(yawQuat, rot);
307
- const fNoYaw = new pc.Vec3();
308
- rotNoYaw.transformVector(pc.Vec3.FORWARD, fNoYaw);
309
- const pitch = Math.atan2(fNoYaw.y, -fNoYaw.z) * pc.math.RAD_TO_DEG;
310
 
311
  orbitCam._targetYaw = yaw;
312
  orbitCam._yaw = yaw;
 
1
  // viewer.js
2
  // ==============================
3
 
 
4
  export let app = null;
5
  let cameraEntity = null;
6
  let modelEntity = null;
 
13
  let sogsUrl, glbUrl, canvasBg;
14
 
15
  function getDeviceTypes() {
 
16
  const ua = navigator.userAgent;
17
  if (/iPad|iPhone|iPod/.test(ua) || (ua.includes("Macintosh") && "ontouchend" in document)) {
18
+ return ['webgl2', 'webgl1']; // Try both on iOS
19
  }
20
  return ['webgl2', 'webgl1'];
21
  }
 
62
 
63
  const canvasId = 'canvas-' + instanceId;
64
  const progressDialog = document.getElementById('progress-dialog-' + instanceId);
 
65
  const viewerContainer = document.getElementById('viewer-container-' + instanceId);
66
 
67
  let oldCanvas = document.getElementById(canvasId);
 
75
  canvas.setAttribute('tabindex', '0');
76
  viewerContainer.insertBefore(canvas, progressDialog);
77
 
 
78
  canvas.style.background = canvasBg;
 
 
79
  canvas.style.touchAction = "none";
80
  canvas.style.webkitTouchCallout = "none";
81
  canvas.addEventListener('gesturestart', e => e.preventDefault());
 
83
  canvas.addEventListener('gestureend', e => e.preventDefault());
84
  canvas.addEventListener('dblclick', e => e.preventDefault());
85
  canvas.addEventListener('touchstart', e => { if (e.touches.length > 1) e.preventDefault(); }, { passive: false });
86
+ canvas.addEventListener('wheel', (e) => { e.preventDefault(); }, { passive: false });
 
 
 
 
87
 
88
  progressDialog.style.display = 'block';
89
  alert("Canvas created. Loading PlayCanvas...");
90
 
91
+ // 1. Import PlayCanvas
92
+ const pcMod = await import("https://cdn.jsdelivr.net/npm/playcanvas@2.8.0/+esm");
 
 
 
93
  alert("PlayCanvas imported.");
94
+ window.pc = pcMod; // ensures global for script-based scripts
95
+ // 2. Now all use window.pc from here
96
+ const pc = window.pc;
97
 
98
+ // 3. Graphics Device
99
  const gfxOptions = {
100
  deviceTypes: getDeviceTypes(),
101
  glslangUrl: "https://mikafil-viewer-sgos.static.hf.space/static/lib/glslang/glslang.js",
 
106
  device.maxPixelRatio = Math.min(window.devicePixelRatio, 2);
107
  alert("Graphics device created.");
108
 
109
+ // 4. App creation (Application, not AppBase for max compatibility)
110
+ app = new pc.Application(canvas, {
111
+ graphicsDevice: device,
112
+ mouse: new pc.Mouse(canvas),
113
+ touch: new pc.TouchDevice(canvas),
114
+ componentSystems: [
115
+ pc.RenderComponentSystem,
116
+ pc.CameraComponentSystem,
117
+ pc.LightComponentSystem,
118
+ pc.ScriptComponentSystem,
119
+ pc.GSplatComponentSystem,
120
+ pc.CollisionComponentSystem,
121
+ pc.RigidbodyComponentSystem
122
+ ],
123
+ resourceHandlers: [
124
+ pc.TextureHandler,
125
+ pc.ContainerHandler,
126
+ pc.ScriptHandler,
127
+ pc.GSplatHandler
128
+ ]
129
+ });
 
 
 
130
  alert("App created.");
131
 
 
132
  app.setCanvasFillMode(pc.FILLMODE_NONE);
133
  app.setCanvasResolution(pc.RESOLUTION_AUTO);
134
 
135
+ // Resize observer logic
136
  resizeObserver = new ResizeObserver(entries => {
137
  entries.forEach(entry => {
138
  app.resizeCanvas(entry.contentRect.width, entry.contentRect.height);
139
  });
140
  });
141
  resizeObserver.observe(viewerContainer);
 
142
  window.addEventListener('resize', () => app.resizeCanvas(viewerContainer.clientWidth, viewerContainer.clientHeight));
143
  app.on('destroy', () => resizeObserver.disconnect());
144
 
145
+ // Asset loading
146
  const assets = {
147
  sogs: new pc.Asset('gsplat', 'gsplat', { url: sogsUrl }),
148
  orbit: new pc.Asset('script', 'script', { url: "https://mikafil-viewer-sgos.static.hf.space/orbit-camera.js" }),
 
155
 
156
  assetListLoader.load(() => {
157
  alert("Asset loader started.");
 
 
158
  if (!assets.sogs.resource) {
159
  alert("SOGS asset failed to load.");
160
  return;
 
166
  modelEntity.setLocalScale(modelScale, modelScale, modelScale);
167
  app.root.addChild(modelEntity);
168
 
 
169
  if (!assets.orbit.resource) {
170
  alert("orbit-camera.js asset failed to load!");
171
  return;
172
  }
173
  alert("orbit-camera.js asset ready.");
174
 
 
175
  if (assets.glb && assets.glb.resource && assets.glb.resource.instantiateRenderEntity) {
176
  const glbEntity = assets.glb.resource.instantiateRenderEntity();
177
  app.root.addChild(glbEntity);
 
180
  alert("GLB not provided or failed to load.");
181
  }
182
 
 
183
  cameraEntity = new pc.Entity('camera');
184
  // Parse and apply background color
185
  let bg = [1, 1, 1, 1];
 
253
  }
254
  }
255
 
 
 
256
  export function resetViewerCamera() {
257
  try {
258
  if (!cameraEntity || !modelEntity || !app) return;
 
260
  if (!orbitCam) return;
261
 
262
  const modelPos = modelEntity.getPosition();
263
+ const tempEnt = new window.pc.Entity();
264
  tempEnt.setPosition(chosenCameraX, chosenCameraY, chosenCameraZ);
265
  tempEnt.lookAt(modelPos);
266
 
267
+ const dist = new window.pc.Vec3().sub2(
268
+ new window.pc.Vec3(chosenCameraX, chosenCameraY, chosenCameraZ),
269
  modelPos
270
  ).length();
271
 
 
277
  orbitCam._distance = dist;
278
 
279
  const rot = tempEnt.getRotation();
280
+ const fwd = new window.pc.Vec3();
281
+ rot.transformVector(window.pc.Vec3.FORWARD, fwd);
282
+
283
+ const yaw = Math.atan2(-fwd.x, -fwd.z) * window.pc.math.RAD_TO_DEG;
284
+ const yawQuat = new window.pc.Quat().setFromEulerAngles(0, -yaw, 0);
285
+ const rotNoYaw = new window.pc.Quat().mul2(yawQuat, rot);
286
+ const fNoYaw = new window.pc.Vec3();
287
+ rotNoYaw.transformVector(window.pc.Vec3.FORWARD, fNoYaw);
288
+ const pitch = Math.atan2(fNoYaw.y, -fNoYaw.z) * window.pc.math.RAD_TO_DEG;
289
 
290
  orbitCam._targetYaw = yaw;
291
  orbitCam._yaw = yaw;