Spaces:
Running
Running
File size: 5,471 Bytes
352fb85 |
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 125 126 127 128 129 130 131 132 133 134 135 136 |
import { Camera } from "../cameras/Camera";
import type { Scene } from "../core/Scene";
import { Matrix3 } from "../math/Matrix3";
import { Quaternion } from "../math/Quaternion";
import { Vector3 } from "../math/Vector3";
import { Splatv } from "../splats/Splatv";
import { SplatvData } from "../splats/SplatvData";
import { initiateFetchRequest, loadRequestDataIntoBuffer } from "../utils/LoaderUtils";
class SplatvLoader {
static async LoadAsync(
url: string,
scene: Scene,
camera: Camera | null,
onProgress?: (progress: number) => void,
useCache: boolean = false,
): Promise<Splatv> {
const res: Response = await initiateFetchRequest(url, useCache);
const buffer = await loadRequestDataIntoBuffer(res, onProgress);
return this._ParseSplatvBuffer(buffer.buffer, scene, camera);
}
static async LoadFromFileAsync(
file: File,
scene: Scene,
camera: Camera | null,
onProgress?: (progress: number) => void,
): Promise<Splatv> {
const reader = new FileReader();
let splatv: Splatv | null = null;
reader.onload = (e) => {
splatv = this._ParseSplatvBuffer(e.target!.result as ArrayBuffer, scene, camera);
};
reader.onprogress = (e) => {
onProgress?.(e.loaded / e.total);
};
reader.readAsArrayBuffer(file);
await new Promise<void>((resolve) => {
reader.onloadend = () => {
resolve();
};
});
if (!splatv) {
throw new Error("Failed to load splatv file");
}
return splatv;
}
private static _ParseSplatvBuffer(inputBuffer: ArrayBuffer, scene: Scene, camera: Camera | null): Splatv {
let result: Splatv | null = null;
const handleChunk = (
chunk: { size: number; type: string; texwidth: number; texheight: number },
buffer: Uint8Array,
chunks: { size: number; type: string }[],
) => {
if (chunk.type === "magic") {
const intView = new Int32Array(buffer.buffer);
if (intView[0] !== 0x674b) {
throw new Error("Invalid splatv file");
}
chunks.push({ size: intView[1], type: "chunks" });
} else if (chunk.type === "chunks") {
const splatChunks = JSON.parse(new TextDecoder("utf-8").decode(buffer));
if (splatChunks.length == 0) {
throw new Error("Invalid splatv file");
} else if (splatChunks.length > 1) {
console.warn("Splatv file contains more than one chunk, only the first one will be loaded");
}
const chunk = splatChunks[0];
const cameras = chunk.cameras as { position: number[]; rotation: number[][] }[];
if (camera && cameras && cameras.length) {
const cameraData = cameras[0];
const position = new Vector3(
cameraData.position[0],
cameraData.position[1],
cameraData.position[2],
);
const rotation = Quaternion.FromMatrix3(
new Matrix3(
cameraData.rotation[0][0],
cameraData.rotation[0][1],
cameraData.rotation[0][2],
cameraData.rotation[1][0],
cameraData.rotation[1][1],
cameraData.rotation[1][2],
cameraData.rotation[2][0],
cameraData.rotation[2][1],
cameraData.rotation[2][2],
),
);
camera.position = position;
camera.rotation = rotation;
}
chunks.push(chunk);
} else if (chunk.type === "splat") {
const data = SplatvData.Deserialize(buffer, chunk.texwidth, chunk.texheight);
const splatv = new Splatv(data);
scene.addObject(splatv);
result = splatv;
}
};
const ubuf = new Uint8Array(inputBuffer);
const chunks: { size: number; type: string; texwidth: number; texheight: number }[] = [
{ size: 8, type: "magic", texwidth: 0, texheight: 0 },
];
let chunk: { size: number; type: string; texwidth: number; texheight: number } | undefined = chunks.shift();
let buffer = new Uint8Array(chunk!.size);
let offset = 0;
let inputOffset = 0;
while (chunk) {
while (offset < chunk.size) {
const sizeToRead = Math.min(chunk.size - offset, ubuf.length - inputOffset);
buffer.set(ubuf.subarray(inputOffset, inputOffset + sizeToRead), offset);
offset += sizeToRead;
inputOffset += sizeToRead;
}
handleChunk(chunk, buffer, chunks);
if (result) {
return result;
}
chunk = chunks.shift();
if (chunk) {
buffer = new Uint8Array(chunk.size);
offset = 0;
}
}
throw new Error("Invalid splatv file");
}
}
export { SplatvLoader };
|