Skip to content

Commit

Permalink
Merge pull request #384 from mkkellogg/dev
Browse files Browse the repository at this point in the history
Release v0.4.6 - Minor updates
  • Loading branch information
mkkellogg authored Dec 4, 2024
2 parents f6f4ade + 000adcc commit 408943e
Show file tree
Hide file tree
Showing 12 changed files with 66 additions and 45 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ Advanced `Viewer` parameters
| `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.
| `antialiased` | When true, will perform additional steps during rendering to address artifacts caused by the rendering of gaussians at substantially different resolutions than that at which they were rendered during training. This will only work correctly for models that were trained using a process that utilizes this compensation calculation. For more details: https://github.com/nerfstudio-project/gsplat/pull/117, https://github.com/graphdeco-inria/gaussian-splatting/issues/294#issuecomment-1772688093
| `kernel2DSize` | A constant added to the size of the 2D screen-space gaussian kernel used in rendering splats. Default value is 0.3.
| `focalAdjustment` | Hacky, non-scientific parameter for tweaking focal length related calculations. For scenes with very small gaussians & small details, increasing this value can help improve visual quality. Default value is 1.0.
| `logLevel` | Verbosity of the console logging. Defaults to `GaussianSplats3D.LogLevel.None`.
| `sphericalHarmonicsDegree` | Degree of spherical harmonics to utilize in rendering splats (assuming the data is present in the splat scene). Valid values are 0, 1, or 2. Default value is 0.
Expand Down Expand Up @@ -361,7 +362,8 @@ GaussianSplats3D.PlyLoader.loadFromURL('<path to .ply or .splat file>',
minimumAlpha,
compressionLevel,
optimizeSplatData,
sphericalHarmonicsDegree)
sphericalHarmonicsDegree,
headers)
.then((splatBuffer) => {
GaussianSplats3D.KSplatLoader.downloadFile(splatBuffer, 'converted_file.ksplat');
});
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.5",
"version": "0.4.6",
"description": "Three.js-based 3D Gaussian splat viewer",
"module": "build/gaussian-splats-3d.module.js",
"main": "build/gaussian-splats-3d.umd.cjs",
Expand Down
1 change: 0 additions & 1 deletion src/DropInViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export class DropInViewer extends THREE.Group {
options.selfDrivenMode = false;
options.useBuiltInControls = false;
options.rootElement = null;
options.ignoreDevicePixelRatio = false;
options.dropInMode = true;
options.camera = undefined;
options.renderer = undefined;
Expand Down
6 changes: 4 additions & 2 deletions src/Util.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const rgbaArrayToInteger = function(arr, offset) {
return arr[offset] + (arr[offset + 1] << 8) + (arr[offset + 2] << 16) + (arr[offset + 3] << 24);
};

export const fetchWithProgress = function(path, onProgress, saveChunks = true) {
export const fetchWithProgress = function(path, onProgress, saveChunks = true, headers) {

const abortController = new AbortController();
const signal = abortController.signal;
Expand All @@ -65,7 +65,9 @@ export const fetchWithProgress = function(path, onProgress, saveChunks = true) {
};

return new AbortablePromise((resolve, reject) => {
fetch(path, { signal })
const fetchOptions = { signal };
if (headers) fetchOptions.headers = headers;
fetch(path, fetchOptions)
.then(async (data) => {
// Handle error conditions where data is still returned
if (!data.ok) {
Expand Down
52 changes: 32 additions & 20 deletions src/Viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class Viewer {
// Tells the viewer to pretend the device pixel ratio is 1, which can boost performance on devices where it is larger,
// at a small cost to visual quality
this.ignoreDevicePixelRatio = options.ignoreDevicePixelRatio || false;
this.devicePixelRatio = this.ignoreDevicePixelRatio ? 1 : window.devicePixelRatio;
this.devicePixelRatio = this.ignoreDevicePixelRatio ? 1 : (window.devicePixelRatio || 1);

// Tells the viewer to use 16-bit floating point values when storing splat covariance data in textures, instead of 32-bit
this.halfPrecisionCovariancesOnGPU = options.halfPrecisionCovariancesOnGPU || false;
Expand Down Expand Up @@ -117,6 +117,9 @@ export class Viewer {
// https://github.com/graphdeco-inria/gaussian-splatting/issues/294#issuecomment-1772688093
this.antialiased = options.antialiased || false;

// This constant is added to the projected 2D screen-space splat scales
this.kernel2DSize = (options.kernel2DSize === undefined) ? 0.3 : options.kernel2DSize;

this.webXRMode = options.webXRMode || WebXRMode.None;
if (this.webXRMode !== WebXRMode.None) {
this.gpuAcceleratedSort = false;
Expand Down Expand Up @@ -286,7 +289,7 @@ export class Viewer {
this.splatMesh = new SplatMesh(this.splatRenderMode, this.dynamicScene, this.enableOptionalEffects,
this.halfPrecisionCovariancesOnGPU, this.devicePixelRatio, this.gpuAcceleratedSort,
this.integerBasedSort, this.antialiased, this.maxScreenSpaceSplatSize, this.logLevel,
this.sphericalHarmonicsDegree, this.sceneFadeInRateMultiplier);
this.sphericalHarmonicsDegree, this.sceneFadeInRateMultiplier, this.kernel2DSize);
this.splatMesh.frustumCulled = false;
if (this.onSplatMeshChangedCallback) this.onSplatMeshChangedCallback();
}
Expand All @@ -303,7 +306,7 @@ export class Viewer {
this.rootElement.style.position = 'absolute';
document.body.appendChild(this.rootElement);
} else {
this.rootElement = this.renderer.domElement.parentElement || document.body;
this.rootElement = this.renderer.domElement || document.body;
}
}

Expand Down Expand Up @@ -725,6 +728,7 @@ export class Viewer {
*
* onProgress: Function to be called as file data are received, or other processing occurs
*
* headers: Optional HTTP headers to be sent along with splat requests
* }
* @return {AbortablePromise}
*/
Expand Down Expand Up @@ -819,7 +823,8 @@ export class Viewer {

const loadFunc = progressiveLoad ? this.downloadAndBuildSingleSplatSceneProgressiveLoad.bind(this) :
this.downloadAndBuildSingleSplatSceneStandardLoad.bind(this);
return loadFunc(path, format, options.splatAlphaRemovalThreshold, buildSection.bind(this), onProgress, hideLoadingUI.bind(this));
return loadFunc(path, format, options.splatAlphaRemovalThreshold, buildSection.bind(this),
onProgress, hideLoadingUI.bind(this), options.headers);
}

/**
Expand All @@ -832,12 +837,13 @@ export class Viewer {
* @param {function} buildFunc Function to build the viewer's splat mesh with the downloaded splat buffer
* @param {function} onProgress Function to be called as file data are received, or other processing occurs
* @param {function} onException Function to be called when exception occurs
* @param {object} headers Optional HTTP headers to pass to use for downloading splat scene
* @return {AbortablePromise}
*/
downloadAndBuildSingleSplatSceneStandardLoad(path, format, splatAlphaRemovalThreshold, buildFunc, onProgress, onException) {
downloadAndBuildSingleSplatSceneStandardLoad(path, format, splatAlphaRemovalThreshold, buildFunc, onProgress, onException, headers) {

const downloadPromise = this.downloadSplatSceneToSplatBuffer(path, splatAlphaRemovalThreshold,
onProgress, false, undefined, format);
const downloadPromise = this.downloadSplatSceneToSplatBuffer(path, splatAlphaRemovalThreshold, onProgress, false,
undefined, format, headers);
const downloadAndBuildPromise = abortablePromiseWithExtractedComponents(downloadPromise.abortHandler);

downloadPromise.then((splatBuffer) => {
Expand Down Expand Up @@ -871,10 +877,11 @@ export class Viewer {
* @param {function} buildFunc Function to rebuild the viewer's splat mesh after a new splat buffer section is downloaded
* @param {function} onDownloadProgress Function to be called as file data are received
* @param {function} onDownloadException Function to be called when exception occurs at any point during the full download
* @param {object} headers Optional HTTP headers to pass to use for downloading splat scene
* @return {AbortablePromise}
*/
downloadAndBuildSingleSplatSceneProgressiveLoad(path, format, splatAlphaRemovalThreshold, buildFunc,
onDownloadProgress, onDownloadException) {
onDownloadProgress, onDownloadException, headers) {
let progressiveLoadedSectionBuildCount = 0;
let progressiveLoadedSectionBuilding = false;
const queuedProgressiveLoadSectionBuilds = [];
Expand Down Expand Up @@ -917,7 +924,7 @@ export class Viewer {
};

const splatSceneDownloadPromise = this.downloadSplatSceneToSplatBuffer(path, splatAlphaRemovalThreshold, onDownloadProgress, true,
onProgressiveLoadSectionProgress, format);
onProgressiveLoadSectionProgress, format, headers);

const progressiveLoadFirstSectionBuildPromise = abortablePromiseWithExtractedComponents(splatSceneDownloadPromise.abortHandler);
const splatSceneDownloadAndBuildPromise = abortablePromiseWithExtractedComponents();
Expand Down Expand Up @@ -953,6 +960,11 @@ export class Viewer {
* rotation (Array<number>): Rotation of the scene represented as a quaternion, defaults to [0, 0, 0, 1]
*
* scale (Array<number>): Scene's scale, defaults to [1, 1, 1]
*
* headers: Optional HTTP headers to be sent along with splat requests
*
* format (SceneFormat) Optional, the format of the scene data (.ply, .ksplat, .splat). If not present, the
* file extension in 'path' will be used to determine the format (if it is present)
* }
* @param {boolean} showLoadingUI Display a loading spinner while the scene is loading, defaults to true
* @param {function} onProgress Function to be called as file data are received
Expand Down Expand Up @@ -998,7 +1010,8 @@ export class Viewer {
const options = sceneOptions[i];
const format = (options.format !== undefined && options.format !== null) ? options.format : sceneFormatFromPath(options.path);
const baseDownloadPromise = this.downloadSplatSceneToSplatBuffer(options.path, options.splatAlphaRemovalThreshold,
onLoadProgress.bind(this, i), false, undefined, format);
onLoadProgress.bind(this, i), false, undefined,
format, options.headers);
baseDownloadPromises.push(baseDownloadPromise);
nativeDownloadPromises.push(baseDownloadPromise.promise);
}
Expand Down Expand Up @@ -1044,23 +1057,22 @@ export class Viewer {
* @param {boolean} progressiveBuild Construct file sections into splat buffers as they are downloaded
* @param {function} onSectionBuilt Function to be called when new section is added to the file
* @param {string} format File format of the scene
* @param {object} headers Optional HTTP headers to pass to use for downloading splat scene
* @return {AbortablePromise}
*/
downloadSplatSceneToSplatBuffer(path, splatAlphaRemovalThreshold = 1, onProgress = undefined,
progressiveBuild = false, onSectionBuilt = undefined, format) {
progressiveBuild = false, onSectionBuilt = undefined, format, headers) {

const optimizeSplatData = progressiveBuild ? false : this.optimizeSplatData;
try {
if (format === SceneFormat.Splat) {
return SplatLoader.loadFromURL(path, onProgress, progressiveBuild,
onSectionBuilt, splatAlphaRemovalThreshold,
this.inMemoryCompressionLevel, optimizeSplatData);
return SplatLoader.loadFromURL(path, onProgress, progressiveBuild, onSectionBuilt, splatAlphaRemovalThreshold,
this.inMemoryCompressionLevel, optimizeSplatData, headers);
} else if (format === SceneFormat.KSplat) {
return KSplatLoader.loadFromURL(path, onProgress, progressiveBuild, onSectionBuilt);
return KSplatLoader.loadFromURL(path, onProgress, progressiveBuild, onSectionBuilt, headers);
} else if (format === SceneFormat.Ply) {
return PlyLoader.loadFromURL(path, onProgress, progressiveBuild, onSectionBuilt,
splatAlphaRemovalThreshold, this.inMemoryCompressionLevel,
optimizeSplatData, this.sphericalHarmonicsDegree);
return PlyLoader.loadFromURL(path, onProgress, progressiveBuild, onSectionBuilt, splatAlphaRemovalThreshold,
this.inMemoryCompressionLevel, optimizeSplatData, this.sphericalHarmonicsDegree, headers);
}
} catch (e) {
if (e instanceof DirectLoadError) {
Expand Down Expand Up @@ -1870,7 +1882,7 @@ export class Viewer {
mvpMatrix.copy(this.camera.matrixWorld).invert();
const mvpCamera = this.perspectiveCamera || this.camera;
mvpMatrix.premultiply(mvpCamera.projectionMatrix);
mvpMatrix.multiply(this.splatMesh.matrixWorld);
if (!this.splatMesh.dynamicMode) mvpMatrix.multiply(this.splatMesh.matrixWorld);

let gpuAcceleratedSortPromise = Promise.resolve(true);
if (this.gpuAcceleratedSort && (queuedSorts.length <= 1 || queuedSorts.length % 2 === 0)) {
Expand Down Expand Up @@ -1979,7 +1991,7 @@ export class Viewer {

if (splatTree) {
baseModelView.copy(this.camera.matrixWorld).invert();
baseModelView.multiply(this.splatMesh.matrixWorld);
if (!this.splatMesh.dynamicMode) baseModelView.multiply(this.splatMesh.matrixWorld);

let nodeRenderCount = 0;
let splatRenderCount = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/loaders/ksplat/KSplatLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class KSplatLoader {
}
};

static loadFromURL(fileName, externalOnProgress, loadDirectoToSplatBuffer, onSectionBuilt) {
static loadFromURL(fileName, externalOnProgress, loadDirectoToSplatBuffer, onSectionBuilt, headers) {
let directLoadBuffer;
let directLoadSplatBuffer;

Expand Down Expand Up @@ -196,7 +196,7 @@ export class KSplatLoader {
}
};

return fetchWithProgress(fileName, localOnProgress, !loadDirectoToSplatBuffer).then((fullBuffer) => {
return fetchWithProgress(fileName, localOnProgress, !loadDirectoToSplatBuffer, headers).then((fullBuffer) => {
if (externalOnProgress) externalOnProgress(0, '0%', LoaderStatus.Processing);
const loadPromise = loadDirectoToSplatBuffer ? directLoadPromise.promise : KSplatLoader.loadFromFileData(fullBuffer);
return loadPromise.then((splatBuffer) => {
Expand Down
7 changes: 4 additions & 3 deletions src/loaders/ply/PlyLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ function finalize(splatData, optimizeSplatData, minimumAlpha, compressionLevel,

export class PlyLoader {

static loadFromURL(fileName, onProgress, loadDirectoToSplatBuffer, onProgressiveLoadSectionProgress, minimumAlpha, compressionLevel,
optimizeSplatData = true, outSphericalHarmonicsDegree = 0, sectionSize, sceneCenter, blockSize, bucketSize) {
static loadFromURL(fileName, onProgress, loadDirectoToSplatBuffer, onProgressiveLoadSectionProgress,
minimumAlpha, compressionLevel, optimizeSplatData = true, outSphericalHarmonicsDegree = 0,
headers, sectionSize, sceneCenter, blockSize, bucketSize) {

let internalLoadType = loadDirectoToSplatBuffer ? InternalLoadType.DirectToSplatBuffer : InternalLoadType.DirectToSplatArray;
if (optimizeSplatData) internalLoadType = InternalLoadType.DirectToSplatArray;
Expand Down Expand Up @@ -256,7 +257,7 @@ export class PlyLoader {
};

if (onProgress) onProgress(0, '0%', LoaderStatus.Downloading);
return fetchWithProgress(fileName, localOnProgress, false).then(() => {
return fetchWithProgress(fileName, localOnProgress, false, headers).then(() => {
if (onProgress) onProgress(0, '0%', LoaderStatus.Processing);
return loadPromise.promise.then((splatData) => {
if (onProgress) onProgress(100, '100%', LoaderStatus.Done);
Expand Down
4 changes: 2 additions & 2 deletions src/loaders/splat/SplatLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function finalize(splatData, optimizeSplatData, minimumAlpha, compressionLevel,
export class SplatLoader {

static loadFromURL(fileName, onProgress, loadDirectoToSplatBuffer, onProgressiveLoadSectionProgress, minimumAlpha, compressionLevel,
optimizeSplatData = true, sectionSize, sceneCenter, blockSize, bucketSize) {
optimizeSplatData = true, headers, sectionSize, sceneCenter, blockSize, bucketSize) {

let internalLoadType = loadDirectoToSplatBuffer ? InternalLoadType.DirectToSplatBuffer : InternalLoadType.DirectToSplatArray;
if (optimizeSplatData) internalLoadType = InternalLoadType.DirectToSplatArray;
Expand Down Expand Up @@ -149,7 +149,7 @@ export class SplatLoader {
};

if (onProgress) onProgress(0, '0%', LoaderStatus.Downloading);
return fetchWithProgress(fileName, localOnProgress, false).then(() => {
return fetchWithProgress(fileName, localOnProgress, false, headers).then(() => {
if (onProgress) onProgress(0, '0%', LoaderStatus.Processing);
return loadPromise.promise.then((splatData) => {
if (onProgress) onProgress(100, '100%', LoaderStatus.Done);
Expand Down
2 changes: 1 addition & 1 deletion src/splatmesh/SplatMaterial.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export class SplatMaterial {
if (dynamicMode) {
vertexShaderSource += `
mat4 transform = transforms[sceneIndex];
mat4 transformModelViewMatrix = modelViewMatrix * transform;
mat4 transformModelViewMatrix = viewMatrix * transform;
`;
} else {
vertexShaderSource += `mat4 transformModelViewMatrix = modelViewMatrix;`;
Expand Down
Loading

0 comments on commit 408943e

Please sign in to comment.