这是indexloc提供的服务,不要输入任何密码
Skip to content
Draft
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
1,312 changes: 1,225 additions & 87 deletions Cargo.lock

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,14 @@ default = [
"query_select",
# "query_sparse",

"mesh_proxy",

# TODO: bevy_interleave storage bind group read_only per plane attribute support
# "morph_particles",
"morph_interpolate",

# "solari",

"sort_bitonic",
"sort_radix", # TODO: fix macos radix sort
"sort_rayon",
Expand Down Expand Up @@ -93,6 +97,10 @@ precompute_covariance_3d = []
packed = []
planar = []

mesh_proxy = ["dep:mcubes"]

solari = ["mesh_proxy", "dep:bevy_solari"]

buffer_storage = []
buffer_texture = []

Expand Down Expand Up @@ -174,6 +182,8 @@ flexbuffers = { version = "25.2", optional = true }
half = { version = "2.6", features = ["serde"] }
# image = { version = "0.25.6", default-features = false, features = ["png"] }
kd-tree = { version = "0.6", optional = true }
mcubes = { version = "0.1.5", optional = true }
bevy_solari = { version = "0.17.1", optional = true }
noise = { version = "0.9.0", optional = true }
ply-rs = { version = "0.1", optional = true }
rand = "0.8"
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ bevy_gaussian_splatting --input-cloud [file://gaussian.ply | https://mitchell.mo
- [X] 3dgs
- [x] 4dgs
- [x] multi-cloud scene format
- [x] lighting and shadows
- [ ] morph targets and skeletons
- [ ] gltf gaussian extensions
- [ ] 4dgs motion blur
- [ ] [deformable radial kernel](https://github.com/VAST-AI-Research/Deformable-Radial-Kernel-Splatting)
Expand All @@ -45,10 +47,8 @@ bevy_gaussian_splatting --input-cloud [file://gaussian.ply | https://mitchell.mo
- [ ] 4D gaussian cloud wavelet compression
- [ ] accelerated spatial queries
- [ ] temporal depth sorting
- [ ] skeletons
- [ ] volume masks
- [ ] level of detail
- [ ] lighting and shadows
- [ ] bevy_openxr support
- [ ] bevy 3D camera to gaussian cloud pipeline

Expand Down
Empty file added examples/solari.rs
Empty file.
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub mod gaussian;
pub mod io;
pub mod material;
pub mod math;
#[cfg(feature = "mesh_proxy")]
pub mod mesh;
pub mod morph;
pub mod query;
pub mod render;
Expand All @@ -35,6 +37,9 @@ pub mod utils;
#[cfg(feature = "noise")]
pub mod noise;

#[cfg(feature = "mesh_proxy")]
pub use mesh::proxy::{ProxyMesh, ProxyMeshPlugin, ProxyMeshSettings, ProxyParams};

pub struct GaussianSplattingPlugin;

impl Plugin for GaussianSplattingPlugin {
Expand Down Expand Up @@ -62,6 +67,9 @@ impl Plugin for GaussianSplattingPlugin {
render::RenderPipelinePlugin::<Gaussian4d>::default(),
));

#[cfg(feature = "mesh_proxy")]
app.add_plugins(mesh::proxy::ProxyMeshPlugin);

app.add_plugins((material::MaterialPlugin, query::QueryPlugin));

#[cfg(feature = "noise")]
Expand Down
6 changes: 6 additions & 0 deletions src/material/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ pub mod spherindrical_harmonics;
#[cfg(feature = "material_noise")]
pub mod noise;

#[cfg(feature = "solari")]
pub mod solari;

#[derive(Default)]
pub struct MaterialPlugin;

Expand All @@ -19,6 +22,9 @@ impl Plugin for MaterialPlugin {
#[cfg(feature = "material_noise")]
app.add_plugins(noise::NoiseMaterialPlugin);

#[cfg(feature = "solari")]
app.add_plugins(solari::SolariMaterialPlugin);

app.add_plugins((
classification::ClassificationMaterialPlugin,
depth::DepthMaterialPlugin,
Expand Down
81 changes: 81 additions & 0 deletions src/material/solari.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use bevy::{
asset::{load_internal_asset, weak_handle},
ecs::query::Or,
pbr::MeshMaterial3d,
prelude::*,
solari::prelude::*,
};

use crate::mesh::proxy::{ProxyMesh, ProxyMeshSettings, ProxyParams};

const SOLARI_SHADER_HANDLE: Handle<Shader> = weak_handle!("6beaa8d4-026e-43a3-8f6b-13213e63ed05");

pub struct SolariMaterialPlugin;

impl Plugin for SolariMaterialPlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(app, SOLARI_SHADER_HANDLE, "solari.wgsl", Shader::from_wgsl);

app.register_type::<GaussianCloudSolari>();

app.add_systems(
PostUpdate,
(
ensure_proxy_settings,
attach_solari_proxies.after(ensure_proxy_settings),
),
);
}
}

#[derive(Component, Default, Clone, Copy, Reflect)]
#[reflect(Component)]
pub struct GaussianCloudSolari;

fn ensure_proxy_settings(
mut commands: Commands,
query: Query<Entity, (With<GaussianCloudSolari>, Without<ProxyMeshSettings>)>,
) {
for entity in &query {
commands
.entity(entity)
.insert(ProxyMeshSettings {
params: ProxyParams::default(),
});
}
}

fn attach_solari_proxies(
mut commands: Commands,
mut materials: ResMut<Assets<StandardMaterial>>,
query: Query<
(
Entity,
&ProxyMesh,
Option<&RaytracingMesh3d>,
Option<&MeshMaterial3d<StandardMaterial>>,
),
(With<GaussianCloudSolari>, Or<(Changed<ProxyMesh>, Added<GaussianCloudSolari>)>),
>,
) {
for (entity, mesh_proxy, raytracing_mesh, mesh_material) in &query {
if raytracing_mesh.is_none() {
commands
.entity(entity)
.insert(RaytracingMesh3d(mesh_proxy.0.clone()));
}

if mesh_material.is_none() {
let material_handle = materials.add(StandardMaterial {
base_color: Color::WHITE.into(),
perceptual_roughness: 0.9,
metallic: 0.0,
..default()
});

commands
.entity(entity)
.insert(MeshMaterial3d::<StandardMaterial>(material_handle));
}
}
}
113 changes: 113 additions & 0 deletions src/material/solari.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#define_import_path bevy_gaussian_splatting::solari

#import bevy_render::maths::PI

const SOLARI_WORLD_CACHE_MAX_SEARCH_STEPS: u32 = 3u;
const SOLARI_WORLD_CACHE_POSITION_BASE_CELL_SIZE: f32 = 0.25;
const SOLARI_WORLD_CACHE_POSITION_LOD_SCALE: f32 = 30.0;
const SOLARI_WORLD_CACHE_EMPTY_CELL: u32 = 0u;
const SOLARI_WORLD_CACHE_SIZE: u32 = #{SOLARI_WORLD_CACHE_SIZE};
const SOLARI_WORLD_CACHE_MASK: u32 = SOLARI_WORLD_CACHE_SIZE - 1u;

@group(4) @binding(0) var<storage, read> solari_world_cache_checksums:
array<atomic<u32>, #{SOLARI_WORLD_CACHE_SIZE}>;
@group(4) @binding(1) var<storage, read> solari_world_cache_radiance:
array<vec4<f32>, #{SOLARI_WORLD_CACHE_SIZE}>;

fn solari_shade_diffuse(
base_color: vec3<f32>,
world_position: vec3<f32>,
world_normal: vec3<f32>,
view_position: vec3<f32>,
exposure: f32,
) -> vec3<f32> {
let radiance = solari_world_cache_lookup(world_position, world_normal, view_position);
if all(radiance == vec3<f32>(0.0)) {
return base_color;
}

let diffuse_brdf = base_color / PI;
return radiance * exposure * diffuse_brdf;
}

fn solari_world_cache_lookup(
world_position: vec3<f32>,
world_normal: vec3<f32>,
view_position: vec3<f32>,
) -> vec3<f32> {
let cell_size = solari_get_cell_size(world_position, view_position);
let world_position_quantized =
bitcast<vec3<u32>>(solari_quantize_position(world_position, cell_size));
let world_normal_quantized =
bitcast<vec3<u32>>(solari_quantize_normal(world_normal));

var key = solari_compute_key(world_position_quantized, world_normal_quantized);
let checksum = solari_compute_checksum(world_position_quantized, world_normal_quantized);

for (var i = 0u; i < SOLARI_WORLD_CACHE_MAX_SEARCH_STEPS; i = i + 1u) {
let existing_checksum = atomicLoad(&solari_world_cache_checksums[key]);
if existing_checksum == checksum {
return solari_world_cache_radiance[key].rgb;
}

if existing_checksum == SOLARI_WORLD_CACHE_EMPTY_CELL {
return vec3<f32>(0.0);
}

key = solari_wrap_key(solari_pcg_hash(key));
}

return vec3<f32>(0.0);
}

fn solari_get_cell_size(world_position: vec3<f32>, view_position: vec3<f32>) -> f32 {
let camera_distance = distance(view_position, world_position) /
SOLARI_WORLD_CACHE_POSITION_LOD_SCALE;
let lod = exp2(floor(log2(1.0 + camera_distance)));
return SOLARI_WORLD_CACHE_POSITION_BASE_CELL_SIZE * lod;
}

fn solari_quantize_position(
world_position: vec3<f32>,
quantization_factor: f32,
) -> vec3<f32> {
return floor(world_position / quantization_factor + 0.0001);
}

fn solari_quantize_normal(world_normal: vec3<f32>) -> vec3<f32> {
return floor(normalize(world_normal) + 0.0001);
}

fn solari_compute_key(world_position: vec3<u32>, world_normal: vec3<u32>) -> u32 {
var key = solari_pcg_hash(world_position.x);
key = solari_pcg_hash(key + world_position.y);
key = solari_pcg_hash(key + world_position.z);
key = solari_pcg_hash(key + world_normal.x);
key = solari_pcg_hash(key + world_normal.y);
key = solari_pcg_hash(key + world_normal.z);
return solari_wrap_key(key);
}

fn solari_compute_checksum(world_position: vec3<u32>, world_normal: vec3<u32>) -> u32 {
var key = solari_iqint_hash(world_position.x);
key = solari_iqint_hash(key + world_position.y);
key = solari_iqint_hash(key + world_position.z);
key = solari_iqint_hash(key + world_normal.x);
key = solari_iqint_hash(key + world_normal.y);
key = solari_iqint_hash(key + world_normal.z);
return key;
}

fn solari_wrap_key(key: u32) -> u32 {
return key & SOLARI_WORLD_CACHE_MASK;
}

fn solari_pcg_hash(input: u32) -> u32 {
let state = input * 747796405u + 2891336453u;
let word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
fn solari_iqint_hash(input: u32) -> u32 {
let n = (input << 13u) ^ input;
return n * (n * n * 15731u + 789221u) + 1376312589u;
}
2 changes: 2 additions & 0 deletions src/mesh/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#[cfg(feature = "mesh_proxy")]
pub mod proxy;
Loading
Loading