Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: radix depth sort #8

Merged
merged 26 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
7b13244
docs: scaffold depth sort and more tooling
mosure Oct 15, 2023
350142c
docs: remove fast gzip issue
mosure Oct 16, 2023
2da7706
fix: correct aabb pipeline camera
mosure Oct 16, 2023
de59171
chore: wasm setup
mosure Oct 16, 2023
38753bf
fix: color and rotation calculations
mosure Oct 17, 2023
81d647a
fix: icecream.gcloud using new format
mosure Oct 17, 2023
d6ff2f8
feat: radix sort parameters
mosure Oct 17, 2023
1dfd9fd
feat: re-enable scale clamp
mosure Oct 17, 2023
6720753
docs: credit
mosure Oct 17, 2023
74215b5
feat: sorting pipeline checkin (in progress)
mosure Oct 23, 2023
57a8d61
feat: more bind group layouts (needs sort phase item implementation)
mosure Oct 24, 2023
33d069a
feat: depth buffer creation (needs pass buffers)
mosure Oct 24, 2023
2ac69c0
feat: shuffle test cube sh coefficients
mosure Oct 24, 2023
8e8ed5e
docs: add TODOs
mosure Oct 24, 2023
ce8a4d2
fix: metal struct packing
mosure Oct 25, 2023
e51bb30
feat: a few options for testing, corrects window dependent squashing …
mosure Oct 26, 2023
a03c4d9
refactor: viewer
mosure Oct 27, 2023
fe26a3c
Merge branch 'experiment/aspect-correction' into feat/depth-sort
mosure Oct 27, 2023
55c426d
fix: remove debug asset server and direction array
mosure Oct 27, 2023
b2dc420
docs: indirect buffer separation
mosure Oct 27, 2023
30802dc
fix: lint
mosure Oct 27, 2023
251aeb8
feat: indirect draw
mosure Oct 29, 2023
7660c9f
fix: only specify exclude
mosure Oct 29, 2023
40a6c94
fix: allow upside down camera
mosure Oct 30, 2023
b606233
credit
mosure Oct 30, 2023
a0d9342
feat: radix pre-sort working (/w instability)
mosure Nov 6, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

[target.wasm32-unknown-unknown]
runner = "wasm-server-runner"
rustflags = ["--cfg=web_sys_unstable_apis"]


