Add minPixelRadius to skip splats below a given pixel radius (#184)

This commit is contained in:
Noeri Huisman
2025-09-29 18:16:38 +02:00
committed by GitHub
parent 6d7d8012a1
commit 15318d7016
4 changed files with 19 additions and 3 deletions
+1
View File
@@ -57,6 +57,7 @@ const spark = new SparkRenderer({
| **preUpdate** | Controls whether to update the splats before or after rendering. For WebXR this *must* be false in order to complete rendering as soon as possible. (default: `false`) | **preUpdate** | Controls whether to update the splats before or after rendering. For WebXR this *must* be false in order to complete rendering as soon as possible. (default: `false`)
| **originDistance** | Distance threshold for `SparkRenderer` movement triggering a splat update at the new origin. (default: `1.0`) This can be useful when your `SparkRenderer` is a child of your camera and you want to retain high precision coordinates near the camera. | **originDistance** | Distance threshold for `SparkRenderer` movement triggering a splat update at the new origin. (default: `1.0`) This can be useful when your `SparkRenderer` is a child of your camera and you want to retain high precision coordinates near the camera.
| **maxStdDev** | Maximum standard deviations from the center to render Gaussians. Values `Math.sqrt(5)`..`Math.sqrt(9)` produce good results and can be tweaked for performance. (default: `Math.sqrt(8)`) | **maxStdDev** | Maximum standard deviations from the center to render Gaussians. Values `Math.sqrt(5)`..`Math.sqrt(9)` produce good results and can be tweaked for performance. (default: `Math.sqrt(8)`)
| **minPixelRadius** | Minimum pixel radius for splat rendering. (default: `0.0`)
| **maxPixelRadius** | Maximum pixel radius for splat rendering. (default: `512.0`) | **maxPixelRadius** | Maximum pixel radius for splat rendering. (default: `512.0`)
| **minAlpha** | Minimum alpha value for splat rendering. (default: `0.5 * (1.0 / 255.0)`) | **minAlpha** | Minimum alpha value for splat rendering. (default: `0.5 * (1.0 / 255.0)`)
| **enable2DGS** | Enable 2D Gaussian splatting rendering ability. When this mode is enabled, any `scale` x/y/z component that is exactly `0` (minimum quantized value) results in the other two non-zero axes being interpreted as an oriented 2D Gaussian Splat instead of the usual approximate projected 3DGS Z-slice. When reading PLY files, scale values less than e^-30 will be interpreted as `0`. (default: `false`) | **enable2DGS** | Enable 2D Gaussian splatting rendering ability. When this mode is enabled, any `scale` x/y/z component that is exactly `0` (minimum quantized value) results in the other two non-zero axes being interpreted as an oriented 2D Gaussian Splat instead of the usual approximate projected 3DGS Z-slice. When reading PLY files, scale values less than e^-30 will be interpreted as `0`. (default: `false`)
+1
View File
@@ -540,6 +540,7 @@
debugFolder.add(spark, "focalAdjustment", 0.1, 2.0, 0.1).name("Tweak focalAdjustment"); debugFolder.add(spark, "focalAdjustment", 0.1, 2.0, 0.1).name("Tweak focalAdjustment");
spark.defaultView.sort32 = true; spark.defaultView.sort32 = true;
debugFolder.add(spark.defaultView, "sort32").name("Float32 sort").listen(); debugFolder.add(spark.defaultView, "sort32").name("Float32 sort").listen();
debugFolder.add(spark, "minPixelRadius", 0, 16, 0.1).name("Min pixel radius").listen();
debugFolder.add(spark, "maxPixelRadius", 1, 1024, 1).name("Max pixel radius").listen(); debugFolder.add(spark, "maxPixelRadius", 1, 1024, 1).name("Max pixel radius").listen();
debugFolder.add(spark, "minAlpha", 0, 1, 0.001).name("Min alpha").listen(); debugFolder.add(spark, "minAlpha", 0, 1, 0.001).name("Min alpha").listen();
+10
View File
@@ -84,6 +84,11 @@ export type SparkRendererOptions = {
* @default Math.sqrt(8) * @default Math.sqrt(8)
*/ */
maxStdDev?: number; maxStdDev?: number;
/**
* Minimum pixel radius for splat rendering.
* @default 0.0
*/
minPixelRadius?: number;
/** /**
* Maximum pixel radius for splat rendering. * Maximum pixel radius for splat rendering.
* @default 512.0 * @default 512.0
@@ -170,6 +175,7 @@ export class SparkRenderer extends THREE.Mesh {
needsUpdate: boolean; needsUpdate: boolean;
originDistance: number; originDistance: number;
maxStdDev: number; maxStdDev: number;
minPixelRadius: number;
maxPixelRadius: number; maxPixelRadius: number;
minAlpha: number; minAlpha: number;
enable2DGS: boolean; enable2DGS: boolean;
@@ -294,6 +300,7 @@ export class SparkRenderer extends THREE.Mesh {
this.needsUpdate = false; this.needsUpdate = false;
this.originDistance = options.originDistance ?? 1; this.originDistance = options.originDistance ?? 1;
this.maxStdDev = options.maxStdDev ?? Math.sqrt(8.0); this.maxStdDev = options.maxStdDev ?? Math.sqrt(8.0);
this.minPixelRadius = options.minPixelRadius ?? 0.0;
this.maxPixelRadius = options.maxPixelRadius ?? 512.0; this.maxPixelRadius = options.maxPixelRadius ?? 512.0;
this.minAlpha = options.minAlpha ?? 0.5 * (1.0 / 255.0); this.minAlpha = options.minAlpha ?? 0.5 * (1.0 / 255.0);
this.enable2DGS = options.enable2DGS ?? false; this.enable2DGS = options.enable2DGS ?? false;
@@ -344,6 +351,8 @@ export class SparkRenderer extends THREE.Mesh {
renderToViewPos: { value: new THREE.Vector3() }, renderToViewPos: { value: new THREE.Vector3() },
// Maximum distance (in stddevs) from Gsplat center to render // Maximum distance (in stddevs) from Gsplat center to render
maxStdDev: { value: 1.0 }, maxStdDev: { value: 1.0 },
// Minimum pixel radius for splat rendering
minPixelRadius: { value: 0.0 },
// Maximum pixel radius for splat rendering // Maximum pixel radius for splat rendering
maxPixelRadius: { value: 512.0 }, maxPixelRadius: { value: 512.0 },
// Minimum alpha value for splat rendering // Minimum alpha value for splat rendering
@@ -528,6 +537,7 @@ export class SparkRenderer extends THREE.Mesh {
this.uniforms.far.value = typedCamera.far; this.uniforms.far.value = typedCamera.far;
this.uniforms.encodeLinear.value = viewpoint.encodeLinear; this.uniforms.encodeLinear.value = viewpoint.encodeLinear;
this.uniforms.maxStdDev.value = this.maxStdDev; this.uniforms.maxStdDev.value = this.maxStdDev;
this.uniforms.minPixelRadius.value = this.minPixelRadius;
this.uniforms.maxPixelRadius.value = this.maxPixelRadius; this.uniforms.maxPixelRadius.value = this.maxPixelRadius;
this.uniforms.minAlpha.value = this.minAlpha; this.uniforms.minAlpha.value = this.minAlpha;
this.uniforms.stochastic.value = viewpoint.stochastic; this.uniforms.stochastic.value = viewpoint.stochastic;
+7 -3
View File
@@ -17,6 +17,7 @@ uniform uint numSplats;
uniform vec4 renderToViewQuat; uniform vec4 renderToViewQuat;
uniform vec3 renderToViewPos; uniform vec3 renderToViewPos;
uniform float maxStdDev; uniform float maxStdDev;
uniform float minPixelRadius;
uniform float maxPixelRadius; uniform float maxPixelRadius;
uniform float time; uniform float time;
uniform float deltaTime; uniform float deltaTime;
@@ -199,11 +200,14 @@ void main() {
vec2 eigenVec1 = normalize(vec2((abs(b) < 0.001) ? 1.0 : b, eigen1 - a)); vec2 eigenVec1 = normalize(vec2((abs(b) < 0.001) ? 1.0 : b, eigen1 - a));
vec2 eigenVec2 = vec2(eigenVec1.y, -eigenVec1.x); vec2 eigenVec2 = vec2(eigenVec1.y, -eigenVec1.x);
float scale1 = position.x * min(maxPixelRadius, maxStdDev * sqrt(eigen1)); float scale1 = min(maxPixelRadius, maxStdDev * sqrt(eigen1));
float scale2 = position.y * min(maxPixelRadius, maxStdDev * sqrt(eigen2)); float scale2 = min(maxPixelRadius, maxStdDev * sqrt(eigen2));
if (scale1 < minPixelRadius && scale2 < minPixelRadius) {
return;
}
// Compute the NDC coordinates for the ellipsoid's diagonal axes. // Compute the NDC coordinates for the ellipsoid's diagonal axes.
vec2 pixelOffset = eigenVec1 * scale1 + eigenVec2 * scale2; vec2 pixelOffset = position.x * eigenVec1 * scale1 + position.y * eigenVec2 * scale2;
vec2 ndcOffset = (2.0 / scaledRenderSize) * pixelOffset; vec2 ndcOffset = (2.0 / scaledRenderSize) * pixelOffset;
vec3 ndc = vec3(ndcCenter.xy + ndcOffset, ndcCenter.z); vec3 ndc = vec3(ndcCenter.xy + ndcOffset, ndcCenter.z);