这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2,447 changes: 2,027 additions & 420 deletions Cargo.lock

Large diffs are not rendered by default.

18 changes: 10 additions & 8 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 = "2.7.6"
version = "3.0.0"
edition = "2021"
authors = ["mosure <mitchell@mosure.me>"]
license = "MIT OR Apache-2.0"
Expand Down Expand Up @@ -106,6 +106,7 @@ tooling = ["byte-unit"]
perftest = []

headless = [
"bevy/png",
"io_flexbuffers",
"io_ply",
"planar",
Expand All @@ -116,6 +117,7 @@ headless = [
]

viewer = [
"bevy/png",
"bevy-inspector-egui",
"bevy_panorbit_camera",
# "bevy_transform_gizmo",
Expand All @@ -141,20 +143,20 @@ webgpu = ["bevy/webgpu"]


[dependencies]
bevy_args = "1.6"
bevy-inspector-egui = { version = "0.27", optional = true }
bevy_args = "1.7"
bevy-inspector-egui = { version = "0.28", optional = true }
bevy_mod_picking = { version = "0.20", optional = true }
# bevy_panorbit_camera = { git = "https://github.com/mosure/bevy_panorbit_camera.git", optional = true, features = ["bevy_egui"] }
bevy_panorbit_camera = { version = "0.19.5", optional = true, features = ["bevy_egui"] }
bevy_panorbit_camera = { version = "0.21", optional = true, features = ["bevy_egui"] }
bevy_transform_gizmo = { version = "0.12", optional = true }
bincode2 = { version = "2.0", optional = true }
byte-unit = { version = "5.1", optional = true }
bytemuck = "1.19"
bytemuck = "1.20"
clap = { version = "4.5", features = ["derive"] }
flate2 = { version = "1.0", optional = true }
flexbuffers = { version = "2.0", optional = true }
half = { version = "2.3", optional = true, features = ["serde"] }
image = { version = "0.25.0", default-features = false, features = ["png"] }
image = { version = "0.25.2", default-features = false, features = ["png"] }
kd-tree = { version = "0.6", optional = true }
noise = { version = "0.9.0", optional = true }
ply-rs = { version = "0.1", optional = true }
Expand All @@ -163,7 +165,7 @@ rayon = { version = "1.8", optional = true }
serde = "1.0"
static_assertions = "1.1"
typenum = "1.17"
wgpu = "0.20"
wgpu = "23.0.1"


[target.'cfg(target_arch = "wasm32")'.dependencies]
Expand All @@ -172,7 +174,7 @@ wasm-bindgen = "0.2"


[dependencies.bevy]
version = "0.14"
version = "0.15"
default-features = false
features = [
"bevy_asset",
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@ fn setup_gaussian_cloud(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
commands.spawn(GaussianSplattingBundle {
cloud: asset_server.load("scenes/icecream.gcloud"),
..Default::default()
});
// GaussianCloudSettings and Visibility are automatically added
commands.spawn(
GaussianCloudHandle(asset_server.load("scenes/icecream.gcloud")),
);

commands.spawn(Camera3dBundle::default());
}
Expand All @@ -79,6 +79,7 @@ fn setup_gaussian_cloud(

| `bevy_gaussian_splatting` | `bevy` |
| :-- | :-- |
| `3.0` | `0.15` |
| `2.3` | `0.14` |
| `2.1` | `0.13` |
| `0.4 - 2.0` | `0.12` |
Expand Down
16 changes: 7 additions & 9 deletions examples/headless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use bevy_args::BevyArgsPlugin;
use bevy_gaussian_splatting::{
GaussianCamera,
GaussianCloud,
GaussianSplattingBundle,
GaussianCloudHandle,
GaussianSplattingPlugin,
random_gaussians,
utils::GaussianSplattingViewer,
Expand Down Expand Up @@ -394,18 +394,16 @@ fn setup_gaussian_cloud(


commands.spawn((
GaussianSplattingBundle { cloud, ..default() },
GaussianCloudHandle(cloud),
Name::new("gaussian_cloud"),
));

commands.spawn((
Camera3dBundle {
transform: Transform::from_translation(Vec3::new(0.0, 1.5, 5.0)),
tonemapping: Tonemapping::None,
camera: Camera {
target: render_target,
..default()
},
Camera3d::default(),
Transform::from_translation(Vec3::new(0.0, 1.5, 5.0)),
Tonemapping::None,
Camera {
target: render_target,
..default()
},
GaussianCamera::default(),
Expand Down
51 changes: 23 additions & 28 deletions examples/multi_camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ use bevy_gaussian_splatting::{
Gaussian,
GaussianCamera,
GaussianCloud,
GaussianMode,
GaussianCloudHandle,
GaussianCloudSettings,
GaussianSplattingBundle,
GaussianMode,
GaussianSplattingPlugin,
gaussian::f32::Rotation,
utils::{
Expand Down Expand Up @@ -161,14 +161,13 @@ pub fn setup_surfel_compare(
}

commands.spawn((
GaussianSplattingBundle {
cloud: gaussian_assets.add(GaussianCloud::from_gaussians(red_gaussians)),
settings: GaussianCloudSettings {
aabb: true,
transform: Transform::from_translation(Vec3::new(spacing, spacing, 0.0)),
gaussian_mode: GaussianMode::GaussianSurfel,
..default()
},
Transform::from_translation(Vec3::new(spacing, spacing, 0.0)),
GaussianCloudHandle(
gaussian_assets.add(GaussianCloud::from_gaussians(red_gaussians))
),
GaussianCloudSettings {
aabb: true,
gaussian_mode: GaussianMode::GaussianSurfel,
..default()
},
Name::new("gaussian_cloud_2dgs"),
Expand All @@ -178,15 +177,13 @@ pub fn setup_surfel_compare(
GaussianCamera {
warmup: true,
},
Camera3dBundle {
camera: Camera{
order: 0,
..default()
},
transform: Transform::from_translation(Vec3::new(0.0, 1.5, 20.0)),
tonemapping: Tonemapping::None,
Camera3d::default(),
Camera{
order: 0,
..default()
},
Transform::from_translation(Vec3::new(0.0, 1.5, 20.0)),
Tonemapping::None,
CameraPosition {
pos: UVec2::new(0, 0),
},
Expand Down Expand Up @@ -232,20 +229,18 @@ fn press_s_to_spawn_camera(
GaussianCamera {
warmup: true,
},
Camera3dBundle {
camera: Camera{
order: 1,
viewport: Viewport {
physical_position: pos * size,
physical_size: size,
..default()
}.into(),
Camera3d::default(),
Camera{
order: 1,
viewport: Viewport {
physical_position: pos * size,
physical_size: size,
..default()
},
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 40.0)),
tonemapping: Tonemapping::None,
}.into(),
..default()
},
Transform::from_translation(Vec3::new(0.0, 0.0, 40.0)),
Tonemapping::None,
CameraPosition {
pos,
},
Expand Down
111 changes: 110 additions & 1 deletion src/gaussian/cloud.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@ use rand::{
Rng,
};

use bevy::prelude::*;
use bevy::{
prelude::*,
render::{
primitives::Aabb,
sync_world::SyncToRenderWorld,
view::visibility::{
check_visibility,
NoFrustumCulling,
VisibilitySystems,
},
},
};
use serde::{
Deserialize,
Serialize,
Expand All @@ -23,6 +34,7 @@ use crate::{
ScaleOpacity,
},
packed::Gaussian,
settings::GaussianCloudSettings,
},
material::spherical_harmonics::{
HALF_SH_COEFF_COUNT,
Expand All @@ -40,6 +52,84 @@ use crate::gaussian::f16::{
};


#[derive(Default)]
pub struct GaussianCloudPlugin;

impl Plugin for GaussianCloudPlugin {
fn build(&self, app: &mut App) {
app.add_systems(
PostUpdate,
(
calculate_bounds.in_set(VisibilitySystems::CalculateBounds),
check_visibility::<With<GaussianCloudHandle>>.in_set(VisibilitySystems::CheckVisibility),
)
);
}
}


// TODO: handle aabb updates (e.g. gaussian particle movements)
#[allow(clippy::type_complexity)]
pub fn calculate_bounds(
mut commands: Commands,
gaussian_clouds: Res<Assets<GaussianCloud>>,
without_aabb: Query<
(
Entity,
&GaussianCloudHandle,
),
(
Without<Aabb>,
Without<NoFrustumCulling>,
),
>,
) {
for (entity, cloud_handle) in &without_aabb {
if let Some(cloud) = gaussian_clouds.get(cloud_handle) {
if let Some(aabb) = cloud.compute_aabb() {
commands.entity(entity).try_insert(aabb);
}
}
}
}


#[derive(
Component,
Clone,
Debug,
Default,
PartialEq,
Reflect,
)]
#[reflect(Component, Default)]
#[require(
GaussianCloudSettings,
SyncToRenderWorld,
Transform,
Visibility,
)]
pub struct GaussianCloudHandle(pub Handle<GaussianCloud>);

impl From<Handle<GaussianCloud>> for GaussianCloudHandle {
fn from(handle: Handle<GaussianCloud>) -> Self {
Self(handle)
}
}

impl From<GaussianCloudHandle> for AssetId<GaussianCloud> {
fn from(handle: GaussianCloudHandle) -> Self {
handle.0.id()
}
}

impl From<&GaussianCloudHandle> for AssetId<GaussianCloud> {
fn from(handle: &GaussianCloudHandle) -> Self {
handle.0.id()
}
}


#[cfg(feature = "f16")]
#[derive(
Asset,
Expand Down Expand Up @@ -133,6 +223,25 @@ impl GaussianCloud {
&mut self.position_visibility[index].visibility
}

pub fn compute_aabb(&self) -> Option<Aabb> {
if self.is_empty() {
return None;
}

let mut min = Vec3::splat(f32::INFINITY);
let mut max = Vec3::splat(f32::NEG_INFINITY);

// TODO: find a more correct aabb bound derived from scalar max gaussian scale
let max_scale = 0.1;

for position in self.position_iter() {
min = min.min(Vec3::from(*position) - Vec3::splat(max_scale));
max = max.max(Vec3::from(*position) + Vec3::splat(max_scale));
}

Aabb::from_min_max(min, max).into()
}


// pub fn rotation(&self, index: usize) -> &[f32; 4] {
// #[cfg(feature = "f16")]
Expand Down
3 changes: 1 addition & 2 deletions src/gaussian/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ pub enum GaussianCloudRasterize {
}


// TODO: breakdown into components
#[derive(Component, Reflect, Clone)]
#[reflect(Component)]
pub struct GaussianCloudSettings {
pub aabb: bool,
pub global_opacity: f32,
pub global_scale: f32,
pub transform: Transform,
pub opacity_adaptive_radius: bool,
pub visualize_bounding_box: bool,
pub sort_mode: SortMode,
Expand All @@ -85,7 +85,6 @@ impl Default for GaussianCloudSettings {
aabb: false,
global_opacity: 1.0,
global_scale: 1.0,
transform: Transform::IDENTITY,
opacity_adaptive_radius: true,
visualize_bounding_box: false,
sort_mode: SortMode::default(),
Expand Down
11 changes: 5 additions & 6 deletions src/io/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use std::io::{

use bevy::asset::{
AssetLoader,
AsyncReadExt,
LoadContext,
io::Reader,
};
Expand All @@ -26,11 +25,11 @@ impl AssetLoader for GaussianCloudLoader {
type Settings = ();
type Error = std::io::Error;

async fn load<'a>(
&'a self,
reader: &'a mut Reader<'_>,
_settings: &'a Self::Settings,
load_context: &'a mut LoadContext<'_>,
async fn load(
&self,
reader: &mut dyn Reader,
_: &Self::Settings,
load_context: &mut LoadContext<'_>,
) -> Result<Self::Asset, Self::Error> {
let mut bytes = Vec::new();
reader.read_to_end(&mut bytes).await?;
Expand Down
Loading