Skip to content

Commit 15318d7

Browse files
authored
Add minPixelRadius to skip splats below a given pixel radius (#184)
1 parent 6d7d801 commit 15318d7

4 files changed

Lines changed: 19 additions & 3 deletions

File tree

docs/docs/spark-renderer.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ const spark = new SparkRenderer({
5757
| **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`)
5858
| **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.
5959
| **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)`)
60+
| **minPixelRadius** | Minimum pixel radius for splat rendering. (default: `0.0`)
6061
| **maxPixelRadius** | Maximum pixel radius for splat rendering. (default: `512.0`)
6162
| **minAlpha** | Minimum alpha value for splat rendering. (default: `0.5 * (1.0 / 255.0)`)
6263
| **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`)

examples/editor/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@
540540
debugFolder.add(spark, "focalAdjustment", 0.1, 2.0, 0.1).name("Tweak focalAdjustment");
541541
spark.defaultView.sort32 = true;
542542
debugFolder.add(spark.defaultView, "sort32").name("Float32 sort").listen();
543+
debugFolder.add(spark, "minPixelRadius", 0, 16, 0.1).name("Min pixel radius").listen();
543544
debugFolder.add(spark, "maxPixelRadius", 1, 1024, 1).name("Max pixel radius").listen();
544545
debugFolder.add(spark, "minAlpha", 0, 1, 0.001).name("Min alpha").listen();
545546

src/SparkRenderer.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ export type SparkRendererOptions = {
8484
* @default Math.sqrt(8)
8585
*/
8686
maxStdDev?: number;
87+
/**
88+
* Minimum pixel radius for splat rendering.
89+
* @default 0.0
90+
*/
91+
minPixelRadius?: number;
8792
/**
8893
* Maximum pixel radius for splat rendering.
8994
* @default 512.0
@@ -170,6 +175,7 @@ export class SparkRenderer extends THREE.Mesh {
170175
needsUpdate: boolean;
171176
originDistance: number;
172177
maxStdDev: number;
178+
minPixelRadius: number;
173179
maxPixelRadius: number;
174180
minAlpha: number;
175181
enable2DGS: boolean;
@@ -294,6 +300,7 @@ export class SparkRenderer extends THREE.Mesh {
294300
this.needsUpdate = false;
295301
this.originDistance = options.originDistance ?? 1;
296302
this.maxStdDev = options.maxStdDev ?? Math.sqrt(8.0);
303+
this.minPixelRadius = options.minPixelRadius ?? 0.0;
297304
this.maxPixelRadius = options.maxPixelRadius ?? 512.0;
298305
this.minAlpha = options.minAlpha ?? 0.5 * (1.0 / 255.0);
299306
this.enable2DGS = options.enable2DGS ?? false;
@@ -344,6 +351,8 @@ export class SparkRenderer extends THREE.Mesh {
344351
renderToViewPos: { value: new THREE.Vector3() },
345352
// Maximum distance (in stddevs) from Gsplat center to render
346353
maxStdDev: { value: 1.0 },
354+
// Minimum pixel radius for splat rendering
355+
minPixelRadius: { value: 0.0 },
347356
// Maximum pixel radius for splat rendering
348357
maxPixelRadius: { value: 512.0 },
349358
// Minimum alpha value for splat rendering
@@ -528,6 +537,7 @@ export class SparkRenderer extends THREE.Mesh {
528537
this.uniforms.far.value = typedCamera.far;
529538
this.uniforms.encodeLinear.value = viewpoint.encodeLinear;
530539
this.uniforms.maxStdDev.value = this.maxStdDev;
540+
this.uniforms.minPixelRadius.value = this.minPixelRadius;
531541
this.uniforms.maxPixelRadius.value = this.maxPixelRadius;
532542
this.uniforms.minAlpha.value = this.minAlpha;
533543
this.uniforms.stochastic.value = viewpoint.stochastic;

src/shaders/splatVertex.glsl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ uniform uint numSplats;
1717
uniform vec4 renderToViewQuat;
1818
uniform vec3 renderToViewPos;
1919
uniform float maxStdDev;
20+
uniform float minPixelRadius;
2021
uniform float maxPixelRadius;
2122
uniform float time;
2223
uniform float deltaTime;
@@ -199,11 +200,14 @@ void main() {
199200
vec2 eigenVec1 = normalize(vec2((abs(b) < 0.001) ? 1.0 : b, eigen1 - a));
200201
vec2 eigenVec2 = vec2(eigenVec1.y, -eigenVec1.x);
201202

202-
float scale1 = position.x * min(maxPixelRadius, maxStdDev * sqrt(eigen1));
203-
float scale2 = position.y * min(maxPixelRadius, maxStdDev * sqrt(eigen2));
203+
float scale1 = min(maxPixelRadius, maxStdDev * sqrt(eigen1));
204+
float scale2 = min(maxPixelRadius, maxStdDev * sqrt(eigen2));
205+
if (scale1 < minPixelRadius && scale2 < minPixelRadius) {
206+
return;
207+
}
204208

205209
// Compute the NDC coordinates for the ellipsoid's diagonal axes.
206-
vec2 pixelOffset = eigenVec1 * scale1 + eigenVec2 * scale2;
210+
vec2 pixelOffset = position.x * eigenVec1 * scale1 + position.y * eigenVec2 * scale2;
207211
vec2 ndcOffset = (2.0 / scaledRenderSize) * pixelOffset;
208212
vec3 ndc = vec3(ndcCenter.xy + ndcOffset, ndcCenter.z);
209213

0 commit comments

Comments
 (0)