mirror of
https://github.com/storytold/spark.git
synced 2026-10-23 08:26:01 +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`)
|
| **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)`)
|
||||||
|
| **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`)
|
| **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`)
|
| **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.
|
| **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");
|
}, "AA").name("AA preset");
|
||||||
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;
|
||||||
|
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");
|
const splatsFolder = secondGui.addFolder("Files");
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,16 @@ export type SparkRendererOptions = {
|
|||||||
* @default Math.sqrt(8)
|
* @default Math.sqrt(8)
|
||||||
*/
|
*/
|
||||||
maxStdDev?: number;
|
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,
|
* 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
|
* 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;
|
preUpdate: boolean;
|
||||||
originDistance: number;
|
originDistance: number;
|
||||||
maxStdDev: number;
|
maxStdDev: number;
|
||||||
|
maxPixelRadius: number;
|
||||||
|
minAlpha: number;
|
||||||
enable2DGS: boolean;
|
enable2DGS: boolean;
|
||||||
preBlurAmount: number;
|
preBlurAmount: number;
|
||||||
blurAmount: number;
|
blurAmount: number;
|
||||||
@@ -301,6 +313,8 @@ export class SparkRenderer extends THREE.Mesh {
|
|||||||
this.preUpdate = options.preUpdate ?? false;
|
this.preUpdate = options.preUpdate ?? 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.maxPixelRadius = options.maxPixelRadius ?? 512.0;
|
||||||
|
this.minAlpha = options.minAlpha ?? 0.5 * (1.0 / 255.0);
|
||||||
this.enable2DGS = options.enable2DGS ?? false;
|
this.enable2DGS = options.enable2DGS ?? false;
|
||||||
this.preBlurAmount = options.preBlurAmount ?? 0.0;
|
this.preBlurAmount = options.preBlurAmount ?? 0.0;
|
||||||
this.blurAmount = options.blurAmount ?? 0.3;
|
this.blurAmount = options.blurAmount ?? 0.3;
|
||||||
@@ -350,6 +364,10 @@ 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 },
|
||||||
|
// 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
|
// Enable interpreting 0-thickness Gsplats as 2DGS
|
||||||
enable2DGS: { value: false },
|
enable2DGS: { value: false },
|
||||||
// Add to projected 2D splat covariance diagonal (thickens and brightens)
|
// 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.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.maxPixelRadius.value = this.maxPixelRadius;
|
||||||
|
this.uniforms.minAlpha.value = this.minAlpha;
|
||||||
this.uniforms.enable2DGS.value = this.enable2DGS;
|
this.uniforms.enable2DGS.value = this.enable2DGS;
|
||||||
this.uniforms.preBlurAmount.value = this.preBlurAmount;
|
this.uniforms.preBlurAmount.value = this.preBlurAmount;
|
||||||
this.uniforms.blurAmount.value = this.blurAmount;
|
this.uniforms.blurAmount.value = this.blurAmount;
|
||||||
|
|||||||
@@ -21,10 +21,6 @@ const float PI = 3.1415926535897932384626433832795;
|
|||||||
const float INFINITY = 1.0 / 0.0;
|
const float INFINITY = 1.0 / 0.0;
|
||||||
const float NEG_INFINITY = -INFINITY;
|
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) {
|
float sqr(float x) {
|
||||||
return x * x;
|
return x * x;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ uniform float near;
|
|||||||
uniform float far;
|
uniform float far;
|
||||||
uniform bool encodeLinear;
|
uniform bool encodeLinear;
|
||||||
uniform float maxStdDev;
|
uniform float maxStdDev;
|
||||||
|
uniform float minAlpha;
|
||||||
uniform bool disableFalloff;
|
uniform bool disableFalloff;
|
||||||
uniform float falloff;
|
uniform float falloff;
|
||||||
|
|
||||||
@@ -60,7 +61,7 @@ void main() {
|
|||||||
|
|
||||||
rgba.a *= mix(1.0, exp(-0.5 * z), falloff);
|
rgba.a *= mix(1.0, exp(-0.5 * z), falloff);
|
||||||
|
|
||||||
if (rgba.a < MIN_ALPHA) {
|
if (rgba.a < minAlpha) {
|
||||||
discard;
|
discard;
|
||||||
}
|
}
|
||||||
if (encodeLinear) {
|
if (encodeLinear) {
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ uniform uint numSplats;
|
|||||||
uniform vec4 renderToViewQuat;
|
uniform vec4 renderToViewQuat;
|
||||||
uniform vec3 renderToViewPos;
|
uniform vec3 renderToViewPos;
|
||||||
uniform float maxStdDev;
|
uniform float maxStdDev;
|
||||||
|
uniform float maxPixelRadius;
|
||||||
uniform float time;
|
uniform float time;
|
||||||
uniform float deltaTime;
|
uniform float deltaTime;
|
||||||
uniform bool debugFlag;
|
uniform bool debugFlag;
|
||||||
|
uniform float minAlpha;
|
||||||
uniform bool enable2DGS;
|
uniform bool enable2DGS;
|
||||||
uniform float blurAmount;
|
uniform float blurAmount;
|
||||||
uniform float preBlurAmount;
|
uniform float preBlurAmount;
|
||||||
@@ -52,7 +54,7 @@ void main() {
|
|||||||
vec4 quaternion, rgba;
|
vec4 quaternion, rgba;
|
||||||
unpackSplat(packed, center, scales, quaternion, rgba);
|
unpackSplat(packed, center, scales, quaternion, rgba);
|
||||||
|
|
||||||
if (rgba.a < MIN_ALPHA) {
|
if (rgba.a < minAlpha) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bvec3 zeroScales = equal(scales, vec3(0.0));
|
bvec3 zeroScales = equal(scales, vec3(0.0));
|
||||||
@@ -141,13 +143,13 @@ void main() {
|
|||||||
|
|
||||||
float fullBlurAmount = blurAmount;
|
float fullBlurAmount = blurAmount;
|
||||||
if ((focalDistance > 0.0) && (apertureAngle > 0.0)) {
|
if ((focalDistance > 0.0) && (apertureAngle > 0.0)) {
|
||||||
float focusRadius = MAX_PIXEL_RADIUS;
|
float focusRadius = maxPixelRadius;
|
||||||
if (viewCenter.z < 0.0) {
|
if (viewCenter.z < 0.0) {
|
||||||
float focusBlur = abs((-viewCenter.z - focalDistance) / viewCenter.z);
|
float focusBlur = abs((-viewCenter.z - focalDistance) / viewCenter.z);
|
||||||
float apertureRadius = focal.x * tan(0.5 * apertureAngle);
|
float apertureRadius = focal.x * tan(0.5 * apertureAngle);
|
||||||
focusRadius = focusBlur * apertureRadius;
|
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
|
// 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
|
// Compute anti-aliasing intensity scaling factor
|
||||||
float blurAdjust = sqrt(max(0.0, detOrig / det));
|
float blurAdjust = sqrt(max(0.0, detOrig / det));
|
||||||
rgba.a *= blurAdjust;
|
rgba.a *= blurAdjust;
|
||||||
if (rgba.a < MIN_ALPHA) {
|
if (rgba.a < minAlpha) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,8 +174,8 @@ 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(MAX_PIXEL_RADIUS, maxStdDev * sqrt(eigen1));
|
float scale1 = position.x * min(maxPixelRadius, maxStdDev * sqrt(eigen1));
|
||||||
float scale2 = position.y * min(MAX_PIXEL_RADIUS, maxStdDev * sqrt(eigen2));
|
float scale2 = position.y * min(maxPixelRadius, maxStdDev * sqrt(eigen2));
|
||||||
|
|
||||||
// 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 = eigenVec1 * scale1 + eigenVec2 * scale2;
|
||||||
|
|||||||
Reference in New Issue
Block a user