Skip to main content

MultiModelViewer

Struct MultiModelViewer 

Source
pub struct MultiModelViewer<G: GaussianPod = DefaultGaussianPod, K: Hash + Eq = String> {
    pub models: HashMap<K, MultiModelViewerModel<G>>,
    pub world_buffers: MultiModelViewerWorldBuffers,
    pub preprocessor: Preprocessor<G, ()>,
    pub radix_sorter: RadixSorter<()>,
    pub renderer: Renderer<G, ()>,
    pub gaussians_buffer_usage: BufferUsages,
}
Expand description

The 3D Gaussian splatting viewer for multiple models.

Fields§

§models: HashMap<K, MultiModelViewerModel<G>>§world_buffers: MultiModelViewerWorldBuffers§preprocessor: Preprocessor<G, ()>§radix_sorter: RadixSorter<()>§renderer: Renderer<G, ()>§gaussians_buffer_usage: BufferUsages

The usage for the gaussians buffer when MultiModelViewer::insert_model is called.

Can be overridden when inserting model using MultiModelViewer::insert_model_with.

Implementations§

Source§

impl<G: GaussianPod, K: Hash + Eq> MultiModelViewer<G, K>

Source

pub fn new( device: &Device, texture_format: TextureFormat, ) -> Result<Self, ViewerCreateError>

Create a new viewer.

Examples found in repository?
examples/multi_model.rs (line 156)
79    async fn init(window: Arc<Window>, args: &Args) -> Self {
80        let model_paths = &args.models;
81        let model_offset = Vec3::from_slice(&args.offset);
82        let size = window.inner_size();
83
84        log::debug!("Creating wgpu instance");
85        let instance =
86            wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
87
88        log::debug!("Creating window surface");
89        let surface = instance.create_surface(window.clone()).expect("surface");
90
91        log::debug!("Requesting adapter");
92        let adapter = instance
93            .request_adapter(&wgpu::RequestAdapterOptions {
94                power_preference: wgpu::PowerPreference::HighPerformance,
95                compatible_surface: Some(&surface),
96                force_fallback_adapter: false,
97            })
98            .await
99            .expect("adapter");
100
101        log::debug!("Requesting device");
102        let (device, queue) = adapter
103            .request_device(&wgpu::DeviceDescriptor {
104                label: Some("Device"),
105                required_limits: adapter.limits(),
106                ..Default::default()
107            })
108            .await
109            .expect("device");
110
111        let surface_caps = surface.get_capabilities(&adapter);
112        let surface_format = surface_caps.formats[0];
113        let config = wgpu::SurfaceConfiguration {
114            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
115            format: surface_format,
116            width: size.width.max(1),
117            height: size.height.max(1),
118            present_mode: surface_caps.present_modes[0],
119            alpha_mode: surface_caps.alpha_modes[0],
120            view_formats: vec![surface_format.remove_srgb_suffix()],
121            desired_maximum_frame_latency: 2,
122        };
123
124        log::debug!("Configuring surface");
125        surface.configure(&device, &config);
126
127        log::debug!("Creating gaussians");
128        let gaussians = model_paths
129            .iter()
130            .map(|model_path| {
131                log::debug!("Reading model from {model_path}");
132                [GaussiansSource::Ply, GaussiansSource::Spz]
133                    .into_iter()
134                    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
135                    .expect("gaussians")
136            })
137            .collect::<Vec<_>>();
138
139        log::debug!("Computing gaussian centroids");
140        let mut gaussian_centroids = gaussians
141            .iter()
142            .map(|g| {
143                let mut centroid = Vec3::ZERO;
144                for gaussian in g.iter_gaussian() {
145                    centroid += gaussian.pos;
146                }
147                centroid / g.len() as f32
148            })
149            .collect::<Vec<_>>();
150
151        log::debug!("Creating camera");
152        let camera = gs::Camera::new(0.1..1e4, 60f32.to_radians());
153
154        log::debug!("Creating viewer");
155        let mut viewer =
156            gs::MultiModelViewer::new(&device, config.view_formats[0]).expect("viewer");
157
158        let quat = Quat::from_axis_angle(Vec3::Z, 180f32.to_radians());
159        for (i, gaussians) in gaussians.iter().enumerate() {
160            let offset = model_offset * i as f32;
161
162            log::debug!("Pushing model {i}");
163
164            viewer.insert_model(&device, i, gaussians);
165            viewer
166                .update_model_transform(&queue, &i, offset, quat, Vec3::ONE)
167                .expect("update model");
168
169            gaussian_centroids[i] = quat.mul_vec3(gaussian_centroids[i]) + offset;
170        }
171
172        log::info!("System initialized");
173
174        Self {
175            surface,
176            device,
177            queue,
178            config,
179
180            camera,
181            gaussians,
182            gaussian_centroids,
183            viewer,
184        }
185    }
Source

