From f8809f6998c4937ebcaa02005e23f7e879973470 Mon Sep 17 00:00:00 2001 From: Mark Kellogg Date: Tue, 19 Mar 2024 08:49:04 -0700 Subject: [PATCH 1/6] Alter splat tree worker to prevent vite build issues --- src/splattree/SplatTree.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/splattree/SplatTree.js b/src/splattree/SplatTree.js index 72bf703..a415133 100644 --- a/src/splattree/SplatTree.js +++ b/src/splattree/SplatTree.js @@ -81,6 +81,8 @@ class SplatSubTree { let splatTreeWorker; function createSplatTreeWorker(self) { + let WorkerSplatTreeNodeIDGen = 0; + class WorkerBox3 { constructor(min, max) { @@ -112,7 +114,7 @@ function createSplatTreeWorker(self) { } class WorkerSplatTreeNode { - static idGen = 0; + constructor(min, max, depth, id) { this.min = [min[0], min[1], min[2]]; this.max = [max[0], max[1], max[2]]; @@ -122,7 +124,7 @@ function createSplatTreeWorker(self) { this.depth = depth; this.children = []; this.data = null; - this.id = id || WorkerSplatTreeNode.idGen++; + this.id = id || WorkerSplatTreeNodeIDGen++; } } From ce45fd137f891ee336866b401fe7ec5e33f09306 Mon Sep 17 00:00:00 2001 From: Mark Kellogg Date: Tue, 19 Mar 2024 08:49:50 -0700 Subject: [PATCH 2/6] Fix scene not being fully revealed in non-streamed mode --- src/SplatMesh.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SplatMesh.js b/src/SplatMesh.js index 63770e4..7858fb5 100644 --- a/src/SplatMesh.js +++ b/src/SplatMesh.js @@ -591,7 +591,6 @@ export class SplatMesh extends THREE.Mesh { this.visibleRegionRadius = 0; this.visibleRegionFadeStartRadius = 0; this.firstRenderTime = -1; - this.finalBuild = false; this.lastBuildScenes = []; this.lastBuildSplatCount = 0; this.lastBuildMaxSplatCount = 0; From fe421b5193aa7c8e53a8d678902790642443ba55 Mon Sep 17 00:00:00 2001 From: Mark Kellogg Date: Tue, 19 Mar 2024 10:11:28 -0700 Subject: [PATCH 3/6] Allow choice of scene reveal mode --- src/SceneRevealMode.js | 5 +++++ src/SplatMesh.js | 20 +++++++++++++++----- src/Viewer.js | 11 ++++++++++- src/index.js | 4 +++- 4 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 src/SceneRevealMode.js diff --git a/src/SceneRevealMode.js b/src/SceneRevealMode.js new file mode 100644 index 0000000..f341b40 --- /dev/null +++ b/src/SceneRevealMode.js @@ -0,0 +1,5 @@ +export const SceneRevealMode = { + Default: 0, + Gradual: 1, + Instant: 2 +}; diff --git a/src/SplatMesh.js b/src/SplatMesh.js index 7858fb5..42eb262 100644 --- a/src/SplatMesh.js +++ b/src/SplatMesh.js @@ -5,6 +5,7 @@ import { WebGLExtensions } from './three-shim/WebGLExtensions.js'; import { WebGLCapabilities } from './three-shim/WebGLCapabilities.js'; import { uintEncodedFloat, rgbaArrayToInteger } from './Util.js'; import { Constants } from './Constants.js'; +import { SceneRevealMode } from './SceneRevealMode.js'; const dummyGeometry = new THREE.BufferGeometry(); const dummyMaterial = new THREE.MeshBasicMaterial(); @@ -12,6 +13,9 @@ const dummyMaterial = new THREE.MeshBasicMaterial(); const COVARIANCES_ELEMENTS_PER_SPLAT = 6; const CENTER_COLORS_ELEMENTS_PER_SPLAT = 4; +const SCENE_FADEIN_RATE_FAST = 0.012; +const SCENE_FADEIN_RATE_GRADUAL = 0.003; + /** * SplatMesh: Container for one or more splat scenes, abstracting them into a single unified container for * splat data. Additionally contains data structures and code to make the splat data renderable as a Three.js mesh. @@ -910,16 +914,22 @@ export class SplatMesh extends THREE.Mesh { this.updateVisibleRegionFadeDistance(); } - updateVisibleRegionFadeDistance() { - const fadeInRate = this.finalBuild ? 0.01 : 0.003; + updateVisibleRegionFadeDistance(sceneRevealMode = SceneRevealMode.Default) { + const fastFadeRate = SCENE_FADEIN_RATE_FAST; + const gradualFadeRate = SCENE_FADEIN_RATE_GRADUAL; + const defaultFadeInRate = this.finalBuild ? fastFadeRate : gradualFadeRate; + const fadeInRate = sceneRevealMode === SceneRevealMode.Default ? defaultFadeInRate : gradualFadeRate; this.visibleRegionFadeStartRadius = (this.visibleRegionRadius - this.visibleRegionFadeStartRadius) * - fadeInRate + this.visibleRegionFadeStartRadius; - const fadeInComplete = (this.visibleRegionFadeStartRadius / this.maxRadius) > 0.99 ? 1 : 0; + fadeInRate + this.visibleRegionFadeStartRadius; + const fadeInPercentage = (this.visibleRegionFadeStartRadius / this.maxRadius); + const fadeInComplete = fadeInPercentage > 0.99; + const shaderFadeInComplete = (fadeInComplete || sceneRevealMode === SceneRevealMode.Instant) ? 1 : 0; + this.material.uniforms.visibleRegionFadeStartRadius.value = this.visibleRegionFadeStartRadius; this.material.uniforms.visibleRegionRadius.value = this.visibleRegionRadius; this.material.uniforms.firstRenderTime.value = this.firstRenderTime; this.material.uniforms.currentTime.value = performance.now(); - this.material.uniforms.fadeInComplete.value = fadeInComplete; + this.material.uniforms.fadeInComplete.value = shaderFadeInComplete; this.material.uniformsNeedUpdate = true; this.visibleRegionChanging = !fadeInComplete; } diff --git a/src/Viewer.js b/src/Viewer.js index 2d40b4d..e784a94 100644 --- a/src/Viewer.js +++ b/src/Viewer.js @@ -21,6 +21,7 @@ import { ARButton } from './webxr/ARButton.js'; import { delayedExecute } from './Util.js'; import { LoaderStatus } from './loaders/LoaderStatus.js'; import { RenderMode } from './RenderMode.js'; +import { SceneRevealMode } from './SceneRevealMode.js'; const THREE_CAMERA_FOV = 50; const MINIMUM_DISTANCE_TO_NEW_FOCAL_POINT = .75; @@ -122,8 +123,16 @@ export class Viewer { this.gpuAcceleratedSort = false; } + // if 'renderMode' is RenderMode.Always, then the viewer will rrender the scene on every update. If it is RenderMode.OnChange, + // it will only render when something in the scene has changed. this.renderMode = options.renderMode || RenderMode.Always; + // SceneRevealMode.Default results in a nice, slow fade-in effect for progressively loaded scenes, + // and fast fade-in for fully loaded, non-streamed scenes. + // SceneRevealMode.Gradual will force the slow fade-in even for fully loaded, non streamed scenes. + // SceneRevealMode.Instant will force all loaded scene data to be immediately visible; + this.sceneRevealMode = options.sceneRevealMode || SceneRevealMode.Default; + this.controls = null; this.showMeshCursor = false; @@ -1170,7 +1179,7 @@ export class Viewer { if (this.dropInMode) this.updateForDropInMode(renderer, camera); if (!this.initialized || !this.splatRenderingInitialized) return; if (this.controls) this.controls.update(); - this.splatMesh.updateVisibleRegionFadeDistance(); + this.splatMesh.updateVisibleRegionFadeDistance(this.sceneRevealMode); this.updateSplatSort(); this.updateForRendererSizeChanges(); this.updateSplatMesh(); diff --git a/src/index.js b/src/index.js index 709b4d4..536e4d6 100644 --- a/src/index.js +++ b/src/index.js @@ -15,6 +15,7 @@ import { AbortablePromise } from './AbortablePromise.js'; import { SceneFormat } from './loaders/SceneFormat.js'; import { WebXRMode } from './webxr/WebXRMode.js'; import { RenderMode } from './RenderMode.js'; +import { SceneRevealMode } from './SceneRevealMode.js'; export { PlyParser, @@ -33,5 +34,6 @@ export { AbortablePromise, SceneFormat, WebXRMode, - RenderMode + RenderMode, + SceneRevealMode }; From 4a60ae50fc254351001f7846f97074311ee081e2 Mon Sep 17 00:00:00 2001 From: Mark Kellogg Date: Tue, 19 Mar 2024 10:21:14 -0700 Subject: [PATCH 4/6] Remove maximum render distance --- src/Viewer.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Viewer.js b/src/Viewer.js index e784a94..22bf866 100644 --- a/src/Viewer.js +++ b/src/Viewer.js @@ -1497,8 +1497,6 @@ export class Viewer { return tempMax.copy(node.max).sub(node.min).length(); }; - const MaximumDistanceToRender = 125; - return function(gatherAllNodes = false) { this.getRenderDimensions(renderDimensions); @@ -1542,8 +1540,7 @@ export class Viewer { const ns = nodeSize(node); const outOfFovY = cameraAngleYZDot < (cosFovYOver2 - .6); const outOfFovX = cameraAngleXZDot < (cosFovXOver2 - .6); - if (!gatherAllNodes && ((outOfFovX || outOfFovY || - distanceToNode > MaximumDistanceToRender) && distanceToNode > ns)) { + if (!gatherAllNodes && ((outOfFovX || outOfFovY) && distanceToNode > ns)) { continue; } splatRenderCount += node.data.indexes.length; From 29b762f99ee45dd740aa68cd9b91d22fdde797fb Mon Sep 17 00:00:00 2001 From: Mark Kellogg Date: Tue, 19 Mar 2024 10:33:20 -0700 Subject: [PATCH 5/6] Update README --- README.md | 37 +++++++++++++++++++++++++++++++------ src/Viewer.js | 6 +++--- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0cf314d..7ea376e 100644 --- a/README.md +++ b/README.md @@ -260,7 +260,8 @@ const viewer = new GaussianSplats3D.Viewer({ 'integerBasedSort': true, 'dynamicScene': false, 'webXRMode': GaussianSplats3D.WebXRMode.None, - 'renderMode': GaussianSplats3D.RenderMode.OnChange + 'renderMode': GaussianSplats3D.RenderMode.OnChange, + 'sceneRevealMode': GaussianSplats3D.SceneRevealMode.Instant }); viewer.addSplatScene('') .then(() => { @@ -291,6 +292,7 @@ Advanced `Viewer` parameters | `dynamicScene` | Tells the viewer to not make any optimizations that depend on the scene being static. Additionally all splat data retrieved from the viewer's splat mesh will not have their respective scene transform applied to them by default. | `webXRMode` | Tells the viewer whether or not to enable built-in Web VR or Web AR. Valid values are defined in the `WebXRMode` enum: `None`, `VR`, and `AR`. Defaults to `None`. | `renderMode` | Controls when the viewer renders the scene. Valid values are defined in the `RenderMode` enum: `Always`, `OnChange`, and `Never`. Defaults to `Always`. +| `sceneRevealMode` | Controls the fade-in effect used when the scene is loaded. Valid values are defined in the `SceneRevealMode` enum: `Default`, `Gradual`, and `Instant`. `Default` results in a nice, slow fade-in effect for progressively loaded scenes, and a fast fade-in for non progressively loaded scenes. `Gradual` will force a slow fade-in for all scenes. `Instant` will force all loaded scene data to be immediately visible.
### Creating KSPLAT files @@ -301,8 +303,7 @@ import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d'; const compressionLevel = 1; const splatAlphaRemovalThreshold = 5; // out of 255 -const plyLoader = new GaussianSplats3D.PlyLoader(); -plyLoader.loadFromURL('', compressionLevel, splatAlphaRemovalThreshold) +GaussianSplats3D.PlyLoader.loadFromURL('', compressionLevel, splatAlphaRemovalThreshold) .then((splatBuffer) => { GaussianSplats3D.KSplatLoader.downloadFile(splatBuffer, 'converted_file.ksplat'); }); @@ -333,15 +334,15 @@ response.setHeader("Cross-Origin-Opener-Policy", "same-origin"); response.setHeader("Cross-Origin-Embedder-Policy", "require-corp"); ``` -If you're using Apache, you can edit the `.htaccess` file to do that by adding the lines: +#### CORS with Apache + +For Apache, you can edit the `.htaccess` file to allow CORS by adding the lines: ``` Header add Cross-Origin-Opener-Policy "same-origin" Header add Cross-Origin-Embedder-Policy "require-corp" ``` -For other web servers, these headers most likely can be set in a similar fashion. - Additionally you may need to require a secure connection to your server by redirecting all access via `http://` to `https://`. In Apache this can be done by updating the `.htaccess` file with the following lines: ``` @@ -349,3 +350,27 @@ RewriteEngine On RewriteCond %{HTTPS} off RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R,L] ``` + +#### CORS with Vite + +For Vite, one popular option is to install the [vite-plugin-cross-origin-isolation](https://github.com/chaosprint/vite-plugin-cross-origin-isolation) plugin via `npm` and then add the following to your `vite.config.js` file. + +```javascript +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [ + { + name: "configure-response-headers", + configureServer: (server) => { + server.middlewares.use((_req, res, next) => { + res.setHeader("Cross-Origin-Embedder-Policy", "require-corp"); + res.setHeader("Cross-Origin-Opener-Policy", "same-origin"); + next(); + }); + }, + }, + ], +}); +``` +There are other ways to configure Vite to handle this referenced in issue [#41](https://github.com/mkkellogg/GaussianSplats3D/issues/41). diff --git a/src/Viewer.js b/src/Viewer.js index 22bf866..4ca9609 100644 --- a/src/Viewer.js +++ b/src/Viewer.js @@ -128,9 +128,9 @@ export class Viewer { this.renderMode = options.renderMode || RenderMode.Always; // SceneRevealMode.Default results in a nice, slow fade-in effect for progressively loaded scenes, - // and fast fade-in for fully loaded, non-streamed scenes. - // SceneRevealMode.Gradual will force the slow fade-in even for fully loaded, non streamed scenes. - // SceneRevealMode.Instant will force all loaded scene data to be immediately visible; + // and a fast fade-in for non progressively loaded scenes. + // SceneRevealMode.Gradual will force a slow fade-in for all scenes. + // SceneRevealMode.Instant will force all loaded scene data to be immediately visible. this.sceneRevealMode = options.sceneRevealMode || SceneRevealMode.Default; this.controls = null; From 865cdb0840a1218d4319dc93920a0ffbcd9e7221 Mon Sep 17 00:00:00 2001 From: Mark Kellogg Date: Wed, 20 Mar 2024 09:00:51 -0700 Subject: [PATCH 6/6] Upgrade version to 0.3.5 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2a93da..531f3c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@mkkellogg/gaussian-splats-3d", - "version": "0.3.4", + "version": "0.3.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@mkkellogg/gaussian-splats-3d", - "version": "0.3.4", + "version": "0.3.5", "license": "MIT", "devDependencies": { "@babel/core": "7.22.0", diff --git a/package.json b/package.json index 47d1e40..f65eca0 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "type": "git", "url": "https://github.com/mkkellogg/GaussianSplats3D" }, - "version": "0.3.4", + "version": "0.3.5", "description": "Three.js-based 3D Gaussian splat viewer", "module": "build/gaussian-splats-3d.module.js", "main": "build/gaussian-splats-3d.umd.cjs",