https://github.com/schwa/spz-rs
Rust library for reading and writing the Niantic Labs Splat Point Cloud format <https://github.com/nianticlabs/spz/>.
https://github.com/schwa/spz-rs
Last synced: about 1 month ago
JSON representation
Rust library for reading and writing the Niantic Labs Splat Point Cloud format <https://github.com/nianticlabs/spz/>.
- Host: GitHub
- URL: https://github.com/schwa/spz-rs
- Owner: schwa
- License: mit
- Created: 2025-02-11T17:27:17.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2025-02-13T18:14:15.000Z (3 months ago)
- Last Synced: 2025-04-13T04:53:44.339Z (about 1 month ago)
- Language: Rust
- Size: 121 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# spz-rs
A Rust library for reading and writing the Niantic Labs Gaussian Splat Point Cloud format .
## Current Status
Limited testing against Niantics original implementation has been done. There is current *no guarantee* that this library will work with all `.spz` files (yet).
This library has an accompanying CLI tool for converting `.ply` files (using the most common Gaussian Splat Point Cloud format) to `.spz` files.
## File Format
The file format is not currently well documented by Niantic. The following is based on their original implementation.
gz compressed file with the extension `.spz`.
```ascii
+-------------------------------------+
| header (16-bytes) |
+-------------------------------------+
| position data (24-bytes per splat) |
+-------------------------------------+
| alpha data (1-byte per splat) |
+-------------------------------------+
| color data (3-bytes per splat) |
+-------------------------------------+
| scale data (3-bytes per splat) |
+-------------------------------------+
| rotation data (3-bytes per splat) |
+-------------------------------------+
| spherical harmonics data (varying) |
+-------------------------------------+
```### Header
```rust
struct Header {
magic: u32, // Always 0x5053474e
version: u32, // Always 0x00000002
num_points: u32,
sh_degree: u8, // 0, 1, or 3
fractional_bits: u8, // 0-23
flags: u8, // TODO: TODO
reserved: u8, // Always 0
}
```### Position Data
3 x 24-bit fixed point numbers, each representing the x, y, and z position of a splat. The fractional bits are specified in the header.
### Alpha Data
1 byte per splat. The sigmoid of the alpha value of a splat, scaled to 0-255.
### Color Data
3 bytes per splat. `((channel * 0.15) + 0.5) * 255.0`
### Scale Data
3 bytes per splat. `((v + 10.0) * 16.0)`
### Rotation Data
3 bytes per splat. Quaternion - drop the imaginary part, normalize and scale the real part to 0-255.
### Spherical Harmonics Data
"The data format uses 8 bits per coefficient, but when packing, we can quantize to fewer bits for better compression."
```c++
constexpr int sh1Bits = 5;
constexpr int shRestBits = 4;
const int shPerPoint = dimForDegree(g.shDegree) * 3;
for (size_t i = 0; i < numPoints * shPerPoint; i += shPerPoint) {
size_t j = 0;
for (; j < 9; j++) { // There are 9 coefficients for degree 1
packed.sh[i + j] = quantizeSH(g.sh[i + j], 1 << (8 - sh1Bits));
}
for (; j < shPerPoint; j++) {
packed.sh[i + j] = quantizeSH(g.sh[i + j], 1 << (8 - shRestBits));
}
}
// Quantizes to 8 bits, the round to nearest bucket center. 0 always maps to a bucket center.
uint8_t quantizeSH(float x, int bucketSize) {
int q = static_cast(std::round(x * 128.0f) + 128.0f);
q = (q + bucketSize / 2) / bucketSize * bucketSize;
return static_cast(std::clamp(q, 0, 255));
}
```## Links