use wgpu::util::DeviceExt;
use super::types::{
ClusterUniforms, LightData, LightGrid, MAX_LIGHTS_PER_CLUSTER, MaterialData, SkinnedObjectData,
TOTAL_CLUSTERS,
};
const INITIAL_LIGHTS: usize = 32;
const INITIAL_OBJECTS: usize = 100;
const INITIAL_MATERIALS: usize = 100;
pub(super) struct SkinnedWorldGpuBuffers {
pub materials_buffer: wgpu::Buffer,
pub materials_buffer_size: usize,
pub lights_buffer: wgpu::Buffer,
pub lights_buffer_size: usize,
pub object_buffer: wgpu::Buffer,
pub object_buffer_size: usize,
pub custom_data_buffer: wgpu::Buffer,
pub custom_data_buffer_size: usize,
pub cluster_uniforms_buffer: wgpu::Buffer,
pub light_grid_buffer: wgpu::Buffer,
pub _light_grid_reset_buffer: wgpu::Buffer,
pub light_indices_buffer: wgpu::Buffer,
pub instance_bind_group: wgpu::BindGroup,
}
impl SkinnedWorldGpuBuffers {
pub fn new(
device: &wgpu::Device,
instance_bind_group_layout: &wgpu::BindGroupLayout,
joint_matrices_buffer: &wgpu::Buffer,
morph_displacement_buffer: &wgpu::Buffer,
) -> Self {
let materials_buffer_size = INITIAL_MATERIALS;
let materials_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Mesh Materials Buffer (Per-World)"),
size: (std::mem::size_of::<MaterialData>() * materials_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let lights_buffer_size = INITIAL_LIGHTS;
let lights_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Mesh Lights Buffer (Per-World)"),
size: (std::mem::size_of::<LightData>() * lights_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let object_buffer_size = INITIAL_OBJECTS;
let object_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Mesh Object Buffer (Per-World)"),
size: (std::mem::size_of::<SkinnedObjectData>() * object_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let custom_data_buffer_size = INITIAL_OBJECTS;
let custom_data_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Mesh Custom Data Buffer (Per-World)"),
size: (std::mem::size_of::<[f32; 4]>() * custom_data_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let cluster_uniforms_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Cluster Uniforms Buffer (Per-World)"),
size: std::mem::size_of::<ClusterUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let light_grid_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Light Grid Buffer (Per-World)"),
size: (std::mem::size_of::<LightGrid>() * TOTAL_CLUSTERS as usize) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let light_grid_reset_data: Vec<LightGrid> = vec![
LightGrid {
_offset: 0,
count: 0
};
TOTAL_CLUSTERS as usize
];
let light_grid_reset_buffer =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Skinned Light Grid Reset Buffer (Per-World)"),
contents: bytemuck::cast_slice(&light_grid_reset_data),
usage: wgpu::BufferUsages::COPY_SRC,
});
let light_indices_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Skinned Light Indices Buffer (Per-World)"),
size: (std::mem::size_of::<u32>()
* TOTAL_CLUSTERS as usize
* MAX_LIGHTS_PER_CLUSTER as usize) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let instance_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Skinned Mesh Instance Bind Group (Per-World)"),
layout: instance_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: materials_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: object_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 2,
resource: lights_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 3,
resource: joint_matrices_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 4,
resource: custom_data_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 5,
resource: morph_displacement_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 7,
resource: light_grid_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 8,
resource: light_indices_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 9,
resource: cluster_uniforms_buffer.as_entire_binding(),
},
],
});
Self {
materials_buffer,
materials_buffer_size,
lights_buffer,
lights_buffer_size,
object_buffer,
object_buffer_size,
custom_data_buffer,
custom_data_buffer_size,
cluster_uniforms_buffer,
light_grid_buffer,
_light_grid_reset_buffer: light_grid_reset_buffer,
light_indices_buffer,
instance_bind_group,
}
}
}
pub(super) struct SkinnedWorldRenderState {
pub skinned_entities: Vec<crate::ecs::world::Entity>,
pub opaque_skinned_entities: Vec<crate::ecs::world::Entity>,
pub transparent_skinned_entities: Vec<crate::ecs::world::Entity>,
pub _num_directional_lights: u32,
pub _num_total_lights: u32,
pub last_used_frame: u64,
pub gpu_buffers: Option<SkinnedWorldGpuBuffers>,
pub ibl_brdf_lut_view: Option<wgpu::TextureView>,
pub ibl_irradiance_view: Option<wgpu::TextureView>,
pub ibl_prefiltered_view: Option<wgpu::TextureView>,
pub ibl_irradiance_b_view: Option<wgpu::TextureView>,
pub ibl_prefiltered_b_view: Option<wgpu::TextureView>,
pub ibl_blend_factor: f32,
}
impl SkinnedWorldRenderState {
pub fn new() -> Self {
Self {
skinned_entities: Vec::new(),
opaque_skinned_entities: Vec::new(),
transparent_skinned_entities: Vec::new(),
_num_directional_lights: 0,
_num_total_lights: 0,
last_used_frame: 0,
gpu_buffers: None,
ibl_brdf_lut_view: None,
ibl_irradiance_view: None,
ibl_prefiltered_view: None,
ibl_irradiance_b_view: None,
ibl_prefiltered_b_view: None,
ibl_blend_factor: 0.0,
}
}
}
impl Default for SkinnedWorldRenderState {
fn default() -> Self {
Self::new()
}
}