mirror of
https://github.com/storytold/spark.git
synced 2026-10-09 00:09:53 +00:00
Externalize render settings minAlpha and maxPixelRadius (#130)
* Add commented benchmarkSort to compare JS vs Wasm sorting. * Add 32-bit float sort via SparkViewpooint.sort32, using 2-pass radix-65536 sort. Turn on sort32 by default for examples/editor. Implemented Rust sort and JS sort, updated benchmarking code to include float16 and float32 sort. * Add sort32 to docs/spark-viewpoint.md. * Externalized SparkRenderer.maxPixelRadius and .minAlpha settings. Added to documentation. Added to examples/editor under Debug folder, moved sort32 there.
This commit is contained in:
committed by
GitHub
parent
23b9b190a0
commit
5eb57038b4
@@ -57,6 +57,8 @@ 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`)
|
||||
| **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)`)
|
||||
| **maxPixelRadius** | Maximum pixel radius for splat rendering. (default: `512.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`)
|
||||
| **preBlurAmount** | Scalar value to add to 2D splat covariance diagonal, effectively blurring + enlarging splats. In scenes trained without the splat anti-aliasing tweak this value was typically 0.3, but with anti-aliasing it is 0.0 (default: `0.0`)
|
||||
| **blurAmount** | Scalar value to add to 2D splat covariance diagonal, with opacity adjustment to correctly account for "blurring" when anti-aliasing. Typically 0.3 (equivalent to approx 0.5 pixel radius) in scenes trained with anti-aliasing.
|
||||
|
||||
@@ -515,6 +515,10 @@
|
||||
},
|
||||
}, "AA").name("AA preset");
|
||||
debugFolder.add(spark, "focalAdjustment", 0.1, 2.0, 0.1).name("Tweak focalAdjustment");
|
||||
spark.defaultView.sort32 = true;
|
||||
debugFolder.add(spark.defaultView, "sort32").name("Float32 sort").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();
|
||||
|
||||
const splatsFolder = secondGui.addFolder("Files");
|
||||
|
||||
|
||||
@@ -116,6 +116,16 @@ export type SparkRendererOptions = {
|
||||
* @default Math.sqrt(8)
|
||||
*/
|
||||
maxStdDev?: number;
|
||||
/**
|
||||
* Maximum pixel radius for splat rendering.
|
||||
* @default 512.0
|
||||
*/
|
||||
maxPixelRadius?: number;
|
||||
/**
|
||||
* Minimum alpha value for splat rendering.
|
||||
* @default 0.5 * (1.0 / 255.0)
|
||||
*/
|
||||
minAlpha?: number;
|
||||
/**
|
||||
* 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
|
||||
@@ -185,6 +195,8 @@ export class SparkRenderer extends THREE.Mesh {
|
||||
preUpdate: boolean;
|
||||
originDistance: number;
|
||||
maxStdDev: number;
|
||||
maxPixelRadius: number;
|
||||
minAlpha: number;
|
||||
enable2DGS: boolean;
|
||||
preBlurAmount: number;
|
||||
blurAmount: number;
|
||||
@@ -301,6 +313,8 @@ export class SparkRenderer extends THREE.Mesh {
|
||||
this.preUpdate = options.preUpdate ?? false;
|
||||
this.originDistance = options.originDistance ?? 1;
|
||||
this.maxStdDev = options.maxStdDev ?? Math.sqrt(8.0);
|
||||
this.maxPixelRadius = options.maxPixelRadius ?? 512.0;
|
||||
this.minAlpha = options.minAlpha ?? 0.5 * (1.0 / 255.0);
|
||||
this.enable2DGS = options.enable2DGS ?? false;
|
||||
this.preBlurAmount = options.preBlurAmount ?? 0.0;
|
||||
this.blurAmount = options.blurAmount ?? 0.3;
|
||||
@@ -350,6 +364,10 @@ export class SparkRenderer extends THREE.Mesh {
|
||||
renderToViewPos: { value: new THREE.Vector3() },
|
||||
// Maximum distance (in stddevs) from Gsplat center to render
|
||||
maxStdDev: { value: 1.0 },
|
||||
// Maximum pixel radius for splat rendering
|
||||
maxPixelRadius: { value: 512.0 },
|
||||
// Minimum alpha value for splat rendering
|
||||
minAlpha: { value: 0.5 * (1.0 / 255.0) },
|
||||
// Enable interpreting 0-thickness Gsplats as 2DGS
|
||||
enable2DGS: { value: false },
|
||||
// Add to projected 2D splat covariance diagonal (thickens and brightens)
|
||||
@@ -517,6 +535,8 @@ export class SparkRenderer extends THREE.Mesh {
|
||||
this.uniforms.far.value = typedCamera.far;
|
||||
this.uniforms.encodeLinear.value = viewpoint.encodeLinear;
|
||||
this.uniforms.maxStdDev.value = this.maxStdDev;
|
||||
this.uniforms.maxPixelRadius.value = this.maxPixelRadius;
|
||||
this.uniforms.minAlpha.value = this.minAlpha;
|
||||
this.uniforms.enable2DGS.value = this.enable2DGS;
|
||||
this.uniforms.preBlurAmount.value = this.preBlurAmount;
|
||||
this.uniforms.blurAmount.value = this.blurAmount;
|
||||
|
||||
@@ -21,10 +21,6 @@ const float PI = 3.1415926535897932384626433832795;
|
||||
const float INFINITY = 1.0 / 0.0;
|
||||
const float NEG_INFINITY = -INFINITY;
|
||||
|
||||
const float MAX_PIXEL_RADIUS = 512.0;
|
||||
const float MIN_ALPHA = 0.5 * (1.0 / 255.0); // 0.00196
|
||||
const float MAX_STDDEV = sqrt(8.0);
|
||||
|
||||
float sqr(float x) {
|
||||
return x * x;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ uniform float near;
|
||||
uniform float far;
|
||||
uniform bool encodeLinear;
|
||||
uniform float maxStdDev;
|
||||
uniform float minAlpha;
|
||||
uniform bool disableFalloff;
|
||||
uniform float falloff;
|
||||
|
||||
@@ -60,7 +61,7 @@ void main() {
|
||||
|
||||
rgba.a *= mix(1.0, exp(-0.5 * z), falloff);
|
||||
|
||||
if (rgba.a < MIN_ALPHA) {
|
||||
if (rgba.a < minAlpha) {
|
||||
discard;
|
||||
}
|
||||
if (encodeLinear) {
|
||||
|
||||
@@ -16,9 +16,11 @@ uniform uint numSplats;
|
||||
uniform vec4 renderToViewQuat;
|
||||
uniform vec3 renderToViewPos;
|
||||
uniform float maxStdDev;
|
||||
uniform float maxPixelRadius;
|
||||
uniform float time;
|
||||
uniform float deltaTime;
|
||||
uniform bool debugFlag;
|
||||
uniform float minAlpha;
|
||||
uniform bool enable2DGS;
|
||||
uniform float blurAmount;
|
||||
uniform float preBlurAmount;
|
||||
@@ -52,7 +54,7 @@ void main() {
|
||||
vec4 quaternion, rgba;
|
||||
unpackSplat(packed, center, scales, quaternion, rgba);
|
||||
|
||||
if (rgba.a < MIN_ALPHA) {
|
||||
if (rgba.a < minAlpha) {
|
||||
return;
|
||||
}
|
||||
bvec3 zeroScales = equal(scales, vec3(0.0));
|
||||
@@ -141,13 +143,13 @@ void main() {
|
||||
|
||||
float fullBlurAmount = blurAmount;
|
||||
if ((focalDistance > 0.0) && (apertureAngle > 0.0)) {
|
||||
float focusRadius = MAX_PIXEL_RADIUS;
|
||||
float focusRadius = maxPixelRadius;
|
||||
if (viewCenter.z < 0.0) {
|
||||
float focusBlur = abs((-viewCenter.z - focalDistance) / viewCenter.z);
|
||||
float apertureRadius = focal.x * tan(0.5 * apertureAngle);
|
||||
focusRadius = focusBlur * apertureRadius;
|
||||
}
|
||||
fullBlurAmount = clamp(sqr(focusRadius), blurAmount, sqr(MAX_PIXEL_RADIUS));
|
||||
fullBlurAmount = clamp(sqr(focusRadius), blurAmount, sqr(maxPixelRadius));
|
||||
}
|
||||
|
||||
// Do convolution with a 0.5-pixel Gaussian for anti-aliasing: sqrt(0.3) ~= 0.5
|
||||
@@ -159,7 +161,7 @@ void main() {
|
||||
// Compute anti-aliasing intensity scaling factor
|
||||
float blurAdjust = sqrt(max(0.0, detOrig / det));
|
||||
rgba.a *= blurAdjust;
|
||||
if (rgba.a < MIN_ALPHA) {
|
||||
if (rgba.a < minAlpha) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -172,8 +174,8 @@ void main() {
|
||||
vec2 eigenVec1 = normalize(vec2((abs(b) < 0.001) ? 1.0 : b, eigen1 - a));
|
||||
vec2 eigenVec2 = vec2(eigenVec1.y, -eigenVec1.x);
|
||||
|
||||
float scale1 = position.x * min(MAX_PIXEL_RADIUS, maxStdDev * sqrt(eigen1));
|
||||
float scale2 = position.y * min(MAX_PIXEL_RADIUS, maxStdDev * sqrt(eigen2));
|
||||
float scale1 = position.x * min(maxPixelRadius, maxStdDev * sqrt(eigen1));
|
||||
float scale2 = position.y * min(maxPixelRadius, maxStdDev * sqrt(eigen2));
|
||||
|
||||
// Compute the NDC coordinates for the ellipsoid's diagonal axes.
|
||||
vec2 pixelOffset = eigenVec1 * scale1 + eigenVec2 * scale2;
|
||||
|
||||
Reference in New Issue
Block a user