Skip to content

Commit

Permalink
Merge pull request #310 from mkkellogg/dev
Browse files Browse the repository at this point in the history
Release 0.4.4: General updates
  • Loading branch information
mkkellogg authored Aug 25, 2024
2 parents ef524f4 + b3ec449 commit 2d80511
Show file tree
Hide file tree
Showing 19 changed files with 638 additions and 322 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,13 @@ Both of the above methods will prompt your browser to automatically start downlo
The third option is to use the included nodejs script:

```
node util/create-ksplat.js [path to .PLY or .SPLAT] [output file] [compression level = 0] [alpha removal threshold = 1]
node util/create-ksplat.js [path to .PLY or .SPLAT] [output file] [compression level = 0] [alpha removal threshold = 1] [scene center = "0,0,0"] [block size = 5.0] [bucket size = 256] [spherical harmonics level = 0]
```

For the nodejs script, it may be necessary to increase the heap size for larger scenes. Use the parameter `--max-old-space-size=[heap size in MB]` to do so:

```
node util/create-ksplat.js --max-old-space-size=8192 [... remaining arguments]
```

Currently supported values for `compressionLevel` are `0`, `1`, or `2`. `0` means no compression and `1` means compression of scale, rotation, position, and spherical harmonics coefficient values from 32-bit to 16-bit. `2` is similar to `1` except spherical harmonics coefficients are compressed to 8-bit.
Expand Down
173 changes: 173 additions & 0 deletions demo/dynamic_dropin.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<title>3D Gaussian Splats - Drop-in example</title>
<script type="text/javascript" src="js/util.js"></script>
<script type="importmap">
{
"imports": {
"three": "./lib/three.module.js",
"@mkkellogg/gaussian-splats-3d": "./lib/gaussian-splats-3d.module.js"
}
}
</script>
<style>

body {
background-color: #000000;
height: 100vh;
margin: 0px;
}

</style>

</head>

<body>
<script type="module">
import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
import * as THREE from 'three';

function setupRenderer() {
const renderWidth = 800;
const renderHeight = 600;

const rootElement = document.createElement('div');
rootElement.style.width = renderWidth + 'px';
rootElement.style.height = renderHeight + 'px';
rootElement.style.position = 'relative';
rootElement.style.left = '50%';
rootElement.style.top = '50%';
rootElement.style.transform = 'translate(-50%, -50%)';
document.body.appendChild(rootElement);

const renderer = new THREE.WebGLRenderer({
antialias: false
});
renderer.setSize(renderWidth, renderHeight);
rootElement.appendChild(renderer.domElement);

return {
'renderer': renderer,
'renderWidth': renderWidth,
'renderHeight': renderHeight
}
}

function setupCamera(renderWidth, renderHeight) {
const camera = new THREE.PerspectiveCamera(65, renderWidth / renderHeight, 0.1, 500);
camera.position.copy(new THREE.Vector3().fromArray([-1, -4, 6]));
camera.lookAt(new THREE.Vector3().fromArray([0, 4, -0]));
camera.up = new THREE.Vector3().fromArray([0, -1, -0.6]).normalize();
return camera;
}

function setupThreeScene() {
const threeScene = new THREE.Scene();
const boxColor = 0xBBBBBB;
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial({'color': boxColor}));
threeScene.add(boxMesh);
boxMesh.position.set(3, 2, 2);
return threeScene;
}

function setupControls(camera, renderer) {
const controls = new GaussianSplats3D.OrbitControls(camera, renderer.domElement);
controls.rotateSpeed = 0.5;
controls.maxPolarAngle = Math.PI * .75;
controls.minPolarAngle = 0.1;
controls.enableDamping = true;
controls.dampingFactor = 0.05;
return controls;
}

const {renderer, renderWidth, renderHeight} = setupRenderer();
const camera = setupCamera(renderWidth, renderHeight);
const threeScene = setupThreeScene();
const controls = setupControls(camera, renderer);

