|
121 | 121 | margin-right: 8px; |
122 | 122 | } |
123 | 123 |
|
124 | | - .ply-loader { |
| 124 | + .loading-icon { |
125 | 125 | width: 35px; |
126 | 126 | padding: 15px; |
127 | 127 | background: #324d70; |
|
198 | 198 | <script type="module"> |
199 | 199 | import * as GaussianSplats3D from 'gaussian-splats-3d'; |
200 | 200 |
|
201 | | - function convertPLY(plyBuffer, compressionLevel, alphaRemovalThreshold) { |
| 201 | + function convertPLYToSplatBuffer(plyBuffer, compressionLevel, alphaRemovalThreshold) { |
202 | 202 | const plyParser = new GaussianSplats3D.PlyParser(plyBuffer); |
203 | | - const splatBuffer = plyParser.parseToSplatBuffer(compressionLevel, alphaRemovalThreshold); |
204 | | - new GaussianSplats3D.SplatLoader(splatBuffer).downloadFile('converted_file.splat'); |
| 203 | + return plyParser.parseToSplatBuffer(compressionLevel, alphaRemovalThreshold); |
205 | 204 | } |
206 | 205 |
|
207 | 206 | window.onFileChange = function(arg, fileNameLabelID) { |
|
256 | 255 | setConversionCheckIconVisibility(false); |
257 | 256 | window.setTimeout(() => { |
258 | 257 | try { |
259 | | - convertPLY(fileReader.result, compressionLevel, alphaRemovalThreshold); |
| 258 | + const splatBuffer = convertPLYToSplatBuffer(fileReader.result, compressionLevel, alphaRemovalThreshold); |
| 259 | + new GaussianSplats3D.SplatLoader(splatBuffer).downloadFile('converted_file.splat'); |
260 | 260 | conversionDone(); |
261 | 261 | } catch (e) { |
262 | 262 | conversionDone(e); |
|
285 | 285 | } |
286 | 286 |
|
287 | 287 | function setConversionLoadingIconVisibility(visible) { |
288 | | - document.getElementById('loading-icon').style.display = visible ? 'block' : 'none'; |
| 288 | + document.getElementById('conversion-loading-icon').style.display = visible ? 'block' : 'none'; |
289 | 289 | } |
290 | 290 |
|
291 | 291 | function setConversionCheckIconVisibility(visible) { |
|
308 | 308 | if (!viewFile.files[0]) { |
309 | 309 | setViewError("Please choose a file to view."); |
310 | 310 | return; |
311 | | - } else if (isNaN(alphaRemovalThreshold) || alphaRemovalThreshold <0 || alphaRemovalThreshold > 255) { |
| 311 | + } else if (isNaN(alphaRemovalThreshold) || alphaRemovalThreshold < 0 || alphaRemovalThreshold > 255) { |
312 | 312 | setViewError("Invalid alpha remval threshold."); |
313 | 313 | return; |
314 | 314 | } |
|
328 | 328 | return; |
329 | 329 | } |
330 | 330 |
|
| 331 | + const viewFileName = viewFile.files[0].name; |
| 332 | + const isPly = viewFileName.toLowerCase().trim().endsWith('.ply'); |
| 333 | + |
331 | 334 | for (let i = 0; i < 3; i++) { |
332 | 335 | cameraUpArray[i] = parseFloat(cameraUpArray[i]); |
333 | 336 | cameraPositionArray[i] = parseFloat(cameraPositionArray[i]); |
|
356 | 359 | try { |
357 | 360 | const fileReader = new FileReader(); |
358 | 361 | fileReader.onload = function(){ |
359 | | - document.getElementById("table-of-contents-container").style.display = 'none'; |
360 | | - document.body.style.backgroundColor = "#000000"; |
361 | | - history.pushState("ViewSplat", null); |
362 | | - runViewer(fileReader.result, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray); |
| 362 | + try { |
| 363 | + runViewer(fileReader.result, isPly, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray); |
| 364 | + } catch (e) { |
| 365 | + setViewError("Could not view .SPLAT file"); |
| 366 | + } |
363 | 367 | } |
364 | | - setViewStatus("Loading .SPLAT..."); |
| 368 | + setViewStatus("Loading scene..."); |
365 | 369 | fileReader.readAsArrayBuffer(viewFile.files[0]); |
366 | 370 | } catch (e) { |
367 | 371 | console.error(e); |
|
370 | 374 | } |
371 | 375 |
|
372 | 376 | function setViewError(msg) { |
| 377 | + setViewLoadingIconVisibility(false); |
373 | 378 | document.getElementById("viewStatus").innerHTML = ""; |
374 | 379 | document.getElementById("viewError").innerHTML = msg; |
375 | 380 | } |
376 | 381 |
|
377 | 382 | function setViewStatus(msg) { |
| 383 | + setViewLoadingIconVisibility(true); |
378 | 384 | document.getElementById("viewError").innerHTML = ""; |
379 | 385 | document.getElementById("viewStatus").innerHTML = msg; |
380 | 386 | } |
381 | 387 |
|
| 388 | + function setViewLoadingIconVisibility(visible) { |
| 389 | + document.getElementById('view-loading-icon').style.display = visible ? 'block' : 'none'; |
| 390 | + } |
| 391 | + |
382 | 392 | window.addEventListener("popstate", (event) => { |
383 | 393 | if (currentAlphaRemovalThreshold !== undefined) { |
384 | 394 | window.location = 'index.html?art=' + currentAlphaRemovalThreshold + '&cu=' + currentCameraUpArray + "&cp=" + currentCameraPositionArray + "&cla=" + currentCameraLookAtArray; |
|
387 | 397 | } |
388 | 398 | }); |
389 | 399 |
|
390 | | - function runViewer(splatBufferData, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray) { |
391 | | - const splatBuffer = new GaussianSplats3D.SplatBuffer(splatBufferData); |
392 | | - const viewer = new GaussianSplats3D.Viewer({ |
| 400 | + function runViewer(splatBufferData, isPly, alphaRemovalThreshold, cameraUpArray, cameraPositionArray, cameraLookAtArray) { |
| 401 | + const viewerOptions = { |
393 | 402 | 'cameraUp': cameraUpArray, |
394 | 403 | 'initialCameraPosition': cameraPositionArray, |
395 | 404 | 'initialCameraLookAt': cameraLookAtArray |
396 | | - }); |
397 | | - viewer.loadSplatBuffer(splatBuffer, { |
| 405 | + }; |
| 406 | + const sceneOptions = { |
398 | 407 | 'halfPrecisionCovariancesOnGPU': true, |
399 | 408 | 'splatAlphaRemovalThreshold': alphaRemovalThreshold |
400 | | - }) |
| 409 | + }; |
| 410 | + let splatBuffer; |
| 411 | + if (isPly) { |
| 412 | + splatBuffer = convertPLYToSplatBuffer(splatBufferData, 0, alphaRemovalThreshold); |
| 413 | + } else { |
| 414 | + splatBuffer = new GaussianSplats3D.SplatBuffer(splatBufferData); |
| 415 | + } |
| 416 | + |
| 417 | + document.getElementById("table-of-contents-container").style.display = 'none'; |
| 418 | + document.body.style.backgroundColor = "#000000"; |
| 419 | + history.pushState("ViewSplat", null); |
| 420 | + const viewer = new GaussianSplats3D.Viewer(viewerOptions); |
| 421 | + viewer.loadSplatBuffer(splatBuffer, sceneOptions) |
401 | 422 | .then(() => { |
402 | 423 | viewer.start(); |
403 | 424 | }); |
|
418 | 439 | <div id="table-of-contents-container" class="table-of-contents-container"> |
419 | 440 | <div class="table-of-contents-inner-container"> |
420 | 441 | <br> |
421 | | - <span class="title">View demo scene</span> |
| 442 | + <span class="title">Demo scenes</span> |
422 | 443 | <br> |
423 | 444 | <div class="table-of-contents-row"> |
424 | 445 | <div class="table-of-contents-entry" onclick="openDemo('garden')"> |
|
437 | 458 | <br> |
438 | 459 | <br> |
439 | 460 | <div class="table-of-contents-row"> |
440 | | - <div id ="conversion-panel" class="splat-panel"> |
| 461 | + |
| 462 | + <div id ="view-panel" class="splat-panel" style="height:300px;"> |
441 | 463 | <br> |
442 | | - <span style="font-weight: bold">Convert your own .PLY to .SPLAT</span> |
| 464 | + <span style="font-weight: bold">View a .PLY or .SPLAT file</span> |
443 | 465 | <br> |
444 | 466 | <br> |
445 | 467 | <table style="text-align: left;"> |
446 | 468 | <tr> |
447 | 469 | <td colspan="2"> |
448 | | - <label for="conversionFile"> |
| 470 | + <label for="viewFile"> |
449 | 471 | <span class="glyphicon glyphicon-folder-open" aria-hidden="true"><span class="button">Choose file</span></span> |
450 | | - <input type="file" id="conversionFile" style="display:none" onchange="window.onFileChange(this, 'conversionFileName')"> |
| 472 | + <input type="file" id="viewFile" style="display:none" onchange="window.onFileChange(this, 'viewFileName')"> |
451 | 473 | </label> |
452 | | - <span id="conversionFileName" style="padding-left:15px; color: #333333">(No file chosen)</span> |
| 474 | + <span id="viewFileName" style="padding-left:15px; color: #333333">(No file chosen)</span> |
453 | 475 | </td> |
454 | 476 | </tr> |
455 | 477 | <tr> |
456 | 478 | <td colspan="2" style="height: 10px;"></td> |
457 | 479 | </tr> |
458 | 480 | <tr> |
459 | 481 | <td> |
460 | | - Compression level: |
| 482 | + Minimum alpha: |
461 | 483 | </td> |
462 | 484 | <td> |
463 | | - <input id="compressionLevel" type="text" class="text-input" style="width: 50px" value="1"></input> |
| 485 | + <input id="alphaRemovalThresholdView" type="text" class="text-input" style="width: 50px" value="1"></input> |
| 486 | + <span style="color:#888888">(1 - 255)</span> |
464 | 487 | </td> |
465 | 488 | </tr> |
466 | 489 | <tr> |
467 | 490 | <td> |
468 | | - Alpha removal threshold: |
| 491 | + Camera up: |
469 | 492 | </td> |
470 | 493 | <td> |
471 | | - <input id="alphaRemovalThreshold" type="text" class="text-input" style="width: 50px" value="1"></input> |
| 494 | + <input id="cameraUp" type="text" class="text-input" style="width: 90px" value="0, 1, 0"></input> |
| 495 | + </td> |
| 496 | + </tr> |
| 497 | + <tr> |
| 498 | + <td> |
| 499 | + Camera position: |
| 500 | + </td> |
| 501 | + <td> |
| 502 | + <input id="cameraPosition" type="text" class="text-input" style="width: 90px" value="0, 1, 0"></input> |
| 503 | + </td> |
| 504 | + </tr> |
| 505 | + <tr> |
| 506 | + <td> |
| 507 | + Camera look-at: |
| 508 | + </td> |
| 509 | + <td> |
| 510 | + <input id="cameraLookAt" type="text" class="text-input" style="width: 90px" value="1, 0, 0"></input> |
472 | 511 | </td> |
473 | 512 | </tr> |
474 | 513 | </table> |
475 | 514 | <br> |
476 | | - <span id="convertButton" class="button" onclick="window.convertPlyFile()">Convert</span> |
| 515 | + <span class="button" onclick="window.viewSplat()">View</span> |
| 516 | + |
| 517 | + <span class="button" onclick="reset()">Reset</span> |
477 | 518 | <br> |
478 | 519 | <br> |
479 | | - <div style="text-align: center;"> |
480 | 520 | <div style="display: flex; flex-direction: row; width: 230px; margin: auto;"> |
481 | 521 | <div style="width: 50px;"> |
482 | | - <div id="loading-icon" class="ply-loader" style="display: none;"> |
483 | | - </div> |
484 | | - <div id="check-icon" class="check" style="display: none;"> |
485 | | - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="35px" width="35px" version="1.1" id="Capa_1" viewBox="0 0 17.837 17.837" xml:space="preserve" style="background:#ffffff00;"> |
486 | | - <g> |
487 | | - <path style="fill:#00790a;" d="M16.145,2.571c-0.272-0.273-0.718-0.273-0.99,0L6.92,10.804l-4.241-4.27 c-0.272-0.274-0.715-0.274-0.989,0L0.204,8.019c-0.272,0.271-0.272,0.717,0,0.99l6.217,6.258c0.272,0.271,0.715,0.271,0.99,0 L17.63,5.047c0.276-0.273,0.276-0.72,0-0.994L16.145,2.571z"/> |
488 | | - </g> |
489 | | - </svg> |
490 | | - </div> |
| 522 | + <div id="view-loading-icon" class="loading-icon" style="display: none;"> |
| 523 | + </div> |
491 | 524 | </div> |
492 | | - <div id="conversionStatus" style="text-align: left; color: #333333; margin-top: 7px; margin-left: 15px; width: 175px"></div> |
493 | | - </div> |
| 525 | + <div id="viewStatus" style="text-align: left; color: #333333; margin-top: 7px; margin-left: 15px; width: 175px"></div> |
494 | 526 | </div> |
495 | | - <span id="conversionError" style="color: #ff0000"></span> |
| 527 | + <span id="viewError" style="color: #ff0000"></span> |
496 | 528 | <br> |
497 | 529 | </div> |
498 | | - |
499 | | - <div id ="view-panel" class="splat-panel"> |
| 530 | + |
| 531 | + <div id ="conversion-panel" class="splat-panel"> |
500 | 532 | <br> |
501 | | - <span style="font-weight: bold">View a .SPLAT file</span> |
| 533 | + <span style="font-weight: bold">Convert your own .PLY to .SPLAT</span> |
502 | 534 | <br> |
503 | 535 | <br> |
504 | 536 | <table style="text-align: left;"> |
505 | 537 | <tr> |
506 | 538 | <td colspan="2"> |
507 | | - <label for="viewFile"> |
| 539 | + <label for="conversionFile"> |
508 | 540 | <span class="glyphicon glyphicon-folder-open" aria-hidden="true"><span class="button">Choose file</span></span> |
509 | | - <input type="file" id="viewFile" style="display:none" onchange="window.onFileChange(this, 'viewFileName')"> |
| 541 | + <input type="file" id="conversionFile" style="display:none" onchange="window.onFileChange(this, 'conversionFileName')"> |
510 | 542 | </label> |
511 | | - <span id="viewFileName" style="padding-left:15px; color: #333333">(No file chosen)</span> |
| 543 | + <span id="conversionFileName" style="padding-left:15px; color: #333333">(No file chosen)</span> |
512 | 544 | </td> |
513 | 545 | </tr> |
514 | 546 | <tr> |
515 | 547 | <td colspan="2" style="height: 10px;"></td> |
516 | 548 | </tr> |
517 | 549 | <tr> |
518 | 550 | <td> |
519 | | - Alpha removal threshold: |
520 | | - </td> |
521 | | - <td> |
522 | | - <input id="alphaRemovalThresholdView" type="text" class="text-input" style="width: 50px" value="1"></input> |
523 | | - </td> |
524 | | - </tr> |
525 | | - <tr> |
526 | | - <td> |
527 | | - Camera up: |
528 | | - </td> |
529 | | - <td> |
530 | | - <input id="cameraUp" type="text" class="text-input" style="width: 90px" value="0, 1, 0"></input> |
531 | | - </td> |
532 | | - </tr> |
533 | | - <tr> |
534 | | - <td> |
535 | | - Camera position: |
| 551 | + Compression level: |
536 | 552 | </td> |
537 | 553 | <td> |
538 | | - <input id="cameraPosition" type="text" class="text-input" style="width: 90px" value="0, 1, 0"></input> |
| 554 | + <input id="compressionLevel" type="text" class="text-input" style="width: 50px" value="1"></input> |
| 555 | + <span style="color:#888888">(0 or 1)</span> |
539 | 556 | </td> |
540 | 557 | </tr> |
541 | 558 | <tr> |
542 | 559 | <td> |
543 | | - Camera look-at: |
| 560 | + Minimum alpha: |
544 | 561 | </td> |
545 | 562 | <td> |
546 | | - <input id="cameraLookAt" type="text" class="text-input" style="width: 90px" value="1, 0, 0"></input> |
| 563 | + <input id="alphaRemovalThreshold" type="text" class="text-input" style="width: 50px" value="1"></input> |
| 564 | + <span style="color:#888888">(1 - 255)</span> |
547 | 565 | </td> |
548 | 566 | </tr> |
549 | 567 | </table> |
550 | 568 | <br> |
551 | | - <span class="button" onclick="window.viewSplat()">View</span> |
552 | | - |
553 | | - <span class="button" onclick="reset()">Reset</span> |
| 569 | + <span id="convertButton" class="button" onclick="window.convertPlyFile()">Convert</span> |
554 | 570 | <br> |
555 | 571 | <br> |
556 | | - <span id="viewStatus" style="color: #333333"></span> |
557 | | - <span id="viewError" style="color: #ff0000"></span> |
| 572 | + <div style="text-align: center;"> |
| 573 | + <div style="display: flex; flex-direction: row; width: 230px; margin: auto;"> |
| 574 | + <div style="width: 50px;"> |
| 575 | + <div id="conversion-loading-icon" class="loading-icon" style="display: none;"> |
| 576 | + </div> |
| 577 | + <div id="check-icon" class="check" style="display: none;"> |
| 578 | + <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="35px" width="35px" version="1.1" id="Capa_1" viewBox="0 0 17.837 17.837" xml:space="preserve" style="background:#ffffff00;"> |
| 579 | + <g> |
| 580 | + <path style="fill:#00790a;" d="M16.145,2.571c-0.272-0.273-0.718-0.273-0.99,0L6.92,10.804l-4.241-4.27 c-0.272-0.274-0.715-0.274-0.989,0L0.204,8.019c-0.272,0.271-0.272,0.717,0,0.99l6.217,6.258c0.272,0.271,0.715,0.271,0.99,0 L17.63,5.047c0.276-0.273,0.276-0.72,0-0.994L16.145,2.571z"/> |
| 581 | + </g> |
| 582 | + </svg> |
| 583 | + </div> |
| 584 | + </div> |
| 585 | + <div id="conversionStatus" style="text-align: left; color: #333333; margin-top: 7px; margin-left: 15px; width: 175px"></div> |
| 586 | + </div> |
| 587 | + </div> |
| 588 | + <span id="conversionError" style="color: #ff0000"></span> |
558 | 589 | <br> |
559 | 590 | </div> |
560 | 591 |
|
|
0 commit comments