Spaces:
Running
Running
File size: 3,673 Bytes
ebb3bda 537f2af ebb3bda ec3121c 537f2af 95af024 62c50cd ec3121c cc654e9 9c554be bdef08e e7b5357 1b5e137 ec3121c cc654e9 95af024 b95cc56 95af024 31a2d08 62c50cd 70a459f ec3121c 9c554be 31a2d08 62c50cd 31a2d08 62c50cd 31a2d08 ec3121c e7b5357 95af024 ec3121c 95af024 ec3121c 95af024 ec3121c 70a459f 95af024 1b5e137 bdef08e 70a459f cc654e9 70a459f 95af024 ec3121c cc654e9 ebb3bda c9731fb 70a459f ebb3bda 62c50cd 3b7903d ebb3bda 3b7903d |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
import type { IViewer } from "./IViewer";
import * as SPLAT from "gsplat";
export class SplatViewer implements IViewer {
canvas: HTMLCanvasElement;
renderer: SPLAT.WebGLRenderer;
scene: SPLAT.Scene;
camera: SPLAT.Camera;
controls: SPLAT.OrbitControls;
splat: SPLAT.Splat | null;
disposed: boolean = false;
topoOnly: boolean = false;
vertexCount: number = 0;
constructor(canvas: HTMLCanvasElement) {
this.canvas = canvas;
this.renderer = new SPLAT.WebGLRenderer(canvas);
this.renderer.renderProgram.outlineColor = new SPLAT.Color32(180, 180, 180);
this.scene = new SPLAT.Scene();
this.camera = new SPLAT.Camera();
this.controls = new SPLAT.OrbitControls(this.camera, canvas);
this.controls.orbitSpeed = 3.0;
this.splat = null;
this.handleResize = this.handleResize.bind(this);
}
async loadScene(url: string, loadingBarCallback?: (progress: number) => void, topoOnly?: boolean) {
this.topoOnly = topoOnly ?? false;
if (url.endsWith(".splat")) {
this.splat = await SPLAT.Loader.LoadAsync(url, this.scene, (progress) => {
loadingBarCallback?.(progress);
});
} else if (url.endsWith(".ply")) {
this.splat = await SPLAT.PLYLoader.LoadAsync(url, this.scene, (progress) => {
loadingBarCallback?.(progress);
});
} else {
throw new Error("Unsupported file format");
}
this.vertexCount = this.splat.data.vertexCount;
const frame = () => {
this.controls.update();
this.renderer.render(this.scene, this.camera);
if (!this.disposed) {
requestAnimationFrame(frame);
}
};
this.disposed = false;
this.handleResize();
window.addEventListener("resize", this.handleResize);
requestAnimationFrame(frame);
}
handleResize() {
this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);
}
dispose() {
window.removeEventListener("resize", this.handleResize);
this.controls.dispose();
this.renderer.dispose();
this.disposed = true;
}
async capture(): Promise<string | null> {
return new Promise((resolve) => {
requestAnimationFrame(() => {
const offscreenCanvas = document.createElement("canvas");
offscreenCanvas.width = 512;
offscreenCanvas.height = 512;
const offscreenContext = offscreenCanvas.getContext("2d") as CanvasRenderingContext2D;
const x = (this.canvas.width - offscreenCanvas.width) / 2;
const y = (this.canvas.height - offscreenCanvas.height) / 2;
offscreenContext.drawImage(
this.canvas,
x,
y,
offscreenCanvas.width,
offscreenCanvas.height,
0,
0,
offscreenCanvas.width,
offscreenCanvas.height
);
const dataUrl = offscreenCanvas.toDataURL("image/png");
offscreenCanvas.remove();
resolve(dataUrl);
});
});
}
setRenderMode(mode: string): void {
if (!this.splat) return;
if (mode === "wireframe") {
this.splat.selected = true;
} else {
this.splat.selected = false;
}
}
getStats(): { name: string; value: any }[] {
return [];
}
}
|