const viewer = new GaussianSplats3D.DropInViewer({
'dynamicScene': true
});
viewer.addSplatScenes([
{
'path': 'assets/data/garden/garden.ksplat',
'splatAlphaRemovalThreshold': 20,
},
{
'path': 'assets/data/bonsai/bonsai_trimmed.ksplat',
'splatAlphaRemovalThreshold': 20,
},
{
'path': 'assets/data/bonsai/bonsai_trimmed.ksplat',
'splatAlphaRemovalThreshold': 20,
}
], true).then(() => {

threeScene.add(viewer);

const bonsaiCount = 2;
const bonsaiStartIndex = 1;
const rotationAxis = new THREE.Vector3(0, -1, -0.6).normalize();
const baseQuaternion = new THREE.Quaternion(-0.147244, -0.07617, 0.14106, 0.9760);
const rotationQuaternion = new THREE.Quaternion();
const quaternion = new THREE.Quaternion();
const orbitCenter = new THREE.Vector3(0.416161, 1.385, 1.145);
const horizontalOffsetVector = new THREE.Vector3();
const position = new THREE.Vector3();
const scale = new THREE.Vector3(1.25, 1.25, 1.25);

// generate splat mesh parent objects
const sphereGeometry = new THREE.SphereGeometry(0.25, 8, 8);
const material = new THREE.MeshBasicMaterial({color: 0xff0000});
const meshA = new THREE.Mesh(sphereGeometry, material);
const meshB = new THREE.Mesh(sphereGeometry, material);

// add splat mesh parent objects to the scene
threeScene.add(meshA);
threeScene.add(meshB);

// You can modify the transform components (position, quaternion, scale) of a SplatScene
// directly like any three.js object OR you can just attach them to another three.js object
// and they will be transformed accordingly. Below we are going with the latter approach.
// The splat scenes at index 1 & 2 are (by default) children of viewer.splatMesh, so we
// re-parent them to meshA and meshB respectively.
meshA.add(viewer.getSplatScene(1));
meshB.add(viewer.getSplatScene(2));

let startTime = performance.now() / 1000.0;
requestAnimationFrame(update);
function update() {
requestAnimationFrame(update);
const timeDelta = performance.now() / 1000.0 - startTime;
for (let i = bonsaiStartIndex; i < bonsaiStartIndex + bonsaiCount; i++) {

// calculate parent mesh positions & orientations
const angle = timeDelta * 0.25 + (Math.PI * 2) * (i /bonsaiCount);
const height = Math.cos(timeDelta + (Math.PI * 2) * (i / bonsaiCount)) * 0.5 + 3;
rotationQuaternion.setFromAxisAngle(rotationAxis, angle);
horizontalOffsetVector.set(3, 0, 0).applyQuaternion(rotationQuaternion);

// apply mesh position, orientation and scale
const mesh = (i % 2 === 0) ? meshA : meshB;
mesh.position.copy(rotationAxis).multiplyScalar(height).add(horizontalOffsetVector).add(orbitCenter);
mesh.quaternion.copy(baseQuaternion).premultiply(rotationQuaternion);
mesh.scale.copy(scale);

// perform standard three.js update and render
controls.update();
renderer.render(threeScene, camera);

}
}
});

</script>
</body>

