demo
Browse files
app.py
CHANGED
|
@@ -437,114 +437,191 @@ void main () {
|
|
| 437 |
}\`;
|
| 438 |
|
| 439 |
function createWorker() {
|
| 440 |
-
const
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 451 |
}
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
|
| 459 |
-
|
| 460 |
-
let row_offset = 0, offsets = {}, types = {};
|
| 461 |
-
const TYPE_MAP = {double: "getFloat64", int: "getInt32", uint: "getUint32", float: "getFloat32", short: "getInt16", ushort: "getUint16", uchar: "getUint8"};
|
| 462 |
-
for (let prop of header.slice(0, header_end_index).split("\\\\n").filter(k => k.startsWith("property "))) {
|
| 463 |
-
const [p, type, name] = prop.split(" ");
|
| 464 |
-
const arrayType = TYPE_MAP[type] || "getInt8";
|
| 465 |
-
types[name] = arrayType; offsets[name] = row_offset;
|
| 466 |
-
row_offset += parseInt(arrayType.replace(/[^\\\\d]/g, "")) / 8;
|
| 467 |
-
}
|
| 468 |
-
let dataView = new DataView(inputBuffer, header_end_index + header_end.length), row = 0;
|
| 469 |
-
const attrs = new Proxy({}, {
|
| 470 |
-
get(target, prop) {
|
| 471 |
-
if (!types[prop]) throw new Error(prop + " not found");
|
| 472 |
-
return dataView[types[prop]](row * row_offset + offsets[prop], true);
|
| 473 |
-
}
|
| 474 |
-
});
|
| 475 |
-
let sizeList = new Float32Array(vertexCount), sizeIndex = new Uint32Array(vertexCount);
|
| 476 |
-
for (row = 0; row < vertexCount; row++) {
|
| 477 |
-
sizeIndex[row] = row;
|
| 478 |
-
if (!types["scale_0"]) continue;
|
| 479 |
-
const size = Math.exp(attrs.scale_0) * Math.exp(attrs.scale_1) * Math.exp(attrs.scale_2);
|
| 480 |
-
const opacity = 1 / (1 + Math.exp(-attrs.opacity));
|
| 481 |
-
sizeList[row] = size * opacity;
|
| 482 |
-
}
|
| 483 |
-
sizeIndex.sort((b, a) => sizeList[a] - sizeList[b]);
|
| 484 |
-
const buffer = new ArrayBuffer(rowLength * vertexCount);
|
| 485 |
-
for (let j = 0; j < vertexCount; j++) {
|
| 486 |
-
row = sizeIndex[j];
|
| 487 |
-
const position = new Float32Array(buffer, j * rowLength, 3);
|
| 488 |
-
const scales = new Float32Array(buffer, j * rowLength + 12, 3);
|
| 489 |
-
const rgba = new Uint8ClampedArray(buffer, j * rowLength + 24, 4);
|
| 490 |
-
const rot = new Uint8ClampedArray(buffer, j * rowLength + 28, 4);
|
| 491 |
-
if (types["scale_0"]) {
|
| 492 |
-
const qlen = Math.sqrt(attrs.rot_0 ** 2 + attrs.rot_1 ** 2 + attrs.rot_2 ** 2 + attrs.rot_3 ** 2);
|
| 493 |
-
rot[0] = (attrs.rot_0 / qlen) * 128 + 128; rot[1] = (attrs.rot_1 / qlen) * 128 + 128;
|
| 494 |
-
rot[2] = (attrs.rot_2 / qlen) * 128 + 128; rot[3] = (attrs.rot_3 / qlen) * 128 + 128;
|
| 495 |
-
scales[0] = Math.exp(attrs.scale_0); scales[1] = Math.exp(attrs.scale_1); scales[2] = Math.exp(attrs.scale_2);
|
| 496 |
-
} else { scales[0] = scales[1] = scales[2] = 0.01; rot[0] = 255; rot[1] = rot[2] = rot[3] = 0; }
|
| 497 |
-
position[0] = attrs.x; position[1] = attrs.y; position[2] = attrs.z;
|
| 498 |
-
if (types["f_dc_0"]) {
|
| 499 |
-
const SH_C0 = 0.28209479177387814;
|
| 500 |
-
rgba[0] = (0.5 + SH_C0 * attrs.f_dc_0) * 255; rgba[1] = (0.5 + SH_C0 * attrs.f_dc_1) * 255; rgba[2] = (0.5 + SH_C0 * attrs.f_dc_2) * 255;
|
| 501 |
-
} else { rgba[0] = attrs.red; rgba[1] = attrs.green; rgba[2] = attrs.blue; }
|
| 502 |
-
rgba[3] = types["opacity"] ? (1 / (1 + Math.exp(-attrs.opacity))) * 255 : 255;
|
| 503 |
-
}
|
| 504 |
-
return buffer;
|
| 505 |
}
|
| 506 |
-
|
| 507 |
-
|
| 508 |
-
|
| 509 |
-
|
| 510 |
-
|
| 511 |
-
|
| 512 |
-
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
|
| 524 |
-
|
| 525 |
-
|
| 526 |
-
|
| 527 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 528 |
}
|
| 529 |
-
|
| 530 |
-
|
| 531 |
-
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
|
| 535 |
-
|
| 536 |
-
|
| 537 |
-
|
| 538 |
-
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
}
|
| 549 |
|
| 550 |
const invert4 = (a) => {
|
|
|
|
| 437 |
}\`;
|
| 438 |
|
| 439 |
function createWorker() {
|
| 440 |
+
const workerCode = `
|
| 441 |
+
let buffer, vertexCount = 0;
|
| 442 |
+
const rowLength = 32;
|
| 443 |
+
var _floatView = new Float32Array(1), _int32View = new Int32Array(_floatView.buffer);
|
| 444 |
+
|
| 445 |
+
function floatToHalf(float) {
|
| 446 |
+
_floatView[0] = float;
|
| 447 |
+
var f = _int32View[0];
|
| 448 |
+
var sign = (f >> 31) & 0x0001, exp = (f >> 23) & 0x00ff, frac = f & 0x007fffff, newExp;
|
| 449 |
+
if (exp == 0) newExp = 0;
|
| 450 |
+
else if (exp < 113) {
|
| 451 |
+
newExp = 0; frac |= 0x00800000; frac = frac >> (113 - exp);
|
| 452 |
+
if (frac & 0x01000000) { newExp = 1; frac = 0; }
|
| 453 |
+
} else if (exp < 142) newExp = exp - 112;
|
| 454 |
+
else { newExp = 31; frac = 0; }
|
| 455 |
+
return (sign << 15) | (newExp << 10) | (frac >> 13);
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
function packHalf2x16(x, y) {
|
| 459 |
+
return (floatToHalf(x) | (floatToHalf(y) << 16)) >>> 0;
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
function processPlyBuffer(inputBuffer) {
|
| 463 |
+
const ubuf = new Uint8Array(inputBuffer);
|
| 464 |
+
const header = new TextDecoder().decode(ubuf.slice(0, 10240));
|
| 465 |
+
const header_end = "end_header\\n";
|
| 466 |
+
const header_end_index = header.indexOf(header_end);
|
| 467 |
+
if (header_end_index < 0) throw new Error("Unable to read PLY header");
|
| 468 |
+
|
| 469 |
+
const match = /element vertex (\\d+)\\n/.exec(header);
|
| 470 |
+
const vertexCount = parseInt(match[1]);
|
| 471 |
+
console.log("Vertex Count:", vertexCount);
|
| 472 |
+
|
| 473 |
+
let row_offset = 0, offsets = {}, types = {};
|
| 474 |
+
const TYPE_MAP = {
|
| 475 |
+
double: "getFloat64", int: "getInt32", uint: "getUint32",
|
| 476 |
+
float: "getFloat32", short: "getInt16", ushort: "getUint16", uchar: "getUint8"
|
| 477 |
+
};
|
| 478 |
+
|
| 479 |
+
const lines = header.slice(0, header_end_index).split("\\n");
|
| 480 |
+
for (let line of lines) {
|
| 481 |
+
if (line.startsWith("property ")) {
|
| 482 |
+
const parts = line.split(" ");
|
| 483 |
+
const type = parts[1];
|
| 484 |
+
const name = parts[2];
|
| 485 |
+
const arrayType = TYPE_MAP[type] || "getInt8";
|
| 486 |
+
types[name] = arrayType;
|
| 487 |
+
offsets[name] = row_offset;
|
| 488 |
+
row_offset += parseInt(arrayType.replace(/[^\\d]/g, "")) / 8;
|
| 489 |
}
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
let dataView = new DataView(inputBuffer, header_end_index + header_end.length);
|
| 493 |
+
let row = 0;
|
| 494 |
+
const attrs = new Proxy({}, {
|
| 495 |
+
get(target, prop) {
|
| 496 |
+
if (!types[prop]) throw new Error(prop + " not found");
|
| 497 |
+
return dataView[types[prop]](row * row_offset + offsets[prop], true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
}
|
| 499 |
+
});
|
| 500 |
+
|
| 501 |
+
let sizeList = new Float32Array(vertexCount);
|
| 502 |
+
let sizeIndex = new Uint32Array(vertexCount);
|
| 503 |
+
for (row = 0; row < vertexCount; row++) {
|
| 504 |
+
sizeIndex[row] = row;
|
| 505 |
+
if (!types["scale_0"]) continue;
|
| 506 |
+
const size = Math.exp(attrs.scale_0) * Math.exp(attrs.scale_1) * Math.exp(attrs.scale_2);
|
| 507 |
+
const opacity = 1 / (1 + Math.exp(-attrs.opacity));
|
| 508 |
+
sizeList[row] = size * opacity;
|
| 509 |
+
}
|
| 510 |
+
sizeIndex.sort((b, a) => sizeList[a] - sizeList[b]);
|
| 511 |
+
|
| 512 |
+
const buffer = new ArrayBuffer(rowLength * vertexCount);
|
| 513 |
+
for (let j = 0; j < vertexCount; j++) {
|
| 514 |
+
row = sizeIndex[j];
|
| 515 |
+
const position = new Float32Array(buffer, j * rowLength, 3);
|
| 516 |
+
const scales = new Float32Array(buffer, j * rowLength + 12, 3);
|
| 517 |
+
const rgba = new Uint8ClampedArray(buffer, j * rowLength + 24, 4);
|
| 518 |
+
const rot = new Uint8ClampedArray(buffer, j * rowLength + 28, 4);
|
| 519 |
+
|
| 520 |
+
if (types["scale_0"]) {
|
| 521 |
+
const qlen = Math.sqrt(attrs.rot_0 ** 2 + attrs.rot_1 ** 2 + attrs.rot_2 ** 2 + attrs.rot_3 ** 2);
|
| 522 |
+
rot[0] = (attrs.rot_0 / qlen) * 128 + 128;
|
| 523 |
+
rot[1] = (attrs.rot_1 / qlen) * 128 + 128;
|
| 524 |
+
rot[2] = (attrs.rot_2 / qlen) * 128 + 128;
|
| 525 |
+
rot[3] = (attrs.rot_3 / qlen) * 128 + 128;
|
| 526 |
+
scales[0] = Math.exp(attrs.scale_0);
|
| 527 |
+
scales[1] = Math.exp(attrs.scale_1);
|
| 528 |
+
scales[2] = Math.exp(attrs.scale_2);
|
| 529 |
+
} else {
|
| 530 |
+
scales[0] = scales[1] = scales[2] = 0.01;
|
| 531 |
+
rot[0] = 255; rot[1] = rot[2] = rot[3] = 0;
|
| 532 |
}
|
| 533 |
+
|
| 534 |
+
position[0] = attrs.x;
|
| 535 |
+
position[1] = attrs.y;
|
| 536 |
+
position[2] = attrs.z;
|
| 537 |
+
|
| 538 |
+
if (types["f_dc_0"]) {
|
| 539 |
+
const SH_C0 = 0.28209479177387814;
|
| 540 |
+
rgba[0] = (0.5 + SH_C0 * attrs.f_dc_0) * 255;
|
| 541 |
+
rgba[1] = (0.5 + SH_C0 * attrs.f_dc_1) * 255;
|
| 542 |
+
rgba[2] = (0.5 + SH_C0 * attrs.f_dc_2) * 255;
|
| 543 |
+
} else {
|
| 544 |
+
rgba[0] = attrs.red;
|
| 545 |
+
rgba[1] = attrs.green;
|
| 546 |
+
rgba[2] = attrs.blue;
|
| 547 |
+
}
|
| 548 |
+
rgba[3] = types["opacity"] ? (1 / (1 + Math.exp(-attrs.opacity))) * 255 : 255;
|
| 549 |
+
}
|
| 550 |
+
return buffer;
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
function generateTexture() {
|
| 554 |
+
if (!buffer) return;
|
| 555 |
+
const f_buffer = new Float32Array(buffer);
|
| 556 |
+
const u_buffer = new Uint8Array(buffer);
|
| 557 |
+
const texwidth = 2048;
|
| 558 |
+
const texheight = Math.ceil((2 * vertexCount) / texwidth);
|
| 559 |
+
const texdata = new Uint32Array(texwidth * texheight * 4);
|
| 560 |
+
const texdata_c = new Uint8Array(texdata.buffer);
|
| 561 |
+
const texdata_f = new Float32Array(texdata.buffer);
|
| 562 |
+
|
| 563 |
+
for (let i = 0; i < vertexCount; i++) {
|
| 564 |
+
texdata_f[8 * i + 0] = f_buffer[8 * i + 0];
|
| 565 |
+
texdata_f[8 * i + 1] = f_buffer[8 * i + 1];
|
| 566 |
+
texdata_f[8 * i + 2] = f_buffer[8 * i + 2];
|
| 567 |
+
texdata_c[4 * (8 * i + 7) + 0] = u_buffer[32 * i + 24 + 0];
|
| 568 |
+
texdata_c[4 * (8 * i + 7) + 1] = u_buffer[32 * i + 24 + 1];
|
| 569 |
+
texdata_c[4 * (8 * i + 7) + 2] = u_buffer[32 * i + 24 + 2];
|
| 570 |
+
texdata_c[4 * (8 * i + 7) + 3] = u_buffer[32 * i + 24 + 3];
|
| 571 |
+
|
| 572 |
+
let scale = [f_buffer[8 * i + 3], f_buffer[8 * i + 4], f_buffer[8 * i + 5]];
|
| 573 |
+
let rot = [
|
| 574 |
+
(u_buffer[32 * i + 28] - 128) / 128,
|
| 575 |
+
(u_buffer[32 * i + 29] - 128) / 128,
|
| 576 |
+
(u_buffer[32 * i + 30] - 128) / 128,
|
| 577 |
+
(u_buffer[32 * i + 31] - 128) / 128
|
| 578 |
+
];
|
| 579 |
+
|
| 580 |
+
const M = [
|
| 581 |
+
1.0 - 2.0 * (rot[2] * rot[2] + rot[3] * rot[3]),
|
| 582 |
+
2.0 * (rot[1] * rot[2] + rot[0] * rot[3]),
|
| 583 |
+
2.0 * (rot[1] * rot[3] - rot[0] * rot[2]),
|
| 584 |
+
2.0 * (rot[1] * rot[2] - rot[0] * rot[3]),
|
| 585 |
+
1.0 - 2.0 * (rot[1] * rot[1] + rot[3] * rot[3]),
|
| 586 |
+
2.0 * (rot[2] * rot[3] + rot[0] * rot[1]),
|
| 587 |
+
2.0 * (rot[1] * rot[3] + rot[0] * rot[2]),
|
| 588 |
+
2.0 * (rot[2] * rot[3] - rot[0] * rot[1]),
|
| 589 |
+
1.0 - 2.0 * (rot[1] * rot[1] + rot[2] * rot[2])
|
| 590 |
+
].map((k, idx) => k * scale[Math.floor(idx / 3)]);
|
| 591 |
+
|
| 592 |
+
const sigma = [
|
| 593 |
+
M[0]*M[0] + M[3]*M[3] + M[6]*M[6],
|
| 594 |
+
M[0]*M[1] + M[3]*M[4] + M[6]*M[7],
|
| 595 |
+
M[0]*M[2] + M[3]*M[5] + M[6]*M[8],
|
| 596 |
+
M[1]*M[1] + M[4]*M[4] + M[7]*M[7],
|
| 597 |
+
M[1]*M[2] + M[4]*M[5] + M[7]*M[8],
|
| 598 |
+
M[2]*M[2] + M[5]*M[5] + M[8]*M[8]
|
| 599 |
+
];
|
| 600 |
+
|
| 601 |
+
texdata[8 * i + 4] = packHalf2x16(4 * sigma[0], 4 * sigma[1]);
|
| 602 |
+
texdata[8 * i + 5] = packHalf2x16(4 * sigma[2], 4 * sigma[3]);
|
| 603 |
+
texdata[8 * i + 6] = packHalf2x16(4 * sigma[4], 4 * sigma[5]);
|
| 604 |
+
}
|
| 605 |
+
self.postMessage({ texdata, texwidth, texheight, vertexCount }, [texdata.buffer]);
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
self.onmessage = (e) => {
|
| 609 |
+
console.log('[Worker] Message received');
|
| 610 |
+
if (e.data.ply) {
|
| 611 |
+
try {
|
| 612 |
+
console.log('[Worker] Processing PLY buffer...');
|
| 613 |
+
buffer = processPlyBuffer(e.data.ply);
|
| 614 |
+
vertexCount = Math.floor(buffer.byteLength / rowLength);
|
| 615 |
+
console.log('[Worker] Vertex count:', vertexCount);
|
| 616 |
+
generateTexture();
|
| 617 |
+
console.log('[Worker] Texture sent');
|
| 618 |
+
} catch (error) {
|
| 619 |
+
console.error('[Worker] Error:', error);
|
| 620 |
+
}
|
| 621 |
+
}
|
| 622 |
+
};
|
| 623 |
+
`;
|
| 624 |
+
return new Worker(URL.createObjectURL(new Blob([workerCode], { type: 'application/javascript' })));
|
| 625 |
}
|
| 626 |
|
| 627 |
const invert4 = (a) => {
|