Getting Started with Level-of-Detail
To get started with the new Level-of-Detail (LoD) features in Spark 2.0, the two simplest approaches are:
1. Create your SplatMesh with the new lod flag
This will load the splat file and create an LoD version of it in a background WebWorker (1-3 seconds per 1M input splats), supporting up to 30M or so input splats. Once the creation is complete, Spark will automatically render downsampled versions of your splats within a reasonable splat count budget for your platform.
2. Pre-build the LoD tree for faster loading and streaming (recommended approach)
Create the LoD tree from the command line and load the resulting .RAD file:
This will output filesmy-splats-lod.rad and more-splats-lod.rad. These can be loaded directly by Spark:
Note that the lod: true flag is unnecessary because the .RAD file encodes that information.
For instant loading you can stream the .RAD file, simply by setting the paged flag:
Handling huge coordinates
Spark internally defaults to a compact 16 bytes/splat encoding PackedSplats to save memory and increase performance (through less memory bandwidth). However, splat center coordinates are stored as float16, which has 0.1% relative precision, meaning coordinates that are 1000 units away will only allow steps of 1 unit, which can cause striping or other quantization artifacts.
Spark 2.0 supports a new ExtSplats extended splat encoding that uses 32 bytes/splat and stores center coordinates as float32 (along with other precision/range improvements). Because this can slightly reduce perforance, you should explicitly enable it where you need it:
-
Increased precision for loaded splats: If the splat file itself has large coordinates, you can enable
This will decode the splat file into the extended encoding format.ExtSplatswhen creating theSplatMesh: -
Increased precision for streamed/pooled splats: A
Once this is set, allSplatMeshloaded with thepagedflag will use a shared pool of splat buffers. ChoosingExtSplatsfor this pool is controlled bySparkRendererduring construction:SplatMeshs loaded with thepagedflag will use the extended encoding format.
Spark also allows you to control the intermediate global splat collection in SplatAccumulator through the additional option SparkRenderer.accumExtSplats. However, this is typically not necessary as Spark will encode the splats relative to the camera viewpoint, ensuring more precision is focused near the viewer where it matters.
Tuning LoD detail and performance
Spark's LoD system allows you to trade off between quality (more splats rendered) and performance (less splats, faster updates). You may need to tinker with the LoD parameters to achieve the right balance for your application.
Adjusting the LoD splat count budget
There are two main parameters for adjusting the # splat selected by the LoD system and rendered to the screen:
-
SparkRenderer.lodSplatCount: Set the base nubmer of LoD splats to render. If not set, this will be automatically set based on the platform: 500K for Oculus, 750K for Vision Pro, 1M for Android, 1.5M for iOS, and 2.5M for desktop. It is recommended to leave this alone and use the next parameter instead, so your application scales automatically by platform. -
SparkRenderer.lodSplatScale: LoD splat count multiplier. By default this is 1.0, and setting it to 2.0 will result in 2x thelodSplatCountbudget. Adjusting this is the easiest way to adjust detail vs. performance.
Shaping the selected LoD splats
Spark implements a fixed foveation system that allows you to emphasize splats directly in front of the viewer, falling off as the angle from the center increases. By default Spark will select splats around the viewer such that they all have roughly the same size based on distance. Setting foveation parameters will bias the selected splats toward the front direction, which matches human visual acuity. To adjust the shape, use the following parameters:
-
SparkRenderer.behindFoveate: Foveation scale to apply to LoD splats behind the viewer. Setting this to 0.1 for example will result in splats 10x larger behind the viewer compared to in front. -
SparkRenderer.coneFov0: Full-width angle in degrees of a cone around the view direction that will have "full resolution" (foveation=1.0). -
SparkRenderer.coneFov: Full-width angle in degrees of a cone around the view direction that will have "reduced resolution" specified by the next parameter. -
SparkRenderer.coneFoveate: Foveation to apply at theconeFovangle. The foveation will scale smoothly from 1.0 down toconeFoveateas the angle goes fromconeFov0toconeFov. FromconeFovto 180 degrees (behind the viewer), the foveation will scale smoothly fromconeFoveatedown tobehindFoveate.
Choosing these parameters well will focus the "splat budget" towards the frontal direction, resulting in more detail where the user is looking. When the viewpoint changes, the LoD system will update the selected splats to maintain the foveation shape, but there will be some latency in the update. Higher total splat budgets (for example by increasing lodSplatScale) will result in longer delays updating the selected shapes, so carefully selecting foveation parameters and splat count to balance detail vs. slower updates is important.
Biasing individual SplatMesh LoD budgets
The above parameters adjust the global splat LoD parameters, but you can also adjust individual SplatMeshes to emphasize/de-emphasize particular objects. To do this, set/adjust the following parameters on the SplatMesh object:
-
SplatMesh.lodScale: LoD detail scale factor for this object. Setting this to 2.0 results in 2x finer detail for this object, while setting to 0.5 will result in 2x coarser splats. -
SplatMesh.behindFoveate/SplatMesh.coneFov0/SplatMesh.coneFov/SplatMesh.coneFoveate: Override the globalSparkRenderer.behindFoveate/SparkRenderer.coneFov0/SparkRenderer.coneFov/SparkRenderer.coneFoveatefor this object.
build-lod command-line tool
To pre-build an LoD tree for a splat file and output a .RAD that can be loaded faster in Spark and even streamed in, use the build-lod command-line tool:
NOTE 1: The additional -- in the options tells npm that the following options are for the build-lod program. This is necessary if you have additional options that start with -/--, which will confuse `npm.
NOTE 2: Building and running the build-lod tool requires Rust to be installed. The recommended approach is by installing rustup as described on the main Rust page: https://rust-lang.org/tools/install/
Calling npm run build-lod invokes the Rust program in rust/build-lod, and you can build or run it directly:
cd rust/build-lod
cargo build --release
cargo run --release -- my-splats.ply more-splats.spz [..options]
--release option is important, without it the LoD building will run very slowly!
To get help for the command, run it without any parameters:
npm run build-lod
Usage: build-lod
[--unlod] // Remove LoD nodes with children from file
[--csplat] [--gsplat] // Use compact (csplat) or higher-precision (default gsplat) splat encoding
[--quick] [--quality] // Use quick (tiny-lod) or quality (bhatt-lod) LoD method (default quick)
...
For each input file my-splats.ply the tool will output a file my-splats-lod.rad, appending the -lod suffix to make it clear that it is an LoD tree file. There is also an --spz output option that will output a non-standard SPZ file that can be loaded in Spark, but has been deprecated in favor of the new RAD file which supports configurable encoding as well as streaming.
The most important options are:
--quick: Use the fast, compacttiny-lodmethod (default setting, no need to specify)--quality: Use the higher-quality, slowerbhatt-lodmethod. Recommended for offline LoD tree building and streaming.--max-sh=#: Limit the maximum Spherical Harmonics encoded, from 0..3.
The tool build-lod supports most splat file formats: .ply (including PlayCanvas compressed), .spz, .splat, .ksplat, .sog, .zip (containing SOGS files). It also accepts multiple file inputs, so you can for example run:
-lod.rad suffix and extension added to it.