use super::super::pass::SkinnedMeshPass;
use crate::render::wgpu::rendergraph::PassExecutionContext;
impl SkinnedMeshPass {
pub(in super::super) fn execute_pass_node<'r, 'e>(
&mut self,
context: PassExecutionContext<'r, 'e, crate::ecs::world::World>,
) -> crate::render::wgpu::rendergraph::Result<
Vec<crate::render::wgpu::rendergraph::SubGraphRunCommand<'r>>,
> {
if self.state().skinned_entities.is_empty() {
return Ok(vec![]);
}
if self.total_joints_to_dispatch > 0 {
let mut compute_pass =
context
.encoder
.begin_compute_pass(&wgpu::ComputePassDescriptor {
label: Some("Skinning Compute Pass"),
timestamp_writes: None,
});
compute_pass.set_pipeline(&self.skinning_compute_pipeline);
compute_pass.set_bind_group(0, &self.skinning_compute_bind_group, &[]);
let num_workgroups = self.total_joints_to_dispatch.div_ceil(64);
compute_pass.dispatch_workgroups(num_workgroups, 1, 1);
}
let (color_view, color_load, color_store) = context.get_color_attachment("color")?;
let (depth_view, depth_load, depth_store) = context.get_depth_attachment("depth")?;
let (shadow_depth_view, _, _) = context.get_depth_attachment("shadow_depth")?;
let (spotlight_shadow_atlas_view, _, _) =
context.get_depth_attachment("spotlight_shadow_atlas")?;
let world_state = self.state();
let brdf_view = world_state
.ibl_brdf_lut_view
.as_ref()
.or(self.brdf_lut_view.as_ref())
.unwrap_or(&self.dummy_white_view);
let irradiance_view = world_state
.ibl_irradiance_view
.as_ref()
.or(self.irradiance_map_view.as_ref())
.unwrap_or(&self.dummy_cube_view);
let prefiltered_view = world_state
.ibl_prefiltered_view
.as_ref()
.or(self.prefiltered_env_view.as_ref())
.unwrap_or(&self.dummy_cube_view);
let irradiance_b_view = world_state
.ibl_irradiance_b_view
.as_ref()
.or(self.irradiance_b_view.as_ref())
.unwrap_or(&self.dummy_cube_view);
let prefiltered_b_view = world_state
.ibl_prefiltered_b_view
.as_ref()
.or(self.prefiltered_b_view.as_ref())
.unwrap_or(&self.dummy_cube_view);
self.shadow_bind_group = context
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Skinned Mesh Shadow Bind Group"),
layout: &self.shadow_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(shadow_depth_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&self.shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(spotlight_shadow_atlas_view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::Sampler(&self.shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 4,
resource: self.spotlight_shadow_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 5,
resource: wgpu::BindingResource::TextureView(brdf_view),
},
wgpu::BindGroupEntry {
binding: 6,
resource: wgpu::BindingResource::Sampler(&self.ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::TextureView(irradiance_view),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::Sampler(&self.ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 9,
resource: wgpu::BindingResource::TextureView(prefiltered_view),
},
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::Sampler(&self.ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::TextureView(
&self.point_shadow_cubemap_view,
),
},
wgpu::BindGroupEntry {
binding: 12,
resource: wgpu::BindingResource::Sampler(&self.point_shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 13,
resource: self.point_shadow_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 14,
resource: wgpu::BindingResource::TextureView(irradiance_b_view),
},
wgpu::BindGroupEntry {
binding: 15,
resource: wgpu::BindingResource::TextureView(prefiltered_b_view),
},
],
});
let default_bind_group = context
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Skinned Mesh Default Texture Bind Group"),
layout: &self.texture_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&self.dummy_white_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(&self.dummy_black_view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 4,
resource: wgpu::BindingResource::TextureView(&self.dummy_normal_view),
},
wgpu::BindGroupEntry {
binding: 5,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 6,
resource: wgpu::BindingResource::TextureView(&self.dummy_white_view),
},
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::TextureView(&self.dummy_white_view),
},
wgpu::BindGroupEntry {
binding: 9,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::TextureView(&self.dummy_white_view),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 12,
resource: wgpu::BindingResource::TextureView(&self.dummy_white_view),
},
wgpu::BindGroupEntry {
binding: 13,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
wgpu::BindGroupEntry {
binding: 14,
resource: wgpu::BindingResource::TextureView(&self.dummy_white_view),
},
wgpu::BindGroupEntry {
binding: 15,
resource: wgpu::BindingResource::Sampler(&self.dummy_sampler),
},
],
});
let entity_to_instance: std::collections::HashMap<crate::ecs::world::Entity, u32> = self
.state()
.skinned_entities
.iter()
.enumerate()
.map(|(index, &entity)| (entity, index as u32))
.collect();
if !self.state().opaque_skinned_entities.is_empty() {
let mut render_pass = context
.encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Skinned Mesh Opaque Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: color_view,
resolve_target: None,
ops: wgpu::Operations {
load: color_load,
store: color_store,
},
depth_slice: None,
})],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: depth_view,
depth_ops: Some(wgpu::Operations {
load: depth_load,
store: depth_store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, &self.uniform_bind_group, &[]);
render_pass.set_bind_group(1, &self.gpu().instance_bind_group, &[]);
render_pass.set_bind_group(3, &self.shadow_bind_group, &[]);
render_pass.set_vertex_buffer(0, self.skinned_vertex_buffer.slice(..));
render_pass.set_index_buffer(
self.skinned_index_buffer.slice(..),
wgpu::IndexFormat::Uint32,
);
let opaque_skinned_entities: Vec<_> = self.state().opaque_skinned_entities.clone();
for &entity in &opaque_skinned_entities {
let instance_index = entity_to_instance[&entity];
let mesh_name = context
.configs
.core
.get_render_mesh(entity)
.map(|rm| rm.name.as_str());
if let Some(name) = mesh_name
&& let Some(&mesh_id) = self.skinned_meshes.get(name)
{
let mesh_data = &self.skinned_mesh_data[mesh_id as usize];
if mesh_data.index_count > 0 {
let material_id = instance_index;
if let Some(bind_group) = self.material_bind_groups.get(&material_id) {
render_pass.set_bind_group(2, bind_group, &[]);
} else {
render_pass.set_bind_group(2, &default_bind_group, &[]);
}
render_pass.draw_indexed(
mesh_data.index_offset
..(mesh_data.index_offset + mesh_data.index_count),
mesh_data.vertex_offset as i32,
instance_index..(instance_index + 1),
);
}
}
}
drop(render_pass);
}
if !self.state().transparent_skinned_entities.is_empty() {
let (width, height) = context.get_texture_size("color")?;
self.resize_oit_textures(context.device, width, height);
{
let mut oit_pass = context
.encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Skinned Mesh OIT Pass"),
color_attachments: &[
Some(wgpu::RenderPassColorAttachment {
view: &self.oit_accum_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 0.0,
}),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
}),
Some(wgpu::RenderPassColorAttachment {
view: &self.oit_reveal_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 1.0,
g: 0.0,
b: 0.0,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
}),
],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: depth_view,
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
}),
stencil_ops: None,
}),
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
oit_pass.set_pipeline(&self.oit_render_pipeline);
oit_pass.set_bind_group(0, &self.uniform_bind_group, &[]);
oit_pass.set_bind_group(1, &self.gpu().instance_bind_group, &[]);
oit_pass.set_bind_group(3, &self.shadow_bind_group, &[]);
oit_pass.set_vertex_buffer(0, self.skinned_vertex_buffer.slice(..));
oit_pass.set_index_buffer(
self.skinned_index_buffer.slice(..),
wgpu::IndexFormat::Uint32,
);
let transparent_skinned_entities: Vec<_> =
self.state().transparent_skinned_entities.clone();
for &entity in &transparent_skinned_entities {
let instance_index = entity_to_instance[&entity];
let mesh_name = context
.configs
.core
.get_render_mesh(entity)
.map(|rm| rm.name.as_str());
if let Some(name) = mesh_name
&& let Some(&mesh_id) = self.skinned_meshes.get(name)
{
let mesh_data = &self.skinned_mesh_data[mesh_id as usize];
if mesh_data.index_count > 0 {
let material_id = instance_index;
if let Some(bind_group) = self.material_bind_groups.get(&material_id) {
oit_pass.set_bind_group(2, bind_group, &[]);
} else {
oit_pass.set_bind_group(2, &default_bind_group, &[]);
}
oit_pass.draw_indexed(
mesh_data.index_offset
..(mesh_data.index_offset + mesh_data.index_count),
mesh_data.vertex_offset as i32,
instance_index..(instance_index + 1),
);
}
}
}
}
let oit_composite_bind_group =
context
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Skinned Mesh OIT Composite Bind Group"),
layout: &self.oit_composite_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&self.oit_accum_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&self.oit_sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(&self.oit_reveal_view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::Sampler(&self.oit_sampler),
},
],
});
let mut composite_pass =
context
.encoder
.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Skinned Mesh OIT Composite Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: color_view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
composite_pass.set_pipeline(&self.oit_composite_pipeline);
composite_pass.set_bind_group(0, &oit_composite_bind_group, &[]);
composite_pass.draw(0..3, 0..1);
}
Ok(vec![])
}
}