use glam::{Vec3, Vec4};
use wgpu::util::DeviceExt;
pub struct PointCloudRenderData {
pub position_buffer: wgpu::Buffer,
pub color_buffer: wgpu::Buffer,
pub uniform_buffer: wgpu::Buffer,
pub bind_group: wgpu::BindGroup,
pub num_points: u32,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
#[allow(clippy::pub_underscore_fields)]
pub struct PointUniforms {
pub model_matrix: [[f32; 4]; 4],
pub point_radius: f32,
pub use_per_point_color: u32,
pub _padding: [f32; 2],
pub base_color: [f32; 4],
}
impl Default for PointUniforms {
fn default() -> Self {
Self {
model_matrix: [
[1.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 1.0],
],
point_radius: 0.01,
use_per_point_color: 0,
_padding: [0.0; 2],
base_color: [0.2, 0.5, 0.8, 1.0], }
}
}
impl PointCloudRenderData {
#[must_use]
pub fn new(
device: &wgpu::Device,
bind_group_layout: &wgpu::BindGroupLayout,
camera_buffer: &wgpu::Buffer,
positions: &[Vec3],
colors: Option<&[Vec4]>,
) -> Self {
let num_points = positions.len() as u32;
let position_data: Vec<f32> = positions
.iter()
.flat_map(|p| [p.x, p.y, p.z, 0.0]) .collect();
let position_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("point positions"),
contents: bytemuck::cast_slice(&position_data),
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
});
let color_data: Vec<f32> = if let Some(colors) = colors {
colors.iter().flat_map(glam::Vec4::to_array).collect()
} else {
vec![1.0; positions.len() * 4]
};
let color_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("point colors"),
contents: bytemuck::cast_slice(&color_data),
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
});
let uniforms = PointUniforms::default();
let uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("point uniforms"),
contents: bytemuck::cast_slice(&[uniforms]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("point cloud bind group"),
layout: bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: camera_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: uniform_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 2,
resource: position_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 3,
resource: color_buffer.as_entire_binding(),
},
],
});
Self {
position_buffer,
color_buffer,
uniform_buffer,
bind_group,
num_points,
}
}
pub fn update_colors(&self, queue: &wgpu::Queue, colors: &[Vec4]) {
let color_data: Vec<f32> = colors.iter().flat_map(glam::Vec4::to_array).collect();
queue.write_buffer(&self.color_buffer, 0, bytemuck::cast_slice(&color_data));
}
pub fn update_uniforms(&self, queue: &wgpu::Queue, uniforms: &PointUniforms) {
queue.write_buffer(&self.uniform_buffer, 0, bytemuck::cast_slice(&[*uniforms]));
}
}