|
252 | 252 | </script> |
253 | 253 | <script type="module"> |
254 | 254 | import * as GaussianSplats3D from 'gaussian-splats-3d'; |
| 255 | + import * as THREE from 'three'; |
255 | 256 |
|
256 | | - function convertPLYToSplatBuffer(plyBuffer, compressionLevel, alphaRemovalThreshold, blockSize, bucketSize) { |
257 | | - const plyParser = new GaussianSplats3D.PlyParser(plyBuffer); |
258 | | - return plyParser.parseToSplatBuffer(compressionLevel, alphaRemovalThreshold, blockSize, bucketSize); |
| 257 | + function convertPLYToSplatBuffer(plyBufferData, compressionLevel, alphaRemovalThreshold, sectionSize, sceneCenter, blockSize, bucketSize) { |
| 258 | + const plyParser = new GaussianSplats3D.PlyParser(plyBufferData.data); |
| 259 | + const splatArray = plyParser.parseToUncompressedSplatArray(); |
| 260 | + plyBufferData.data = null; |
| 261 | + const splatBufferGenerator = GaussianSplats3D.SplatBufferGenerator.getStandardGenerator(alphaRemovalThreshold, compressionLevel, sectionSize, sceneCenter, blockSize, bucketSize); |
| 262 | + return splatBufferGenerator.generateFromUncompressedSplatArray(splatArray); |
259 | 263 | } |
260 | 264 |
|
261 | | - function convertStandardSplatToSplatBuffer(bufferData, compressionLevel, alphaRemovalThreshold, blockSize, bucketSize){ |
262 | | - const splatArray = GaussianSplats3D.SplatLoader.parseStandardSplatToUncompressedSplatArray(bufferData); |
263 | | - const splatCompressor = new GaussianSplats3D.SplatCompressor(compressionLevel, alphaRemovalThreshold, blockSize, bucketSize); |
264 | | - return splatCompressor.uncompressedSplatArrayToSplatBuffer(splatArray); |
| 265 | + function convertStandardSplatToSplatBuffer(bufferData, compressionLevel, alphaRemovalThreshold, sectionSize, blockSize, bucketSize){ |
| 266 | + const splatArray = GaussianSplats3D.SplatParser.parseStandardSplatToUncompressedSplatArray(bufferData); |
| 267 | + const splatBufferGenerator = GaussianSplats3D.SplatBufferGenerator.getStandardGenerator(alphaRemovalThreshold, compressionLevel, sectionSize, sceneCenter, blockSize, bucketSize); |
| 268 | + return splatBufferGenerator.generateFromUncompressedSplatArray(splatArray); |
265 | 269 | } |
266 | 270 |
|
267 | 271 | function isPlyFile(fileName) { |
268 | 272 | return fileName.toLowerCase().trim().endsWith('.ply'); |
269 | 273 | } |
270 | 274 |
|
271 | | - function fileBufferToSplatBuffer(fileBufferData, isPly, isStandardSplat, compressionLevel, alphaRemovalThreshold, blockSize, bucketSize) { |
| 275 | + function fileBufferToSplatBuffer(fileBufferData, format, compressionLevel, alphaRemovalThreshold, sectionSize, sceneCenter, blockSize, bucketSize) { |
272 | 276 | let splatBuffer; |
273 | | - if (isPly) { |
274 | | - splatBuffer = convertPLYToSplatBuffer(fileBufferData, compressionLevel, alphaRemovalThreshold, blockSize, bucketSize); |
| 277 | + if (format === GaussianSplats3D.SceneFormat.Ply) { |
| 278 | + splatBuffer = convertPLYToSplatBuffer(fileBufferData, compressionLevel, alphaRemovalThreshold, sectionSize, sceneCenter, blockSize, bucketSize); |
275 | 279 | } else { |
276 | | - if (isStandardSplat) { |
277 | | - splatBuffer = convertStandardSplatToSplatBuffer(fileBufferData, compressionLevel, alphaRemovalThreshold, blockSize, bucketSize); |
| 280 | + if (format === GaussianSplats3D.SceneFormat.Splat) { |
| 281 | + splatBuffer = convertStandardSplatToSplatBuffer(fileBufferData.data, compressionLevel, alphaRemovalThreshold, sectionSize, sceneCenter, blockSize, bucketSize); |
278 | 282 | } else { |
279 | | - splatBuffer = new GaussianSplats3D.SplatBuffer(fileBufferData); |
| 283 | + GaussianSplats3D.KSplatLoader.checkVersion(fileBufferData.data); |
| 284 | + splatBuffer = new GaussianSplats3D.SplatBuffer(fileBufferData.data); |
280 | 285 | } |
281 | 286 | } |
282 | 287 | return splatBuffer; |
|
313 | 318 | const conversionFile = document.getElementById("conversionFile"); |
314 | 319 | const compressionLevel = parseInt(document.getElementById("compressionLevel").value); |
315 | 320 | const alphaRemovalThreshold = parseInt(document.getElementById("alphaRemovalThreshold").value); |
| 321 | + const sectionSize = 0; |
| 322 | + let sceneCenterArray = document.getElementById("sceneCenter").value; |
316 | 323 | const blockSize = parseFloat(document.getElementById("blockSize").value); |
317 | 324 | const bucketSize = parseInt(document.getElementById("bucketSize").value); |
318 | 325 |
|
| 326 | + sceneCenterArray = sceneCenterArray.split(','); |
| 327 | + |
| 328 | + if (sceneCenterArray.length !== 3) { |
| 329 | + setViewError("Scene center must contain 3 elements."); |
| 330 | + return; |
| 331 | + } |
| 332 | + |
| 333 | + for (let i = 0; i < 3; i++) { |
| 334 | + sceneCenterArray[i] = parseFloat(sceneCenterArray[i]); |
| 335 | + |
| 336 | + if (isNaN(sceneCenterArray[i])) { |
| 337 | + setViewError("Invalid scene center."); |
| 338 | + return; |
| 339 | + } |
| 340 | + } |
| 341 | + |
| 342 | + const sceneCenter = new THREE.Vector3().fromArray(sceneCenterArray); |
| 343 | + |
319 | 344 | if (isNaN(compressionLevel) || compressionLevel < 0 || compressionLevel > 1) { |
320 | 345 | setConversionError("Invalid compression level."); |
321 | 346 | return; |
|
356 | 381 | setConversionStatus("Parsing file..."); |
357 | 382 | setConversionLoadingIconVisibility(true); |
358 | 383 | setConversionCheckIconVisibility(false); |
359 | | - const conversionFileName = conversionFile.files[0].name; |
360 | | - const isPly = isPlyFile(conversionFileName); |
361 | | - const isStandardSplat = GaussianSplats3D.SplatLoader.isStandardSplatFormat(conversionFileName); |
| 384 | + const conversionFileName = conversionFile.files[0].name.trim(); |
| 385 | + const format = GaussianSplats3D.LoaderUtils.sceneFormatFromPath(conversionFileName); |
| 386 | + const fileData = {data: fileReader.result}; |
362 | 387 | window.setTimeout(() => { |
363 | 388 | try { |
364 | | - const splatBuffer = fileBufferToSplatBuffer(fileReader.result, isPly, isStandardSplat, compressionLevel, |
365 | | - alphaRemovalThreshold, blockSize, bucketSize); |
366 | | - new GaussianSplats3D.SplatLoader(splatBuffer).downloadFile('converted_file.ksplat'); |
| 389 | + const splatBuffer = fileBufferToSplatBuffer(fileData, format, compressionLevel, |
| 390 | + alphaRemovalThreshold, sectionSize, sceneCenter, blockSize, bucketSize); |
| 391 | + GaussianSplats3D.KSplatLoader.downloadFile(splatBuffer, 'converted_file.ksplat'); |
367 | 392 | conversionDone(); |
368 | 393 | } catch (e) { |
369 | 394 | conversionDone(e); |
|
456 | 481 | } |
457 | 482 | } |
458 | 483 |
|
459 | | - const viewFileName = viewFile.files[0].name; |
460 | | - const isPly = isPlyFile(viewFileName); |
461 | | - const isStandardSplat = GaussianSplats3D.SplatLoader.isStandardSplatFormat(viewFileName); |
| 484 | + const viewFileName = viewFile.files[0].name.trim(); |
| 485 | + const format = GaussianSplats3D.LoaderUtils.sceneFormatFromPath(viewFileName); |
462 | 486 |
|
463 | 487 | currentAlphaRemovalThreshold = alphaRemovalThreshold; |
464 | 488 | currentCameraUpArray = cameraUpArray; |
|
468 | 492 | const fileReader = new FileReader(); |
469 | 493 | fileReader.onload = function(){ |
470 | 494 | try { |
471 | | - runViewer(fileReader.result, isPly, isStandardSplat, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray); |
| 495 | + runViewer(fileReader.result, format, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray); |
472 | 496 | } catch (e) { |
| 497 | + console.error(e); |
473 | 498 | setViewError("Could not view scene."); |
474 | 499 | } |
475 | 500 | } |
|
505 | 530 | } |
506 | 531 | }); |
507 | 532 |
|
508 | | - function runViewer(splatBufferData, isPly, isStandardSplat, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray) { |
| 533 | + function runViewer(splatBufferData, format, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray) { |
509 | 534 | const viewerOptions = { |
510 | 535 | 'cameraUp': cameraUpArray, |
511 | 536 | 'initialCameraPosition': cameraPositionArray, |
|
516 | 541 | 'splatAlphaRemovalThreshold': alphaRemovalThreshold |
517 | 542 | }; |
518 | 543 |
|
519 | | - const splatBuffer = fileBufferToSplatBuffer(splatBufferData, isPly, isStandardSplat, 0, alphaRemovalThreshold); |
| 544 | + const splatBuffer = fileBufferToSplatBuffer({data: splatBufferData}, format, 0, alphaRemovalThreshold); |
520 | 545 | document.getElementById("demo-content").style.display = 'none'; |
521 | 546 | document.body.style.backgroundColor = "#000000"; |
522 | 547 | history.pushState("ViewSplat", null); |
|
575 | 600 | <img src="assets/images/stump.png" class="demo-scene-panel-image"> |
576 | 601 | <span class="small-title">Stump</span> |
577 | 602 | </div> |
| 603 | + <div class="demo-scene-panel" onclick="openDemo('bonsai')"> |
| 604 | + <img src="assets/images/bonsai.png" class="demo-scene-panel-image"> |
| 605 | + <span class="small-title">Bonsai</span> |
| 606 | + </div> |
578 | 607 | <div class="demo-scene-panel" onclick="openDemo('dynamic_scenes')"> |
579 | 608 | <img src="assets/images/dynamic_scenes.png" class="demo-scene-panel-image"> |
580 | 609 | <span class="small-title">Dynamic scenes</span> |
|
656 | 685 | <span id="viewError" style="color: #ff0000"></span> |
657 | 686 | </div> |
658 | 687 |
|
659 | | - <div id ="conversion-panel" class="splat-panel" style="height:360px;"> |
| 688 | + <div id ="conversion-panel" class="splat-panel" style="height:380px;"> |
660 | 689 | <br> |
661 | 690 | <span class="small-title">Convert a <span class="file-ext">.ply</span> or <span class="file-ext">.splat</span> to <span class="file-ext">.ksplat</span></span> |
662 | 691 | <br> |
|
682 | 711 | <input id="alphaRemovalThreshold" type="text" class="text-input" style="width: 50px" value="1"></input> |
683 | 712 | <span style="color:#888888">(1 - 255)</span> |
684 | 713 | </td> |
685 | | - </tr> |
| 714 | + </tr> |
| 715 | + <tr> |
| 716 | + <td> |
| 717 | + Scene center: |
| 718 | + </td> |
| 719 | + <td> |
| 720 | + <input id="sceneCenter" type="text" class="text-input" style="width: 50px" value="0, 0, 0"></input> |
| 721 | + </td> |
| 722 | + </tr> |
686 | 723 | <tr> |
687 | 724 | <td> |
688 | 725 | Compression level: |
|
739 | 776 | <span id="conversionError" style="color: #ff0000"></span> |
740 | 777 | </div> |
741 | 778 |
|
742 | | - <div id ="controls-panel" class="splat-panel" style="height:360px;"> |
| 779 | + <div id ="controls-panel" class="splat-panel" style="height:380px;"> |
743 | 780 |
|
744 | 781 | <br> |
745 | 782 | <span class="small-title">Mouse input</span> |
|
0 commit comments