From 0b63bbfed3822c5900feec327962bdd0732da8f0 Mon Sep 17 00:00:00 2001 From: Andreas Wilms Date: Mon, 9 Mar 2026 16:39:07 +0100 Subject: [PATCH] full conversion for environment --- app/workers/converter.worker.ts | 52 +++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/app/workers/converter.worker.ts b/app/workers/converter.worker.ts index 9f3b5fd..46beb5d 100644 --- a/app/workers/converter.worker.ts +++ b/app/workers/converter.worker.ts @@ -49,22 +49,62 @@ function parseLci(buffer: ArrayBuffer): Blob { /** * Converts XGrids environment.bin to PlayCanvas Gaussian Splat PLY */ +/** + * Converts XGrids environment.bin to a Full Gaussian Splatting PLY + * Extracts: Position, Scale, Rotation (Quaternions), and Opacity + */ function parseEnvironment(buffer: ArrayBuffer): Blob { const view = new DataView(buffer); - const POINT_SIZE = 44; + const POINT_SIZE = 44; // 11 floats * 4 bytes const numPoints = Math.floor(buffer.byteLength / POINT_SIZE); - let ply = `ply\nformat ascii 1.0\nelement vertex ${numPoints}\nproperty float x\nproperty float y\nproperty float z\nproperty float scale_0\nproperty float scale_1\nproperty float scale_2\nproperty float rot_0\nproperty float rot_1\nproperty float rot_2\nproperty float rot_3\nproperty float opacity\nend_header\n`; + let plyHeader = [ + "ply", + "format ascii 1.0", + `element vertex ${numPoints}`, + "property float x", + "property float y", + "property float z", + "property float scale_0", + "property float scale_1", + "property float scale_2", + "property float rot_0", + "property float rot_1", + "property float rot_2", + "property float rot_3", + "property float opacity", + "end_header", + "", + ].join("\n"); + + // 2. Extract all 11 properties for every point + // We use an array of strings to build the body efficiently + const rows: string[] = []; for (let i = 0; i < numPoints; i++) { const offset = i * POINT_SIZE; - const row = []; + const pointData = []; + for (let j = 0; j < 11; j++) { - row.push(view.getFloat32(offset + j * 4, true).toFixed(6)); + // getFloat32(offset, littleEndian: true) + const val = view.getFloat32(offset + j * 4, true); + pointData.push(val.toFixed(6)); + } + + rows.push(pointData.join(" ")); + + // Periodically clear memory pressure if the scene is massive + if (i % 100000 === 0 && i > 0) { + self.postMessage({ + type: "LOG", + message: `Processing Environment: ${i.toLocaleString()} splats...`, + }); } - ply += row.join(" ") + "\n"; } - return new Blob([ply], { type: "application/octet-stream" }); + + return new Blob([plyHeader + rows.join("\n")], { + type: "application/octet-stream", + }); } // --- WORKER INFRASTRUCTURE ---