Rendering Performance Optimization Guide
This guide helps optimize the SDK on devices with varying performance levels for a smooth 3DGS (3D Gaussian Splatting) rendering experience.
1. Disable Anti-Aliasing
Three.js WebGLRenderer does not enable anti-aliasing by default. If your project has antialias: true enabled, consider disabling it in performance-sensitive scenarios:
const renderer = new THREE.WebGLRenderer({ antialias: false });
Why disable it? Each Gaussian point in 3DGS is inherently a smoothly attenuating semi-transparent ellipse. When many ellipses overlap, edges are naturally smooth without additional multisample anti-aliasing (MSAA). Disabling MSAA reduces the number of samples per pixel processed by the GPU (typically from 4 to 1), improving rendering frame rate.
Cesium users: Cesium's Viewer does not enable MSAA by default, so no additional action is needed.
2. Reduce Rendering Resolution
By lowering the device pixel ratio, you can proportionally reduce the total number of pixels the GPU needs to process. This is the most effective approach for GPU fill-rate bottlenecks.
Three.js:
// High-performance device: use native pixel ratio
renderer.setPixelRatio(window.devicePixelRatio);
// Mid-range device: cap pixel ratio
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
// Low-end device / mobile: fixed 1x rendering
renderer.setPixelRatio(1.0);
Cesium:
const viewer = new Cesium.Viewer('container', {
// Control rendering resolution via resolutionScale
resolutionScale: 1.0 // Use 1.0 for low-end devices; use window.devicePixelRatio for high-end
});
Performance comparison reference (based on 1080p logical resolution):
| Pixel Ratio | Actual Rendered Pixels | Relative Cost |
|---|---|---|
| 1.0 | 1920×1080 ≈ 2.07M | 1× |
| 1.5 | 2880×1620 ≈ 4.66M | 2.25× |
| 2.0 | 3840×2160 ≈ 8.29M | 4× |
| 3.0 | 5760×3240 ≈ 18.66M | 9× |
High DPI screens (e.g., Retina) typically have a
devicePixelRatioof 2 or 3. Reducing it to 1.0 can yield 4–9x improvement in fragment processing performance, at the cost of a blurrier rendering output.
3. Limit Maximum Rendered Splats — setMaxSplats
This is the most important performance tuning parameter. It controls the upper limit of total Gaussian splats participating in rendering per frame.
lccObj.setMaxSplats(3000000); // Max 3 million splats per frame
The SDK's LOD scheduler traverses the scene's spatial index each frame, selecting nodes for rendering based on distance and view frustum. When the total splat count exceeds this limit, the scheduler discards nodes starting from distant or low-priority ones until the total count satisfies the limit.
Reference values: PC: 900K – 10M, Mobile: 500K – 2.6M, depending on device performance. See Device Tier Recommended Configurations at the end of this page.
4. Limit Maximum Splats Per Node — setMaxNodeSplats
Controls the maximum number of rendered splats per spatial node. Nodes exceeding this threshold are automatically downgraded to a coarser LOD level.
lccObj.setMaxNodeSplats(1500000); // Max 1.5 million splats per node
Why is this parameter needed? In large scenes, dense areas such as building clusters may contain millions of Gaussian splats in a single node at the highest LOD. Without this limit, the camera approaching such an area would cause a single node to consume the entire rendering budget, leaving no budget for other areas. This parameter makes rendering budget distribution more balanced.
Recommended values: Typically set to 1/3 – 2/3 of the setMaxSplats value, depending on scene density and device tier. See Device Tier Recommended Configurations at the end of this page.
5. Limit Rendering Start LOD — setStartLod
Controls the highest precision level. LOD 0 is the finest; higher values mean lower precision.
lccObj.setStartLod(0); // Finest quality (desktop default)
lccObj.setStartLod(1); // Skip finest level (mobile default)
lccObj.setStartLod(2); // Skip first two levels (very low-end devices)
The SDK builds multi-level LOD data for scene content. LOD 0 contains full precision data, LOD 1 has approximately 1/2 the splat count of LOD 0, and so on with each subsequent level. setStartLod limits the finest LOD level that the scheduler can select: setting it to 1 means LOD 0 data will not be loaded even when the camera is close to an object.
Performance impact:
| Setting | Close-up Quality | Splat Count Reduction | Use Case |
|---|---|---|---|
setStartLod(0) | Highest | — | High-end PC |
setStartLod(1) | Medium | ~50% | Mid-range PC and below, all mobile |
setStartLod(2) | Lower | ~75% | Low-end PC / Mobile |
6. Limit Maximum Rendering Distance — setMaxDistance
Controls the maximum rendering distance from the camera, in meters. Content beyond this distance will not be downloaded, decompressed, or rendered.
lccObj.setMaxDistance(200); // Desktop default
lccObj.setMaxDistance(100); // Mobile default
Reducing the maximum distance decreases the number of visible nodes, lowering the full pipeline cost of network downloads, CPU sorting, and GPU rendering. Suitable for indoor or close-range viewing scenarios.
Note: The SDK has a built-in altitude-adaptive mechanism — when the camera rises above 20 meters, the distance limit is automatically relaxed, allowing an overhead view to see farther.
Reference values:
| Platform | Range |
|---|---|
| PC | 100 – 240 |
| Mobile | 80 – 110 |
See Device Tier Recommended Configurations at the end of this page.
7. LOD Auto Optimization — setLodAutoLevelUp
When enabled, the SDK automatically improves the precision of certain nodes when the rendering budget has surplus capacity.
lccObj.setLodAutoLevelUp(true); // Enable (recommended for mid-to-high-end devices)
lccObj.setLodAutoLevelUp(false); // Disable (recommended for low-end devices or stable frame rate)
When the actual rendered splat count is below the setMaxSplats limit (e.g., the camera is facing an open area), the auto optimization mechanism allocates the remaining budget to nearby nodes, automatically loading higher-precision LOD data to enhance detail.
Trade-off: Enabling this improves visual quality, but may trigger additional data downloads and decompression, potentially causing occasional frame rate fluctuations on low-end devices.
8. Spherical Harmonics Lighting — useShcoef
Spherical harmonics lighting (SH) enables Gaussian splat colors to change with the viewing angle, producing more realistic reflections and glossy effects. The SDK has this disabled by default.
// Check if data contains SH coefficients before enabling
if (lccObj.hasShcoef()) {
lccObj.useShcoef(true, (percent) => {
console.log('SH loading: ' + (percent * 100).toFixed(1) + '%');
});
}
// Disable
lccObj.useShcoef(false, () => {});
When enabled:
- Surface reflections and gloss on objects change naturally with viewing angle
- Rendering quality is significantly improved, especially for materials like metal, glass, and lacquer
Performance cost:
- Increased GPU memory usage for storing additional RGB spherical harmonics coefficients
- Increased GPU vertex shader computation for evaluating 15 additional SH basis functions
- For LCC format, additional SH data files need to be downloaded
Recommendation: Enable only on high-end desktop devices. Not recommended for mobile.
9. Other Optimization Options
Local Caching (IndexedDB)
Enable local data caching via useIndexDB: true (enabled by default). On subsequent visits to the same scene, data is loaded directly from local storage, significantly reducing load times.
LOD Smooth Transition
LCC2 supports LOD smooth transitions (enabled by default), reducing visual popping during LOD switches:
lccObj.setSmooth(true); // Enable (default)
lccObj.setSmooth(false); // Disable
This feature constrains LOD differences between adjacent spatial nodes, eliminating precision discontinuities. The CPU overhead is minimal, and it is recommended to keep it enabled.
Device Tier Recommended Configurations
PC
| Tier | splatCount | nodeSplatCount | distance | startLod | devicePixelRatio |
|---|---|---|---|---|---|
| High | 10,000,000 | 6,000,000 | 240 | 0 | Native dpr |
| MidHigh | 4,200,000 | 1,500,000 | 220 | 1 | Native dpr |
| Balance | 2,200,000 | 1,000,000 | 200 | 1 | dpr > 1 ? 1.4 : dpr |
| MidLow | 1,800,000 | 700,000 | 150 | 2 | 1 |
| Low | 900,000 | 400,000 | 100 | 2 | dpr > 1 ? 0.8 : 0.5 |
Mobile
| Tier | splatCount | nodeSplatCount | distance | startLod | devicePixelRatio |
|---|---|---|---|---|---|
| High | 2,600,000 | 1,000,000 | 110 | 1 | Native dpr |
| MidHigh | 1,800,000 | 800,000 | 100 | 1 | Native dpr |
| Balance | 1,000,000 | 600,000 | 90 | 1 | dpr > 1 ? 1.2 : dpr |
| MidLow | 800,000 | 400,000 | 80 | 2 | 1 |
| Low | 500,000 | 300,000 | 80 | 2 | 0.8 |