pub fn new_with_options( device: &Device, texture_format: TextureFormat, options: ViewerCreateOptions, ) -> Result<Self, ViewerCreateError>

Create a new viewer with extra ViewerCreateOptions.

Note that only ViewerCreateOptions::gaussians_buffer_usage is used when inserting models with MultiModelViewer::insert_model. You can also override the usage using MultiModelViewer::insert_model_with.

Source

pub fn insert_model( &mut self, device: &Device, key: K, gaussians: &impl IterGaussian, ) -> Option<MultiModelViewerModel<G>>

Insert a new model to the viewer.

Examples found in repository?
examples/multi_model.rs (line 164)
79    async fn init(window: Arc<Window>, args: &Args) -> Self {
80        let model_paths = &args.models;
81        let model_offset = Vec3::from_slice(&args.offset);
82        let size = window.inner_size();
83
84        log::debug!("Creating wgpu instance");
85        let instance =
86            wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
87
88        log::debug!("Creating window surface");
89        let surface = instance.create_surface(window.clone()).expect("surface");
90
91        log::debug!("Requesting adapter");
92        let adapter = instance
93            .request_adapter(&wgpu::RequestAdapterOptions {
94                power_preference: wgpu::PowerPreference::HighPerformance,
95                compatible_surface: Some(&surface),
96                force_fallback_adapter: false,
97            })
98            .await
99            .expect("adapter");
100
101        log::debug!("Requesting device");
102        let (device, queue) = adapter
103            .request_device(&wgpu::DeviceDescriptor {
104                label: Some("Device"),
105                required_limits: adapter.limits(),
106                ..Default::default()
107            })
108            .await
109            .expect("device");
110
111        let surface_caps = surface.get_capabilities(&adapter);
112        let surface_format = surface_caps.formats[0];
113        let config = wgpu::SurfaceConfiguration {
114            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
115            format: surface_format,
116            width: size.width.max(1),
117            height: size.height.max(1),
118            present_mode: surface_caps.present_modes[0],
119            alpha_mode: surface_caps.alpha_modes[0],
120            view_formats: vec![surface_format.remove_srgb_suffix()],
121            desired_maximum_frame_latency: 2,
122        };
123
124        log::debug!("Configuring surface");
125        surface.configure(&device, &config);
126
127        log::debug!("Creating gaussians");
128        let gaussians = model_paths
129            .iter()
130            .map(|model_path| {
131                log::debug!("Reading model from {model_path}");
132                [GaussiansSource::Ply, GaussiansSource::Spz]
133                    .into_iter()
134                    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
135                    .expect("gaussians")
136            })
137            .collect::<Vec<_>>();
138
139        log::debug!("Computing gaussian centroids");
140        let mut gaussian_centroids = gaussians
141            .iter()
142            .map(|g| {
143                let mut centroid = Vec3::ZERO;
144                for gaussian in g.iter_gaussian() {
145                    centroid += gaussian.pos;
146                }
147                centroid / g.len() as f32
148            })
149            .collect::<Vec<_>>();
150
151        log::debug!("Creating camera");
152        let camera = gs::Camera::new(0.1..1e4, 60f32.to_radians());
153
154        log::debug!("Creating viewer");
155        let mut viewer =
156            gs::MultiModelViewer::new(&device, config.view_formats[0]).expect("viewer");
157
158        let quat = Quat::from_axis_angle(Vec3::Z, 180f32.to_radians());
159        for (i, gaussians) in gaussians.iter().enumerate() {
160            let offset = model_offset * i as f32;
161
162            log::debug!("Pushing model {i}");
163
164            viewer.insert_model(&device, i, gaussians);
165            viewer
166                .update_model_transform(&queue, &i, offset, quat, Vec3::ONE)
167                .expect("update model");
168
169            gaussian_centroids[i] = quat.mul_vec3(gaussian_centroids[i]) + offset;
170        }
171
172        log::info!("System initialized");
173
174        Self {
175            surface,
176            device,
177            queue,
178            config,
179
180            camera,
181            gaussians,
182            gaussian_centroids,
183            viewer,
184        }
185    }
Source

pub fn insert_model_with( &mut self, device: &Device, key: K, gaussians_buffer_usage: BufferUsages, gaussians: &impl IterGaussian, ) -> Option<MultiModelViewerModel<G>>

Insert a new model to the viewer with custom gaussians buffer usage.

This ignores MultiModelViewer::gaussians_buffer_usage, and instead uses the provided usage in the argument.

Source

