mod constructor;
mod materials;
mod mesh_registry;
mod uniforms;
use crate::ecs::skin::systems::SkinningCache;
use std::collections::{HashMap, HashSet};
use super::types::*;
use super::world_state::{SkinnedWorldGpuBuffers, SkinnedWorldRenderState};
pub struct SkinnedMeshPass {
pub(super) skinning_compute_pipeline: wgpu::ComputePipeline,
pub(super) skinning_compute_bind_group: wgpu::BindGroup,
pub(super) _skinning_compute_bind_group_layout: wgpu::BindGroupLayout,
pub(super) bone_transforms_buffer: wgpu::Buffer,
pub(super) inverse_bind_matrices_buffer: wgpu::Buffer,
pub(super) joint_matrices_buffer: wgpu::Buffer,
pub(super) skin_data_buffer: wgpu::Buffer,
pub(super) bone_transforms_buffer_size: usize,
pub(super) inverse_bind_matrices_buffer_size: usize,
pub(super) joint_matrices_buffer_size: usize,
pub(super) skin_data_buffer_size: usize,
pub(super) render_pipeline: wgpu::RenderPipeline,
pub(super) oit_render_pipeline: wgpu::RenderPipeline,
pub(super) oit_composite_pipeline: wgpu::RenderPipeline,
pub(super) oit_composite_bind_group_layout: wgpu::BindGroupLayout,
pub(super) uniform_buffer: wgpu::Buffer,
pub(super) uniform_bind_group: wgpu::BindGroup,
pub(super) instance_bind_group_layout: wgpu::BindGroupLayout,
pub(super) texture_bind_group_layout: wgpu::BindGroupLayout,
pub(super) shadow_bind_group: wgpu::BindGroup,
pub(super) shadow_bind_group_layout: wgpu::BindGroupLayout,
pub(super) shadow_sampler: wgpu::Sampler,
pub(super) spotlight_shadow_buffer: wgpu::Buffer,
pub(super) point_shadow_buffer: wgpu::Buffer,
pub(super) point_shadow_sampler: wgpu::Sampler,
pub(super) point_shadow_cubemap_view: wgpu::TextureView,
pub(super) dummy_white_view: wgpu::TextureView,
pub(super) dummy_black_view: wgpu::TextureView,
pub(super) dummy_normal_view: wgpu::TextureView,
pub(super) dummy_cube_view: wgpu::TextureView,
pub(super) dummy_sampler: wgpu::Sampler,
pub(super) brdf_lut_view: Option<wgpu::TextureView>,
pub(super) irradiance_map_view: Option<wgpu::TextureView>,
pub(super) prefiltered_env_view: Option<wgpu::TextureView>,
pub(super) irradiance_b_view: Option<wgpu::TextureView>,
pub(super) prefiltered_b_view: Option<wgpu::TextureView>,
pub(super) ibl_sampler: wgpu::Sampler,
pub(super) skinned_vertex_buffer: wgpu::Buffer,
pub(super) skinned_index_buffer: wgpu::Buffer,
pub(super) skinned_vertex_buffer_size: u64,
pub(super) skinned_index_buffer_size: u64,
pub(super) skinned_meshes: HashMap<String, u32>,
pub(super) skinned_mesh_data: Vec<SkinnedMeshData>,
pub(super) current_skinned_vertex_offset: u32,
pub(super) current_skinned_index_offset: u32,
pub(super) morph_displacement_buffer: wgpu::Buffer,
pub(super) morph_displacement_buffer_size: usize,
pub(super) current_morph_displacement_offset: u32,
pub(super) total_joints_to_dispatch: u32,
pub(super) material_bind_groups: HashMap<u32, wgpu::BindGroup>,
pub(super) material_bind_group_cache_key: HashMap<u32, MaterialTextures>,
pub(super) registered_textures: HashMap<String, (wgpu::TextureView, wgpu::Sampler)>,
pub(super) skinning_cache: SkinningCache,
pub(super) oit_accum_texture: wgpu::Texture,
pub(super) oit_accum_view: wgpu::TextureView,
pub(super) oit_reveal_texture: wgpu::Texture,
pub(super) oit_reveal_view: wgpu::TextureView,
pub(super) oit_sampler: wgpu::Sampler,
pub(super) oit_texture_size: (u32, u32),
pub(super) _cluster_bounds_buffer: wgpu::Buffer,
pub(super) _view_matrix_buffer: wgpu::Buffer,
pub(super) _cluster_bounds_pipeline: wgpu::ComputePipeline,
pub(super) _cluster_assign_pipeline: wgpu::ComputePipeline,
pub(super) _cluster_bounds_bind_group: wgpu::BindGroup,
pub(super) _cluster_assign_bind_group_layout: wgpu::BindGroupLayout,
pub(super) _cluster_assign_bind_group: Option<wgpu::BindGroup>,
pub(super) _last_camera_hash: u64,
pub(super) _camera_changed: bool,
pub(super) _num_directional_lights: u32,
pub(super) current_world_id: u64,
pub(super) world_states: HashMap<u64, SkinnedWorldRenderState>,
pub(super) frame_counter: u64,
pub(crate) dirty_skinned_mesh_names: HashSet<String>,
}
fn create_skinned_shader_module(
device: &wgpu::Device,
label: &str,
source: &str,
) -> wgpu::ShaderModule {
#[cfg(target_arch = "wasm32")]
let source = strip_specular_color_texture_skinned(source);
device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some(label),
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::from(source)),
})
}
#[cfg(target_arch = "wasm32")]
fn strip_specular_color_texture_skinned(source: &str) -> String {
let mut result = String::with_capacity(source.len());
let mut lines = source.lines().peekable();
while let Some(line) = lines.next() {
let trimmed = line.trim();
if trimmed == "@group(2) @binding(16)" || trimmed == "@group(2) @binding(17)" {
lines.next();
continue;
}
if trimmed.starts_with("if material.has_specular_color_texture") {
for inner in lines.by_ref() {
if inner.trim() == "}" {
break;
}
}
continue;
}
result.push_str(line);
result.push('\n');
}
result
}
fn skinned_texture_bind_group_layout_entries() -> Vec<wgpu::BindGroupLayoutEntry> {
let texture_entry = |binding: u32| wgpu::BindGroupLayoutEntry {
binding,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
};
let sampler_entry = |binding: u32| wgpu::BindGroupLayoutEntry {
binding,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
};
#[allow(unused_mut)]
let mut entries = vec![
texture_entry(0),
sampler_entry(1),
texture_entry(2),
sampler_entry(3),
texture_entry(4),
sampler_entry(5),
texture_entry(6),
sampler_entry(7),
texture_entry(8),
sampler_entry(9),
texture_entry(10),
sampler_entry(11),
texture_entry(12),
sampler_entry(13),
texture_entry(14),
sampler_entry(15),
];
#[cfg(not(target_arch = "wasm32"))]
{
entries.push(texture_entry(16));
entries.push(sampler_entry(17));
}
entries
}
impl SkinnedMeshPass {
pub fn set_current_world(&mut self, world_id: u64) {
self.current_world_id = world_id;
self.world_states.entry(world_id).or_default();
}
pub(super) fn state(&self) -> &SkinnedWorldRenderState {
self.world_states.get(&self.current_world_id).unwrap()
}
pub(super) fn state_mut(&mut self) -> &mut SkinnedWorldRenderState {
self.world_states.get_mut(&self.current_world_id).unwrap()
}
pub(super) fn gpu(&self) -> &SkinnedWorldGpuBuffers {
self.state().gpu_buffers.as_ref().unwrap()
}
pub(super) fn ensure_world_gpu_buffers(&mut self, device: &wgpu::Device) {
let world_state = self.world_states.get_mut(&self.current_world_id).unwrap();
if world_state.gpu_buffers.is_none() {
world_state.gpu_buffers = Some(SkinnedWorldGpuBuffers::new(
device,
&self.instance_bind_group_layout,
&self.joint_matrices_buffer,
&self.morph_displacement_buffer,
));
}
}
}