use crate::{
BasicColorModifiersBuffer, RotScaleBuffer, SelectionBuffer, TransformFlagsBuffer,
core::{
self, BufferWrapper, ComputeBundle, ComputeBundleBuilder, GaussianPod,
GaussianTransformBuffer, GaussiansBuffer, ModelTransformBuffer,
},
shader,
};
pub trait Modifier<G: GaussianPod> {
fn apply(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &GaussiansBuffer<G>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
);
}
impl<
G: GaussianPod,
F: Fn(
&wgpu::Device,
&mut wgpu::CommandEncoder,
&GaussiansBuffer<G>,
&ModelTransformBuffer,
&GaussianTransformBuffer,
),
> Modifier<G> for F
{
fn apply(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &GaussiansBuffer<G>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
) {
self(
device,
encoder,
gaussians,
model_transform,
gaussian_transform,
);
}
}
pub const MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor =
wgpu::BindGroupLayoutDescriptor {
label: Some("Modifier Gaussians Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
};
#[derive(Debug)]
pub struct WithSelection;
#[derive(Debug)]
pub struct NoSelection;
#[derive(Debug)]
pub struct BasicModifierBundle<G: GaussianPod, S = NoSelection, B = wgpu::BindGroup> {
bundle: ComputeBundle<B>,
gaussian_pod_marker: std::marker::PhantomData<G>,
selection_marker: std::marker::PhantomData<S>,
}
impl<G: GaussianPod, S, B> BasicModifierBundle<G, S, B> {
pub fn bundle(&self) -> &ComputeBundle<B> {
&self.bundle
}
}
impl<G: GaussianPod> BasicModifierBundle<G> {
pub const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> =
wgpu::BindGroupLayoutDescriptor {
label: Some("Basic Modifier Bind Group Layout"),
entries: BasicModifierBundle::<G, WithSelection>::BIND_GROUP_LAYOUT_DESCRIPTOR
.entries
.split_at(3)
.0,
};
pub fn new(
device: &wgpu::Device,
gaussians_buffer: &GaussiansBuffer<G>,
model_transform_buffer: &ModelTransformBuffer,
gaussian_transform_buffer: &GaussianTransformBuffer,
transform_flags_buffer: &TransformFlagsBuffer,
basic_color_modifiers_buffer: &BasicColorModifiersBuffer,
rot_scale_buffer: &RotScaleBuffer,
) -> Self {
Self::create_bundle_builder(false)
.build(
device,
[
[
gaussians_buffer.buffer().as_entire_binding(),
model_transform_buffer.buffer().as_entire_binding(),
gaussian_transform_buffer.buffer().as_entire_binding(),
],
[
transform_flags_buffer.buffer().as_entire_binding(),
basic_color_modifiers_buffer.buffer().as_entire_binding(),
rot_scale_buffer.buffer().as_entire_binding(),
],
],
)
.map(|bundle| Self {
bundle,
gaussian_pod_marker: std::marker::PhantomData,
selection_marker: std::marker::PhantomData,
})
.map_err(|e| log::error!("{e}"))
.expect("basic modifier bundle")
}
fn create_bundle_builder<'a>(
has_selection: bool,
) -> ComputeBundleBuilder<'a, wesl::PkgResolver> {
ComputeBundleBuilder::new()
.label("Basic Modifier")
.bind_group_layouts([
&MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
match has_selection {
true => &BasicModifierBundle::<G, WithSelection>::BIND_GROUP_LAYOUT_DESCRIPTOR,
false => &BasicModifierBundle::<G>::BIND_GROUP_LAYOUT_DESCRIPTOR,
},
])
.resolver({
let mut resolver = wesl::PkgResolver::new();
resolver.add_package(&core::shader::PACKAGE);
resolver.add_package(&shader::PACKAGE);
resolver
})
.main_shader(
"wgpu_3dgs_editor::modifier::basic"
.parse()
.expect("modifier::basic module path"),
)
.entry_point("main")
.wesl_compile_options(wesl::CompileOptions {
features: wesl::Features {
flags: G::features()
.into_iter()
.chain(std::iter::once(("selection_buffer", has_selection)))
.map(|(k, v)| (k.to_string(), v.into()))
.collect(),
..Default::default()
},
..Default::default()
})
}
}
impl<G: GaussianPod> BasicModifierBundle<G, WithSelection> {
pub const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor<'static> =
wgpu::BindGroupLayoutDescriptor {
label: Some("Basic Modifier Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
};
#[allow(clippy::too_many_arguments)]
pub fn new_with_selection(
device: &wgpu::Device,
gaussians_buffer: &GaussiansBuffer<G>,
model_transform_buffer: &ModelTransformBuffer,
gaussian_transform_buffer: &GaussianTransformBuffer,
transform_flags_buffer: &TransformFlagsBuffer,
basic_color_modifiers_buffer: &BasicColorModifiersBuffer,
rot_scale_buffer: &RotScaleBuffer,
selection_buffer: &SelectionBuffer,
) -> Self {
BasicModifierBundle::<G>::create_bundle_builder(true)
.build(
device,
[
vec![
gaussians_buffer.buffer().as_entire_binding(),
model_transform_buffer.buffer().as_entire_binding(),
gaussian_transform_buffer.buffer().as_entire_binding(),
],
vec![
transform_flags_buffer.buffer().as_entire_binding(),
basic_color_modifiers_buffer.buffer().as_entire_binding(),
rot_scale_buffer.buffer().as_entire_binding(),
selection_buffer.buffer().as_entire_binding(),
],
],
)
.map(|bundle| Self {
bundle,
gaussian_pod_marker: std::marker::PhantomData,
selection_marker: std::marker::PhantomData,
})
.map_err(|e| log::error!("{e}"))
.expect("basic modifier bundle")
}
}
impl<G: GaussianPod, S> BasicModifierBundle<G, S> {
pub fn apply_with_count(&self, encoder: &mut wgpu::CommandEncoder, gaussian_count: u32) {
self.bundle().dispatch(encoder, gaussian_count);
}
}
impl<G: GaussianPod, S> Modifier<G> for BasicModifierBundle<G, S> {
fn apply(
&self,
_device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &GaussiansBuffer<G>,
_model_transform: &ModelTransformBuffer,
_gaussian_transform: &GaussianTransformBuffer,
) {
self.apply_with_count(encoder, gaussians.len() as u32);
}
}
impl<G: GaussianPod> BasicModifierBundle<G, NoSelection, ()> {
pub fn new_without_bind_group(device: &wgpu::Device) -> Self {
BasicModifierBundle::<G>::create_bundle_builder(false)
.build_without_bind_groups(device)
.map(|bundle| Self {
bundle,
gaussian_pod_marker: std::marker::PhantomData,
selection_marker: std::marker::PhantomData,
})
.expect("basic modifier bundle")
}
}
impl<G: GaussianPod> BasicModifierBundle<G, WithSelection, ()> {
pub fn new_without_bind_group_with_selection(device: &wgpu::Device) -> Self {
BasicModifierBundle::<G>::create_bundle_builder(true)
.build_without_bind_groups(device)
.map(|bundle| Self {
bundle,
gaussian_pod_marker: std::marker::PhantomData,
selection_marker: std::marker::PhantomData,
})
.expect("basic modifier bundle")
}
}
impl<G: GaussianPod, S> BasicModifierBundle<G, S, ()> {
pub fn apply_with_count(
&self,
encoder: &mut wgpu::CommandEncoder,
gaussians_bind_group: &wgpu::BindGroup,
bind_group: &wgpu::BindGroup,
gaussian_count: u32,
) {
self.bundle()
.dispatch(encoder, gaussian_count, [gaussians_bind_group, bind_group]);
}
}
#[derive(Debug)]
pub struct BasicModifier<G: GaussianPod, S = NoSelection> {
pub transform_flags_buffer: TransformFlagsBuffer,
pub basic_color_modifiers_buffer: BasicColorModifiersBuffer,
pub rot_scale_buffer: RotScaleBuffer,
pub modifier: BasicModifierBundle<G, S>,
}
impl<G: GaussianPod> BasicModifier<G> {
pub fn new(
device: &wgpu::Device,
gaussians_buffer: &GaussiansBuffer<G>,
model_transform_buffer: &ModelTransformBuffer,
gaussian_transform_buffer: &GaussianTransformBuffer,
) -> Self {
log::debug!("Creating transform flags buffer");
let transform_flags_buffer = TransformFlagsBuffer::new(device);
log::debug!("Creating basic color modifiers buffer");
let basic_color_modifiers_buffer = BasicColorModifiersBuffer::new(device);
log::debug!("Creating rotation scale buffer");
let rot_scale_buffer = RotScaleBuffer::new(device);
log::debug!("Creating basic modifier bundle");
let modifier = BasicModifierBundle::new(
device,
gaussians_buffer,
model_transform_buffer,
gaussian_transform_buffer,
&transform_flags_buffer,
&basic_color_modifiers_buffer,
&rot_scale_buffer,
);
log::debug!("Basic modifier created");
Self {
transform_flags_buffer,
basic_color_modifiers_buffer,
rot_scale_buffer,
modifier,
}
}
}
impl<G: GaussianPod> BasicModifier<G, WithSelection> {
pub fn new_with_selection(
device: &wgpu::Device,
gaussians_buffer: &GaussiansBuffer<G>,
model_transform_buffer: &ModelTransformBuffer,
gaussian_transform_buffer: &GaussianTransformBuffer,
selection_buffer: &SelectionBuffer,
) -> Self {
log::debug!("Creating transform flags buffer");
let transform_flags_buffer = TransformFlagsBuffer::new(device);
log::debug!("Creating basic color modifiers buffer");
let basic_color_modifiers_buffer = BasicColorModifiersBuffer::new(device);
log::debug!("Creating rotation scale buffer");
let rot_scale_buffer = RotScaleBuffer::new(device);
log::debug!("Creating basic modifier bundle");
let modifier = BasicModifierBundle::new_with_selection(
device,
gaussians_buffer,
model_transform_buffer,
gaussian_transform_buffer,
&transform_flags_buffer,
&basic_color_modifiers_buffer,
&rot_scale_buffer,
selection_buffer,
);
log::debug!("Basic modifier created");
Self {
transform_flags_buffer,
basic_color_modifiers_buffer,
rot_scale_buffer,
modifier,
}
}
}
impl<G: GaussianPod, S> Modifier<G> for BasicModifier<G, S> {
fn apply(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &GaussiansBuffer<G>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
) {
self.modifier.apply(
device,
encoder,
gaussians,
model_transform,
gaussian_transform,
);
}
}