</html>
35 changes: 26 additions & 9 deletions demo/dynamic_scenes.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
'initialCameraLookAt': [1.52976, 2.27776, 1.65898],
'dynamicScene': true
});
const lp = viewer.addSplatScenes([

viewer.addSplatScenes([
{
'path': 'assets/data/garden/garden.ksplat',
'splatAlphaRemovalThreshold': 20,
Expand All @@ -64,24 +65,40 @@
const position = new THREE.Vector3();
const scale = new THREE.Vector3(1.25, 1.25, 1.25);

// generate splat mesh parent objects
const sphereGeometry = new THREE.SphereGeometry(0.25, 8, 8);
const material = new THREE.MeshBasicMaterial({color: 0xff0000});
const meshA = new THREE.Mesh(sphereGeometry, material);
const meshB = new THREE.Mesh(sphereGeometry, material);

// add splat mesh parent objects to the scene
viewer.splatMesh.add(meshA);
viewer.splatMesh.add(meshB);

// You can modify the transform components (position, quaternion, scale) of a SplatScene
// directly like any three.js object OR you can just attach them to another three.js object
// and they will be transformed accordingly. Below we are going with the latter approach.
// The splat scenes at index 1 & 2 are (by default) children of viewer.splatMesh, so we
// re-parent them to meshA and meshB respectively.
meshA.add(viewer.getSplatScene(1));
meshB.add(viewer.getSplatScene(2));

let startTime = performance.now() / 1000.0;
requestAnimationFrame(update);
function update() {
requestAnimationFrame(update);
const timeDelta = performance.now() / 1000.0 - startTime;
for (let i = bonsaiStartIndex; i < bonsaiStartIndex + bonsaiCount; i++) {
// calculate parent mesh positions & orientations
const angle = timeDelta * 0.25 + (Math.PI * 2) * (i /bonsaiCount);
const height = Math.cos(timeDelta + (Math.PI * 2) * (i / bonsaiCount)) * 0.5 + 3;

rotationQuaternion.setFromAxisAngle(rotationAxis, angle);
horizontalOffsetVector.set(3, 0, 0).applyQuaternion(rotationQuaternion);
position.copy(rotationAxis).multiplyScalar(height).add(horizontalOffsetVector).add(orbitCenter);
quaternion.copy(baseQuaternion).premultiply(rotationQuaternion);

const splatScene = viewer.getSplatScene(i);
splatScene.position.copy(position);
splatScene.quaternion.copy(quaternion);
splatScene.scale.copy(scale);
// apply mesh position, orientation and scale
const mesh = (i % 2 === 0) ? meshA : meshB;
mesh.position.copy(rotationAxis).multiplyScalar(height).add(horizontalOffsetVector).add(orbitCenter);
mesh.quaternion.copy(baseQuaternion).premultiply(rotationQuaternion);
mesh.scale.copy(scale);
}
}

Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"type": "git",
"url": "https://github.com/mkkellogg/GaussianSplats3D"
},
"version": "0.4.3",
"version": "0.4.4",
"description": "Three.js-based 3D Gaussian splat viewer",
"module": "build/gaussian-splats-3d.module.js",
"main": "build/gaussian-splats-3d.umd.cjs",
Expand Down
4 changes: 2 additions & 2 deletions src/AbortablePromise.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ export class AbortablePromise {
}, this.abortHandler);
}

abort() {
if (this.abortHandler) this.abortHandler();
abort(reason) {
if (this.abortHandler) this.abortHandler(reason);
}

}
Expand Down
4 changes: 4 additions & 0 deletions src/DropInViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ export class DropInViewer extends THREE.Group {
return this.viewer.removeSplatScenes(indexes, showLoadingUI);
}

getSceneCount() {
return this.viewer.getSceneCount();
}

dispose() {
return this.viewer.dispose();
}
Expand Down
8 changes: 4 additions & 4 deletions src/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,12 @@ export const fetchWithProgress = function(path, onProgress, saveChunks = true) {
const abortController = new AbortController();
const signal = abortController.signal;
let aborted = false;
let rejectFunc = null;
const abortHandler = (reason) => {
abortController.abort(reason);
rejectFunc(new AbortedPromiseError('Fetch aborted.'));
abortController.abort(new AbortedPromiseError(reason));
aborted = true;
};

return new AbortablePromise((resolve, reject) => {
rejectFunc = reject;
fetch(path, { signal })
.then(async (data) => {
const reader = data.body.getReader();
Expand Down Expand Up @@ -109,6 +106,9 @@ export const fetchWithProgress = function(path, onProgress, saveChunks = true) {
break;
}
}
})
.catch((error) => {
reject(error);
});
}, abortHandler);

Expand Down
Loading

0 comments on commit 2d80511

Please sign in to comment.