pub fn remove_model(&mut self, key: &K) -> Option<MultiModelViewerModel<G>>

Remove a model from the viewer.

Source

pub fn update_camera( &mut self, queue: &Queue, camera: &impl CameraTrait, texture_size: UVec2, )

Update the camera.

Examples found in repository?
examples/multi_model.rs (lines 228-232)
187    fn update(&mut self, input: &core::Input, delta_time: f32) {
188        const SPEED: f32 = 1.0;
189
190        let mut forward = 0.0;
191        if input.held_keys.contains(&KeyCode::KeyW) {
192            forward += SPEED * delta_time;
193        }
194        if input.held_keys.contains(&KeyCode::KeyS) {
195            forward -= SPEED * delta_time;
196        }
197
198        let mut right = 0.0;
199        if input.held_keys.contains(&KeyCode::KeyD) {
200            right += SPEED * delta_time;
201        }
202        if input.held_keys.contains(&KeyCode::KeyA) {
203            right -= SPEED * delta_time;
204        }
205
206        self.camera.move_by(forward, right);
207
208        let mut up = 0.0;
209        if input.held_keys.contains(&KeyCode::Space) {
210            up += SPEED * delta_time;
211        }
212        if input.held_keys.contains(&KeyCode::ShiftLeft) {
213            up -= SPEED * delta_time;
214        }
215
216        self.camera.move_up(up);
217
218        // Camera rotation
219        const SENSITIVITY: f32 = 0.15;
220
221        let yaw = input.mouse_diff.x * SENSITIVITY * delta_time;
222        let pitch = input.mouse_diff.y * SENSITIVITY * delta_time;
223
224        self.camera.pitch_by(-pitch);
225        self.camera.yaw_by(-yaw);
226
227        // Update the viewer
228        self.viewer.update_camera(
229            &self.queue,
230            &self.camera,
231            uvec2(self.config.width, self.config.height),
232        );
233    }
Source

pub fn update_camera_with_pod(&mut self, queue: &Queue, pod: &CameraPod)

Update the camera with CameraPod.

Source

pub fn update_model_transform( &mut self, queue: &Queue, key: &K, pos: Vec3, rot: Quat, scale: Vec3, ) -> Result<(), MultiModelViewerAccessError>

Update the model transform.

Examples found in repository?
examples/multi_model.rs (line 166)
79    async fn init(window: Arc<Window>, args: &Args) -> Self {
80        let model_paths = &args.models;
81        let model_offset = Vec3::from_slice(&args.offset);
82        let size = window.inner_size();
83
84        log::debug!("Creating wgpu instance");
85        let instance =
86            wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
87
88        log::debug!("Creating window surface");
89        let surface = instance.create_surface(window.clone()).expect("surface");
90
91        log::debug!("Requesting adapter");
92        let adapter = instance
93            .request_adapter(&wgpu::RequestAdapterOptions {
94                power_preference: wgpu::PowerPreference::HighPerformance,
95                compatible_surface: Some(&surface),
96                force_fallback_adapter: false,
97            })
98            .await
99            .expect("adapter");
100
101        log::debug!("Requesting device");
102        let (device, queue) = adapter
103            .request_device(&wgpu::DeviceDescriptor {
104                label: Some("Device"),
105                required_limits: adapter.limits(),
106                ..Default::default()
107            })
108            .await
109            .expect("device");
110
111        let surface_caps = surface.get_capabilities(&adapter);
112        let surface_format = surface_caps.formats[0];
113        let config = wgpu::SurfaceConfiguration {
114            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
115            format: surface_format,
116            width: size.width.max(1),
117            height: size.height.max(1),
118            present_mode: surface_caps.present_modes[0],
119            alpha_mode: surface_caps.alpha_modes[0],
120            view_formats: vec![surface_format.remove_srgb_suffix()],
121            desired_maximum_frame_latency: 2,
122        };
123
124        log::debug!("Configuring surface");
125        surface.configure(&device, &config);
126
127        log::debug!("Creating gaussians");
128        let gaussians = model_paths
129            .iter()
130            .map(|model_path| {
131                log::debug!("Reading model from {model_path}");
132                [GaussiansSource::Ply, GaussiansSource::Spz]
133                    .into_iter()
134                    .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
135                    .expect("gaussians")
136            })
137            .collect::<Vec<_>>();
138
139        log::debug!("Computing gaussian centroids");
140        let mut gaussian_centroids = gaussians
141            .iter()
142            .map(|g| {
143                let mut centroid = Vec3::ZERO;
144                for gaussian in g.iter_gaussian() {
145                    centroid += gaussian.pos;
146                }
147                centroid / g.len() as f32
148            })
149            .collect::<Vec<_>>();
150
151        log::debug!("Creating camera");
152        let camera = gs::Camera::new(0.1..1e4, 60f32.to_radians());
153
154        log::debug!("Creating viewer");
155        let mut viewer =
156            gs::MultiModelViewer::new(&device, config.view_formats[0]).expect("viewer");
157
158        let quat = Quat::from_axis_angle(Vec3::Z, 180f32.to_radians());
159        for (i, gaussians) in gaussians.iter().enumerate() {
160            let offset = model_offset * i as f32;
161
162            log::debug!("Pushing model {i}");
163
164            viewer.insert_model(&device, i, gaussians);
165            viewer
166                .update_model_transform(&queue, &i, offset, quat, Vec3::ONE)
167                .expect("update model");
168
169            gaussian_centroids[i] = quat.mul_vec3(gaussian_centroids[i]) + offset;
170        }
171
172        log::info!("System initialized");
173
174        Self {
175            surface,
176            device,
177            queue,
178            config,
179
180            camera,
181            gaussians,
182            gaussian_centroids,
183            viewer,
184        }
185    }
Source

