mkkellogg / GaussianSplats3D

Three.js-based implementation of 3D Gaussian splatting
MIT License
1.54k stars 199 forks source link

Manual render option #286

Closed nickpaustian-slv closed 4 months ago

nickpaustian-slv commented 4 months ago

I'm working on a project where I am using a splat as the background of a web experience with other scene 3D geometry, I needed to be able to implement custom render process with different passes applied to the splat and the other scene elements independently.

I've added an option (manualRender) passed into the constructor that just disables the default render step.

If there isn't another way to already achieve this I thought it might be useful to our users.

Cheers! Nick

mkkellogg commented 4 months ago

You should be able to just use the existing selfDrivenMode constructor parameter for Viewer. Setting it to false tells the viewer you're going to call the update() and render() functions yourself. Here's an example of manual updating and rendering:

import * as GaussianSplats3D from '@mkkellogg/gaussian-splats-3d';
import * as THREE from 'three';

const renderWidth = 800;
const renderHeight = 600;

const rootElement = document.createElement('div');
rootElement.style.width = renderWidth + 'px';
rootElement.style.height = renderHeight + 'px';
document.body.appendChild(rootElement);

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

const camera = new THREE.PerspectiveCamera(65, renderWidth / renderHeight, 0.1, 500);

const viewer = new GaussianSplats3D.Viewer({
    'selfDrivenMode': false,
    'renderer': renderer,
    'camera': camera,
    'useBuiltInControls': false
});
viewer.addSplatScene('<path to .ply, .ksplat, or .splat file>')
.then(() => {
    requestAnimationFrame(update);
});

function update() {
    requestAnimationFrame(update);
    viewer.update();
    viewer.render();
}

You can even just directly render the viewer's splat mesh:

function update() {
    requestAnimationFrame(update);
    viewer.update();
    renderer.render(viewer.splatMesh);
}

There's also the DropInViewer, which acts like a standard three.js object:

const threeScene = new THREE.Scene();
const viewer = new GaussianSplats3D.DropInViewer({});
viewer.addSplatScene('<path to .ply, .ksplat, or .splat file>');
threeScene.add(viewer);

requestAnimationFrame(update);
function update() {
    requestAnimationFrame(update);
    renderer.render(threeScene, camera);
}
nickpaustian-slv commented 4 months ago

Ah of course, I did look at the self-driven mode earlier before I needed to perform custom rendering. Must have been very tunnel visioned on getting the render passes working when it came time. Cheers Mark I'll check out both of those options.