# fix spurious network error on windows
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Cargo.lock
**/*.rs.bk
*.pdb

*.py

*.ply
*.gcloud
Expand Down
12 changes: 6 additions & 6 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@
{
"type": "lldb",
"request": "launch",
"name": "Debug executable 'bevy_gaussian_splatting'",
"name": "Debug executable 'viewer'",
"cargo": {
"args": [
"build",
"--bin=bevy_gaussian_splatting",
"--bin=viewer",
"--package=bevy_gaussian_splatting"
],
"filter": {
"name": "bevy_gaussian_splatting",
"name": "viewer",
"kind": "bin"
}
},
Expand All @@ -50,16 +50,16 @@
{
"type": "lldb",
"request": "launch",
"name": "Debug unit tests in executable 'bevy_gaussian_splatting'",
"name": "Debug unit tests in executable 'viewer'",
"cargo": {
"args": [
"test",
"--no-run",
"--bin=bevy_gaussian_splatting",
"--bin=viewer",
"--package=bevy_gaussian_splatting"
],
"filter": {
"name": "bevy_gaussian_splatting",
"name": "viewer",
"kind": "bin"
}
},
Expand Down
20 changes: 13 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "bevy_gaussian_splatting"
description = "bevy gaussian splatting render pipeline plugin"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
authors = ["mosure <[email protected]>"]
license = "MIT"
Expand All @@ -10,26 +10,32 @@ categories = ["computer-vision", "graphics", "rendering", "rendering::data-forma
homepage = "https://github.com/mosure/bevy_gaussian_splatting"
repository = "https://github.com/mosure/bevy_gaussian_splatting"
readme = "README.md"
include = ["tools"]
exclude = [".devcontainer", ".github", "docs", "dist", "build", "assets", "credits"]
default-run = "bevy_gaussian_splatting"
default-run = "viewer"

# TODO: use minimal bevy features
[dependencies]
bevy = "0.11.3"
bevy-inspector-egui = "0.20.0"
bevy_panorbit_camera = "0.8.0"
bincode2 = "2.0.1"
bytemuck = "1.14.0"
flate2 = "1.0.28"
ply-rs = "0.1.3"
rand = "0.8.5"
serde = "1.0.189"
wgpu = "0.16.0"


[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.7"
wasm-bindgen = "0.2.87"


# TODO: use minimal bevy features
[dependencies.bevy]
version = "0.11.3"
default-features = true


[dependencies.web-sys]
version = "0.3.4"
features = [
Expand Down Expand Up @@ -63,8 +69,8 @@ codegen-units = 1
path = "src/lib.rs"

[[bin]]
name = "bevy_gaussian_splatting"
path = "src/main.rs"
name = "viewer"
path = "viewer/viewer.rs"

[[bin]]
name = "ply_to_gcloud"
Expand Down
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@

bevy gaussian splatting render pipeline plugin

`cargo run -- {path to ply or gcloud.gz file}`
`cargo run -- {path to ply or gcloud file}`

## capabilities

- [X] ply to gcloud converter
- [X] gcloud and ply asset loaders
- [X] bevy gaussian cloud render pipeline
- [ ] wasm support /w [live demo](https://mosure.github.io/bevy_gaussian_splatting)
- [ ] temporal depth sorting
- [ ] f16 and f32 gcloud support
- [ ] 4D gaussian clouds via morph targets
- [ ] bevy_openxr support
Expand All @@ -43,14 +45,25 @@ fn setup_gaussian_cloud(
asset_server: Res<AssetServer>,
) {
commands.spawn(GaussianSplattingBundle {
cloud: asset_server.load("scenes/icecream.ply"),
cloud: asset_server.load("scenes/icecream.gcloud"),
..Default::default()
});

commands.spawn(Camera3dBundle::default());
}
```

## tools

- [ply to gcloud converter](tools/README.md#ply-to-gcloud-converter)
- [] gaussian cloud training tool

## wasm support

to build wasm run:
- `cargo build --target wasm32-unknown-unknown --release`
- `wasm-bindgen --out-dir ./out/ --target web ./target/`


## compatible bevy versions

Expand All @@ -64,11 +77,13 @@ fn setup_gaussian_cloud(
- [4d gaussians](https://github.com/hustvl/4DGaussians)
- [bevy](https://github.com/bevyengine/bevy)
- [bevy-hanabi](https://github.com/djeedai/bevy_hanabi)
- [deformable-3d-gaussians](https://github.com/ingra14m/Deformable-3D-Gaussians)
- [diff-gaussian-rasterization](https://github.com/graphdeco-inria/diff-gaussian-rasterization)
- [dreamgaussian](https://github.com/dreamgaussian/dreamgaussian)
- [dynamic-3d-gaussians](https://github.com/JonathonLuiten/Dynamic3DGaussians)
- [ewa splatting](https://www.cs.umd.edu/~zwicker/publications/EWASplatting-TVCG02.pdf)
- [gaussian-splatting](https://github.com/graphdeco-inria/gaussian-splatting)
- [gaussian-splatting-viewer](https://github.com/limacv/GaussianSplattingViewer/tree/main)
- [gaussian-splatting-web](https://github.com/cvlab-epfl/gaussian-splatting-web)
- [making gaussian splats smaller](https://aras-p.info/blog/2023/09/13/Making-Gaussian-Splats-smaller/)
- [onesweep](https://arxiv.org/ftp/arxiv/papers/2206/2206.01784.pdf)
Expand Down
Binary file modified assets/scenes/icecream.gcloud
Binary file not shown.
45 changes: 30 additions & 15 deletions src/gaussian.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use rand::seq::SliceRandom;
use std::{
io::{
BufReader,
Expand Down Expand Up @@ -41,7 +42,9 @@ const fn num_sh_coefficients(degree: usize) -> usize {
}
}
const SH_DEGREE: usize = 3;
pub const MAX_SH_COEFF_COUNT: usize = num_sh_coefficients(SH_DEGREE) * 3;
pub const SH_CHANNELS: usize = 3;
pub const MAX_SH_COEFF_COUNT_PER_CHANNEL: usize = num_sh_coefficients(SH_DEGREE);
pub const MAX_SH_COEFF_COUNT: usize = MAX_SH_COEFF_COUNT_PER_CHANNEL * SH_CHANNELS;
#[derive(
Clone,
Copy,
Expand Down Expand Up @@ -95,8 +98,9 @@ where
A: serde::de::SeqAccess<'de>,
{
let mut coefficients = [0.0; MAX_SH_COEFF_COUNT];
for i in 0..MAX_SH_COEFF_COUNT {
coefficients[i] = seq

for (i, coefficient) in coefficients.iter_mut().enumerate().take(MAX_SH_COEFF_COUNT) {
*coefficient = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(i, &self))?;
}
Expand Down Expand Up @@ -126,11 +130,9 @@ pub const MAX_SIZE_VARIANCE: f32 = 5.0;
// TODO: support f16 gaussian clouds (shader and asset loader)
pub struct Gaussian {
pub rotation: [f32; 4],
pub position: Vec3,
pub scale: Vec3,
pub opacity: f32,
pub position: [f32; 4],
pub scale_opacity: [f32; 4],
pub spherical_harmonic: SphericalHarmonicCoefficients,
padding: f32,
}

#[derive(
Expand All @@ -153,9 +155,18 @@ impl GaussianCloud {
0.0,
0.0,
],
position: Vec3::new(0.0, 0.0, 0.0),
scale: Vec3::new(0.5, 0.5, 0.5),
opacity: 0.8,
position: [
0.0,
0.0,
0.0,
1.0,
],
scale_opacity: [
0.5,
0.5,
0.5,
0.5,
],
spherical_harmonic: SphericalHarmonicCoefficients{
coefficients: [
1.0, 0.0, 1.0,
Expand All @@ -176,16 +187,18 @@ impl GaussianCloud {
0.6, 0.1, 0.2,
],
},
padding: 0.0,
};
let mut cloud = GaussianCloud(Vec::new());

for &x in [-0.5, 0.5].iter() {
for &y in [-0.5, 0.5].iter() {
for &z in [-0.5, 0.5].iter() {
let mut g = origin.clone();
g.position = Vec3::new(x, y, z);
let mut g = origin;
g.position = [x, y, z, 1.0];
cloud.0.push(g);

let mut rng = rand::thread_rng();
cloud.0.last_mut().unwrap().spherical_harmonic.coefficients.shuffle(&mut rng);
}
}
}
Expand Down Expand Up @@ -235,14 +248,16 @@ impl AssetLoader for GaussianCloudLoader {
let cloud = GaussianCloud(ply_cloud);

load_context.set_default_asset(LoadedAsset::new(cloud));
return Ok(());

Ok(())
},
Some(ext) if ext == "gcloud" => {
let decompressed = GzDecoder::new(bytes);
let cloud: GaussianCloud = deserialize_from(decompressed).expect("failed to decode cloud");

load_context.set_default_asset(LoadedAsset::new(cloud));
return Ok(());

Ok(())
},
_ => Ok(()),
}
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct GaussianSplattingPlugin;
impl Plugin for GaussianSplattingPlugin {
fn build(&self, app: &mut App) {
// TODO: allow hot reloading of GaussianCloud handle through inspector UI
app.register_type::<SphericalHarmonicCoefficients>();
app.register_type::<GaussianCloud>();
app.add_asset::<GaussianCloud>();
app.register_asset_reflect::<GaussianCloud>();
Expand Down
59 changes: 36 additions & 23 deletions src/ply.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use std::io::BufRead;

use bevy::{
asset::Error,
math::Vec3,
};
use bevy::asset::Error;
use ply_rs::{
ply::{
Property,
Expand All @@ -14,7 +11,9 @@ use ply_rs::{

use crate::gaussian::{
Gaussian,
MAX_SH_COEFF_COUNT_PER_CHANNEL,
MAX_SIZE_VARIANCE,
SH_CHANNELS,
};


Expand All @@ -25,19 +24,16 @@ impl PropertyAccess for Gaussian {

fn set_property(&mut self, key: String, property: Property) {
match (key.as_ref(), property) {
("x", Property::Float(v)) => self.position.x = v,
("y", Property::Float(v)) => self.position.y = v,
("z", Property::Float(v)) => self.position.z = v,
// ("nx", Property::Float(v)) => self.normal.x = v,
// ("ny", Property::Float(v)) => self.normal.y = v,
// ("nz", Property::Float(v)) => self.normal.z = v,
("x", Property::Float(v)) => self.position[0] = v,
("y", Property::Float(v)) => self.position[1] = v,
("z", Property::Float(v)) => self.position[2] = v,
("f_dc_0", Property::Float(v)) => self.spherical_harmonic.coefficients[0] = v,
("f_dc_1", Property::Float(v)) => self.spherical_harmonic.coefficients[1] = v,
("f_dc_2", Property::Float(v)) => self.spherical_harmonic.coefficients[2] = v,
("opacity", Property::Float(v)) => self.opacity = 1.0 / (1.0 + (-v).exp()),
("scale_0", Property::Float(v)) => self.scale.x = v,
("scale_1", Property::Float(v)) => self.scale.y = v,
("scale_2", Property::Float(v)) => self.scale.z = v,
("scale_0", Property::Float(v)) => self.scale_opacity[0] = v,
("scale_1", Property::Float(v)) => self.scale_opacity[1] = v,
("scale_2", Property::Float(v)) => self.scale_opacity[2] = v,
("opacity", Property::Float(v)) => self.scale_opacity[3] = 1.0 / (1.0 + (-v).exp()),
("rot_0", Property::Float(v)) => self.rotation[0] = v,
("rot_1", Property::Float(v)) => self.rotation[1] = v,
("rot_2", Property::Float(v)) => self.rotation[2] = v,
Expand All @@ -47,7 +43,6 @@ impl PropertyAccess for Gaussian {

match i {
_ if i + 3 < self.spherical_harmonic.coefficients.len() => {
// TODO: verify this is the correct sh order (packed not planar)
self.spherical_harmonic.coefficients[i + 3] = v;
},
_ => { },
Expand All @@ -65,18 +60,36 @@ pub fn parse_ply(mut reader: &mut dyn BufRead) -> Result<Vec<Gaussian>, Error> {
let mut cloud = Vec::new();

for (_ignore_key, element) in &header.elements {
match element.name.as_ref() {
"vertex" => { cloud = gaussian_parser.read_payload_for_element(&mut reader, &element, &header)?; },
_ => {},
if element.name == "vertex" {
cloud = gaussian_parser.read_payload_for_element(&mut reader, element, &header)?;
}
}

for gaussian in &mut cloud {
let mean_scale = (gaussian.scale.x + gaussian.scale.y + gaussian.scale.z) / 3.0;
gaussian.scale = gaussian.scale
.max(Vec3::splat(mean_scale - MAX_SIZE_VARIANCE))
.min(Vec3::splat(mean_scale + MAX_SIZE_VARIANCE))
.exp();
gaussian.position[3] = 1.0;

let mean_scale = (gaussian.scale_opacity[0] + gaussian.scale_opacity[1] + gaussian.scale_opacity[2]) / 3.0;
for i in 0..3 {
gaussian.scale_opacity[i] = gaussian.scale_opacity[i]
.max(mean_scale - MAX_SIZE_VARIANCE)
.min(mean_scale + MAX_SIZE_VARIANCE)
.exp();
}

let sh_src = gaussian.spherical_harmonic.coefficients;
let sh = &mut gaussian.spherical_harmonic.coefficients;

for (i, sh_src) in sh_src.iter().enumerate().skip(SH_CHANNELS) {
let j = i - SH_CHANNELS;

let channel = j / (MAX_SH_COEFF_COUNT_PER_CHANNEL - 1);
let coefficient = (j % (MAX_SH_COEFF_COUNT_PER_CHANNEL - 1)) + 1;

let interleaved_idx = coefficient * SH_CHANNELS + channel;
assert!(interleaved_idx >= SH_CHANNELS);

sh[interleaved_idx] = *sh_src;
}
}

Ok(cloud)
Expand Down
Loading