pub fn update_model_transform_with_pod( &mut self, queue: &Queue, key: &K, pod: &ModelTransformPod, ) -> Result<(), MultiModelViewerAccessError>

Update the model transform with ModelTransformPod.

Source

pub fn update_gaussian_transform( &mut self, queue: &Queue, size: f32, display_mode: GaussianDisplayMode, sh_deg: GaussianShDegree, no_sh0: bool, max_std_dev: GaussianMaxStdDev, )

Update the Gaussian transform.

Source

pub fn update_gaussian_transform_with_pod( &mut self, queue: &Queue, pod: &GaussianTransformPod, )

Update the Gaussian transform with GaussianTransformPod.

Source

pub fn render( &self, encoder: &mut CommandEncoder, texture_view: &TextureView, keys: &[&K], ) -> Result<(), MultiModelViewerAccessError>

Render the viewer.

Examples found in repository?
examples/multi_model.rs (lines 276-280)
235    fn render(&mut self) {
236        let texture = match self.surface.get_current_texture() {
237            wgpu::CurrentSurfaceTexture::Success(texture)
238            | wgpu::CurrentSurfaceTexture::Suboptimal(texture) => texture,
239            e => {
240                log::error!("Failed to get current texture: {e:?}");
241                return;
242            }
243        };
244        let texture_view = texture.texture.create_view(&wgpu::TextureViewDescriptor {
245            label: Some("Texture View"),
246            format: Some(self.config.view_formats[0]),
247            ..Default::default()
248        });
249
250        let mut encoder = self
251            .device
252            .create_command_encoder(&wgpu::CommandEncoderDescriptor {
253                label: Some("Command Encoder"),
254            });
255
256        let mut render_keys = self
257            .gaussian_centroids
258            .iter()
259            .enumerate()
260            .map(|(i, centroid)| (i, centroid - self.camera.pos))
261            .collect::<Vec<_>>();
262
263        render_keys.sort_by(|(_, a), (_, b)| {
264            a.length()
265                .partial_cmp(&b.length())
266                .unwrap_or(std::cmp::Ordering::Equal)
267        });
268
269        let render_keys = render_keys
270            .into_iter()
271            .rev()
272            .map(|(i, _)| i)
273            .collect::<Vec<_>>();
274
275        self.viewer
276            .render(
277                &mut encoder,
278                &texture_view,
279                render_keys.iter().collect::<Vec<_>>().as_slice(),
280            )
281            .expect("render");
282
283        self.queue.submit(std::iter::once(encoder.finish()));
284        if let Err(e) = self.device.poll(wgpu::PollType::wait_indefinitely()) {
285            log::error!("Failed to poll device: {e:?}");
286        }
287        texture.present();
288    }

Trait Implementations§

Source§

impl<G: Debug + GaussianPod, K: Debug + Hash + Eq> Debug for MultiModelViewer<G, K>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<G, K> Freeze for MultiModelViewer<G, K>

§

impl<G = GaussianPodWithShSingleCov3dSingleConfigs, K = String> !RefUnwindSafe for MultiModelViewer<G, K>

§

impl<G, K> Send for MultiModelViewer<G, K>
where K: Send,

§

impl<G, K> Sync for MultiModelViewer<G, K>
where K: Sync,

§

impl<G, K> Unpin for MultiModelViewer<G, K>
where G: Unpin, K: Unpin,

§

impl<G, K> UnsafeUnpin for MultiModelViewer<G, K>

§

impl<G = GaussianPodWithShSingleCov3dSingleConfigs, K = String> !UnwindSafe for MultiModelViewer<G, K>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,