lod export
This commit is contained in:
14
app/page.tsx
14
app/page.tsx
@@ -8,8 +8,6 @@ export default function XgridsWizard() {
|
|||||||
const workerRef = useRef<Worker | null>(null);
|
const workerRef = useRef<Worker | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 1. Point to the NEW location in the /app folder
|
|
||||||
// Next.js recognizes the 'new URL' pattern and bundles it as a separate worker
|
|
||||||
const worker = new Worker(
|
const worker = new Worker(
|
||||||
new URL("./workers/converter.worker.ts", import.meta.url),
|
new URL("./workers/converter.worker.ts", import.meta.url),
|
||||||
);
|
);
|
||||||
@@ -18,11 +16,17 @@ export default function XgridsWizard() {
|
|||||||
worker.onmessage = (e) => {
|
worker.onmessage = (e) => {
|
||||||
const { type, message, data } = e.data;
|
const { type, message, data } = e.data;
|
||||||
if (type === "LOG") setStatus(message);
|
if (type === "LOG") setStatus(message);
|
||||||
|
|
||||||
if (type === "DONE") {
|
if (type === "DONE") {
|
||||||
setIsProcessing(false);
|
setIsProcessing(false);
|
||||||
setStatus("Conversion Complete!");
|
setStatus(
|
||||||
downloadFile(data.sog, `${data.fileName}.sog`);
|
`Conversion Complete! Downloading ${data.files.length} files...`,
|
||||||
// Removed: downloadFile(data.ply, ...) — worker doesn't produce a PLY
|
);
|
||||||
|
|
||||||
|
// Loop through all generated files and trigger downloads
|
||||||
|
data.files.forEach((file: { name: string; blob: Blob }) => {
|
||||||
|
downloadFile(file.blob, file.name);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -41,13 +41,16 @@ self.onmessage = async (e: MessageEvent) => {
|
|||||||
try {
|
try {
|
||||||
self.postMessage({ type: "LOG", message: "Initialisiere..." });
|
self.postMessage({ type: "LOG", message: "Initialisiere..." });
|
||||||
|
|
||||||
// Fetch the WASM binary ourselves and inject it
|
// Emscripten's native locateFile hook
|
||||||
const wasmResponse = await fetch("/workers/webp.wasm");
|
|
||||||
const wasmBinary = await wasmResponse.arrayBuffer();
|
|
||||||
|
|
||||||
// Inject before the module loads
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
globalThis.Module = { wasmBinary };
|
globalThis.Module = globalThis.Module || {};
|
||||||
|
// @ts-ignore
|
||||||
|
globalThis.Module.locateFile = function (path: string) {
|
||||||
|
if (path.endsWith(".wasm")) {
|
||||||
|
return new URL("/webp.wasm", self.location.origin).href;
|
||||||
|
}
|
||||||
|
return path;
|
||||||
|
};
|
||||||
|
|
||||||
const {
|
const {
|
||||||
readFile,
|
readFile,
|
||||||
@@ -55,7 +58,6 @@ self.onmessage = async (e: MessageEvent) => {
|
|||||||
MemoryReadFileSystem,
|
MemoryReadFileSystem,
|
||||||
MemoryFileSystem,
|
MemoryFileSystem,
|
||||||
getInputFormat,
|
getInputFormat,
|
||||||
getOutputFormat,
|
|
||||||
} = await import("@playcanvas/splat-transform");
|
} = await import("@playcanvas/splat-transform");
|
||||||
|
|
||||||
const readFs = new MemoryReadFileSystem();
|
const readFs = new MemoryReadFileSystem();
|
||||||
@@ -69,9 +71,9 @@ self.onmessage = async (e: MessageEvent) => {
|
|||||||
readFs.set(file.name, new Uint8Array(file.buffer));
|
readFs.set(file.name, new Uint8Array(file.buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullOptions = {
|
const readOptions = {
|
||||||
iterations: 0,
|
iterations: 0,
|
||||||
lodSelect: [0],
|
lodSelect: [0, 1, 2, 3, 4], // we have captured a total level of 5
|
||||||
unbundled: false,
|
unbundled: false,
|
||||||
lodChunkCount: 0,
|
lodChunkCount: 0,
|
||||||
lodChunkExtent: 0,
|
lodChunkExtent: 0,
|
||||||
@@ -84,37 +86,92 @@ self.onmessage = async (e: MessageEvent) => {
|
|||||||
fileSystem: readFs,
|
fileSystem: readFs,
|
||||||
inputFormat: getInputFormat(mainLccName),
|
inputFormat: getInputFormat(mainLccName),
|
||||||
params: [],
|
params: [],
|
||||||
options: fullOptions,
|
options: readOptions,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mainTable = tables[0];
|
const mainTable = tables[0];
|
||||||
if (!mainTable) throw new Error("Keine Splat-Daten gefunden.");
|
if (!mainTable) throw new Error("Keine Splat-Daten gefunden.");
|
||||||
|
|
||||||
self.postMessage({ type: "LOG", message: "Kompiliere SOG..." });
|
const generatedFiles: { name: string; blob: Blob }[] = [];
|
||||||
|
|
||||||
const writeFs = new MemoryFileSystem();
|
// PASS 1: Generate Single High-Quality SOG
|
||||||
const outputName = `${fileName}.sog`;
|
self.postMessage({ type: "LOG", message: "Kompiliere Single SOG..." });
|
||||||
|
|
||||||
|
const writeFsSingle = new MemoryFileSystem();
|
||||||
|
const singleOutputName = `${fileName}.sog`;
|
||||||
|
const singleOptions = {
|
||||||
|
...readOptions,
|
||||||
|
iterations: 10,
|
||||||
|
unbundled: false,
|
||||||
|
};
|
||||||
|
|
||||||
await writeFile(
|
await writeFile(
|
||||||
{
|
{
|
||||||
filename: outputName,
|
filename: singleOutputName,
|
||||||
outputFormat: getOutputFormat(outputName, fullOptions),
|
outputFormat: "sog",
|
||||||
dataTable: mainTable,
|
dataTable: mainTable,
|
||||||
options: { ...fullOptions, iterations: 8 },
|
options: singleOptions,
|
||||||
},
|
},
|
||||||
writeFs,
|
writeFsSingle,
|
||||||
);
|
);
|
||||||
|
|
||||||
const sogData = writeFs.results.get(outputName);
|
const singleSogData = writeFsSingle.results.get(singleOutputName);
|
||||||
if (!sogData) throw new Error("SOG-Erstellung fehlgeschlagen.");
|
if (singleSogData) {
|
||||||
|
generatedFiles.push({
|
||||||
|
name: singleOutputName,
|
||||||
|
blob: new Blob([new Uint8Array(singleSogData).slice().buffer], {
|
||||||
|
type: "application/octet-stream",
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// PASS 2: Generate Unbundled LOD SOGs + JSON
|
||||||
|
// ==========================================
|
||||||
|
self.postMessage({ type: "LOG", message: "Kompiliere LOD Chunks..." });
|
||||||
|
|
||||||
|
const writeFsLods = new MemoryFileSystem();
|
||||||
|
|
||||||
|
// MUST be exactly "meta.json" for unbundled SOG format
|
||||||
|
const lodsOutputName = "meta.json";
|
||||||
|
|
||||||
|
const lodOptions = {
|
||||||
|
...readOptions,
|
||||||
|
iterations: 10,
|
||||||
|
unbundled: true,
|
||||||
|
lodChunkCount: 512,
|
||||||
|
lodChunkExtent: 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
await writeFile(
|
||||||
|
{
|
||||||
|
filename: lodsOutputName,
|
||||||
|
outputFormat: "sog",
|
||||||
|
dataTable: mainTable,
|
||||||
|
options: lodOptions,
|
||||||
|
},
|
||||||
|
writeFsLods,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Jetzt iterieren wir über alle generierten Dateien im System
|
||||||
|
for (const [generatedName, data] of writeFsLods.results.entries()) {
|
||||||
|
const mimeType = generatedName.endsWith(".json")
|
||||||
|
? "application/json"
|
||||||
|
: "application/octet-stream";
|
||||||
|
|
||||||
|
generatedFiles.push({
|
||||||
|
name: generatedName,
|
||||||
|
blob: new Blob([new Uint8Array(data).slice().buffer], {
|
||||||
|
type: mimeType,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all Data to Frontend
|
||||||
self.postMessage({
|
self.postMessage({
|
||||||
type: "DONE",
|
type: "DONE",
|
||||||
data: {
|
data: {
|
||||||
sog: new Blob([new Uint8Array(sogData).slice().buffer], {
|
files: generatedFiles,
|
||||||
type: "application/octet-stream",
|
|
||||||
}),
|
|
||||||
fileName,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
|
|||||||
Reference in New Issue
Block a user