use crate::ecs::mesh::components::{
Vertex, create_cone_mesh, create_cube_mesh, create_cylinder_mesh, create_plane_mesh,
create_sphere_mesh, create_subdivided_plane_mesh, create_torus_mesh,
};
use crate::render::wgpu::passes::geometry::HizPass;
use std::collections::{HashMap, HashSet};
use super::super::types::{
ClusterBounds, CullingUniforms, INITIAL_INDEX_BUFFER_SIZE, INITIAL_VERTEX_BUFFER_SIZE,
InstancedTransformComputeUniforms, MAX_POINT_LIGHT_SHADOWS, MAX_SPOTLIGHT_SHADOWS,
MeshBoundsAABB, MeshBoundsData, MeshLodInfo, MeshUniforms, MorphDisplacement,
PointLightShadowData, TOTAL_CLUSTERS,
};
use super::{MeshPass, texture_bind_group_layout_entries};
impl MeshPass {
pub fn new(
device: &wgpu::Device,
queue: &wgpu::Queue,
color_format: wgpu::TextureFormat,
depth_format: wgpu::TextureFormat,
window_size: (u32, u32),
) -> Self {
let shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"mesh.wgsl",
include_str!("../../../../shaders/mesh.wgsl"),
);
let oit_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"mesh_oit.wgsl",
include_str!("../../../../shaders/mesh_oit.wgsl"),
);
let composite_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"oit_composite.wgsl",
include_str!("../../../../shaders/oit_composite.wgsl"),
);
let depth_prepass_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"mesh_depth_prepass.wgsl",
include_str!("../../../../shaders/mesh_depth_prepass.wgsl"),
);
let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Uniform Buffer"),
size: std::mem::size_of::<MeshUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let uniform_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Mesh Uniform Bind Group Layout"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
});
let uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Mesh Uniform Bind Group"),
layout: &uniform_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: uniform_buffer.as_entire_binding(),
}],
});
let overlay_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Overlay Uniform Buffer"),
size: std::mem::size_of::<MeshUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let overlay_uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Mesh Overlay Uniform Bind Group"),
layout: &uniform_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: overlay_uniform_buffer.as_entire_binding(),
}],
});
let morph_displacement_buffer_size =
(std::mem::size_of::<MorphDisplacement>() * 1000) as u64;
let morph_displacement_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Morph Displacement Buffer"),
size: morph_displacement_buffer_size,
usage: wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
let cluster_bounds_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Cluster Bounds Buffer"),
size: (std::mem::size_of::<ClusterBounds>() * TOTAL_CLUSTERS as usize) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let view_matrix_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("View Matrix Buffer"),
size: std::mem::size_of::<[[f32; 4]; 4]>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let instance_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Mesh Instance Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 7,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 8,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 9,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let oit_accum_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("OIT Accumulation Texture"),
size: wgpu::Extent3d {
width: window_size.0,
height: window_size.1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba16Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let oit_reveal_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("OIT Reveal Texture"),
size: wgpu::Extent3d {
width: window_size.0,
height: window_size.1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R8Unorm,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let oit_accum_view = oit_accum_texture.create_view(&wgpu::TextureViewDescriptor::default());
let oit_reveal_view =
oit_reveal_texture.create_view(&wgpu::TextureViewDescriptor::default());
let transmission_color_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Mesh Transmission Color Texture"),
size: wgpu::Extent3d {
width: window_size.0,
height: window_size.1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba16Float,
usage: wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let transmission_color_view =
transmission_color_texture.create_view(&wgpu::TextureViewDescriptor::default());
let transmission_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("Mesh Transmission Sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default()
});
let overlay_depth_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Overlay Depth Texture"),
size: wgpu::Extent3d {
width: window_size.0,
height: window_size.1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: depth_format,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let overlay_depth_view =
overlay_depth_texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("OIT Sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default()
});
let texture_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Mesh Texture Bind Group Layout"),
entries: &texture_bind_group_layout_entries(),
});
let dummy_shadow_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Dummy Shadow Texture"),
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
});
let dummy_shadow_view =
dummy_shadow_texture.create_view(&wgpu::TextureViewDescriptor::default());
let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("Shadow Sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default()
});
let spotlight_shadow_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Spotlight Shadow Buffer"),
size: (std::mem::size_of::<crate::render::wgpu::passes::SpotlightShadowData>()
* MAX_SPOTLIGHT_SHADOWS) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let point_shadow_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Point Light Shadow Buffer"),
size: (std::mem::size_of::<PointLightShadowData>() * MAX_POINT_LIGHT_SHADOWS) as u64,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let point_shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("Point Shadow Sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
mipmap_filter: wgpu::MipmapFilterMode::Nearest,
..Default::default()
});
let scene_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Scene Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Depth,
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Depth,
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 7,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 8,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 9,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 10,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 11,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: false },
view_dimension: wgpu::TextureViewDimension::CubeArray,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 12,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 13,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 14,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 15,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 16,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 17,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let ibl_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("IBL Sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::MipmapFilterMode::Linear,
..Default::default()
});
let dummy_brdf_lut = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Dummy BRDF LUT"),
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba16Float,
usage: wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let dummy_brdf_lut_view =
dummy_brdf_lut.create_view(&wgpu::TextureViewDescriptor::default());
let dummy_cubemap = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Dummy IBL Cubemap"),
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 6,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba16Float,
usage: wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let dummy_cubemap_view = dummy_cubemap.create_view(&wgpu::TextureViewDescriptor {
dimension: Some(wgpu::TextureViewDimension::Cube),
..Default::default()
});
let dummy_point_shadow_cubemap = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Dummy Point Shadow Cubemap Array"),
size: wgpu::Extent3d {
width: 1,
height: 1,
depth_or_array_layers: 6 * MAX_POINT_LIGHT_SHADOWS as u32,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::R32Float,
usage: wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let dummy_point_shadow_view =
dummy_point_shadow_cubemap.create_view(&wgpu::TextureViewDescriptor {
dimension: Some(wgpu::TextureViewDimension::CubeArray),
..Default::default()
});
let scene_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Scene Bind Group"),
layout: &scene_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&dummy_shadow_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(&dummy_shadow_view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::Sampler(&shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 4,
resource: spotlight_shadow_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 5,
resource: wgpu::BindingResource::TextureView(&dummy_brdf_lut_view),
},
wgpu::BindGroupEntry {
binding: 6,
resource: wgpu::BindingResource::Sampler(&ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::TextureView(&dummy_cubemap_view),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::Sampler(&ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 9,
resource: wgpu::BindingResource::TextureView(&dummy_cubemap_view),
},
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::Sampler(&ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::TextureView(&dummy_point_shadow_view),
},
wgpu::BindGroupEntry {
binding: 12,
resource: wgpu::BindingResource::Sampler(&point_shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 13,
resource: point_shadow_buffer.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 14,
resource: wgpu::BindingResource::TextureView(&dummy_cubemap_view),
},
wgpu::BindGroupEntry {
binding: 15,
resource: wgpu::BindingResource::TextureView(&dummy_cubemap_view),
},
wgpu::BindGroupEntry {
binding: 16,
resource: wgpu::BindingResource::TextureView(&transmission_color_view),
},
wgpu::BindGroupEntry {
binding: 17,
resource: wgpu::BindingResource::Sampler(&transmission_sampler),
},
],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Mesh Pipeline Layout"),
bind_group_layouts: &[
Some(&uniform_bind_group_layout),
Some(&instance_bind_group_layout),
Some(&texture_bind_group_layout),
Some(&scene_bind_group_layout),
],
immediate_size: 0,
});
let depth_prepass_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Depth Prepass Pipeline Layout"),
bind_group_layouts: &[
Some(&uniform_bind_group_layout),
Some(&instance_bind_group_layout),
],
immediate_size: 0,
});
let vertex_attributes = [
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: 12,
shader_location: 1,
format: wgpu::VertexFormat::Float32x3,
},
wgpu::VertexAttribute {
offset: 24,
shader_location: 2,
format: wgpu::VertexFormat::Float32x2,
},
wgpu::VertexAttribute {
offset: 32,
shader_location: 3,
format: wgpu::VertexFormat::Float32x2,
},
wgpu::VertexAttribute {
offset: 40,
shader_location: 4,
format: wgpu::VertexFormat::Float32x4,
},
wgpu::VertexAttribute {
offset: 56,
shader_location: 5,
format: wgpu::VertexFormat::Float32x4,
},
];
let vertex_buffer_layout = wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &vertex_attributes,
};
let opaque_targets: Vec<Option<wgpu::ColorTargetState>> = vec![
Some(wgpu::ColorTargetState {
format: color_format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
}),
Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::R32Float,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
}),
Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Rgba16Float,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
}),
];
let opaque_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Opaque Mesh Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: std::slice::from_ref(&vertex_buffer_layout),
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &opaque_targets,
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::GreaterEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let opaque_double_sided_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Opaque Double-Sided Mesh Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: std::slice::from_ref(&vertex_buffer_layout),
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &opaque_targets,
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::GreaterEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let overlay_opaque_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Overlay Opaque Mesh Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[vertex_buffer_layout],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &opaque_targets,
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Greater),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let vertex_buffer_layout2 = wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &vertex_attributes,
};
let overlay_opaque_double_sided_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Overlay Opaque Double-Sided Mesh Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: std::slice::from_ref(&vertex_buffer_layout2),
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &opaque_targets,
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Greater),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let depth_prepass_vertex_buffer_layout = wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &vertex_attributes,
};
let depth_prepass_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Depth Prepass Pipeline"),
layout: Some(&depth_prepass_pipeline_layout),
vertex: wgpu::VertexState {
module: &depth_prepass_shader,
entry_point: Some("vs_main"),
buffers: std::slice::from_ref(&depth_prepass_vertex_buffer_layout),
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &depth_prepass_shader,
entry_point: Some("fs_main"),
targets: &[],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Greater),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let oit_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("OIT Mesh Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &oit_shader,
entry_point: Some("vs_main"),
buffers: &[wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &vertex_attributes,
}],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &oit_shader,
entry_point: Some("fs_main"),
targets: &[
Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Rgba16Float,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::One,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL,
}),
Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::R8Unorm,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::Zero,
dst_factor: wgpu::BlendFactor::Src,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::Zero,
dst_factor: wgpu::BlendFactor::Src,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL,
}),
Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::R32Float,
blend: None,
write_mask: wgpu::ColorWrites::RED,
}),
],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(false),
depth_compare: Some(wgpu::CompareFunction::GreaterEqual),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let blend_opaque_depth_prepass_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Blend Opaque Depth Prepass Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &oit_shader,
entry_point: Some("vs_main"),
buffers: &[wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &vertex_attributes,
}],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &oit_shader,
entry_point: Some("fs_blend_opaque_prepass"),
targets: &[],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: depth_format,
depth_write_enabled: Some(true),
depth_compare: Some(wgpu::CompareFunction::Greater),
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let composite_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("OIT Composite Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let oit_composite_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("OIT Composite Bind Group"),
layout: &composite_bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&oit_accum_view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(&oit_reveal_view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::Sampler(&sampler),
},
],
});
let composite_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("OIT Composite Pipeline Layout"),
bind_group_layouts: &[Some(&composite_bind_group_layout)],
immediate_size: 0,
});
let oit_composite_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("OIT Composite Pipeline"),
layout: Some(&composite_pipeline_layout),
vertex: wgpu::VertexState {
module: &composite_shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &composite_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: color_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: Default::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
conservative: false,
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Vertex Buffer"),
size: (std::mem::size_of::<Vertex>() * INITIAL_VERTEX_BUFFER_SIZE) as u64,
usage: wgpu::BufferUsages::VERTEX
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
let index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Index Buffer"),
size: (std::mem::size_of::<u32>() * INITIAL_INDEX_BUFFER_SIZE) as u64,
usage: wgpu::BufferUsages::INDEX
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
let vertex_buffer_size =
(std::mem::size_of::<Vertex>() * INITIAL_VERTEX_BUFFER_SIZE) as u64;
let index_buffer_size = (std::mem::size_of::<u32>() * INITIAL_INDEX_BUFFER_SIZE) as u64;
let culling_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"Mesh Culling Shader",
include_str!("../../../../shaders/mesh_culling.wgsl"),
);
let culling_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Mesh Culling Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: false },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 7,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 8,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let culling_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Mesh Culling Pipeline Layout"),
bind_group_layouts: &[Some(&culling_bind_group_layout)],
immediate_size: 0,
});
let culling_pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Mesh Culling Pipeline"),
layout: Some(&culling_pipeline_layout),
module: &culling_shader,
entry_point: Some("main"),
compilation_options: Default::default(),
cache: None,
});
let culling_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Culling Uniform Buffer"),
size: std::mem::size_of::<CullingUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let mesh_bounds_buffer_size = 64;
let mesh_bounds_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh Bounds Buffer"),
size: (std::mem::size_of::<MeshBoundsData>() * mesh_bounds_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
let mesh_aabbs_buffer_size = 64;
let mesh_aabbs_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh AABBs Buffer"),
size: (std::mem::size_of::<MeshBoundsAABB>() * mesh_aabbs_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
let mesh_lod_buffer_size = 64;
let mesh_lod_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Mesh LOD Buffer"),
size: (std::mem::size_of::<MeshLodInfo>() * mesh_lod_buffer_size) as u64,
usage: wgpu::BufferUsages::STORAGE
| wgpu::BufferUsages::COPY_DST
| wgpu::BufferUsages::COPY_SRC,
mapped_at_creation: false,
});
let hiz_pass = HizPass::new(device);
let phase1_culling_uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Phase 1 Culling Uniform Buffer"),
size: std::mem::size_of::<CullingUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let cluster_bounds_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"Cluster Bounds Shader",
include_str!("../../../../shaders/cluster_bounds.wgsl"),
);
let cluster_assign_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"Cluster Light Assign Shader",
include_str!("../../../../shaders/cluster_light_assign.wgsl"),
);
let cluster_bounds_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Cluster Bounds Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let cluster_bounds_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Cluster Bounds Pipeline Layout"),
bind_group_layouts: &[Some(&cluster_bounds_bind_group_layout)],
immediate_size: 0,
});
let cluster_bounds_pipeline =
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Cluster Bounds Pipeline"),
layout: Some(&cluster_bounds_pipeline_layout),
module: &cluster_bounds_shader,
entry_point: Some("main"),
compilation_options: Default::default(),
cache: None,
});
let cluster_assign_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Cluster Light Assign Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 4,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let cluster_assign_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Cluster Light Assign Pipeline Layout"),
bind_group_layouts: &[Some(&cluster_assign_bind_group_layout)],
immediate_size: 0,
});
let cluster_assign_pipeline =
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Cluster Light Assign Pipeline"),
layout: Some(&cluster_assign_pipeline_layout),
module: &cluster_assign_shader,
entry_point: Some("main"),
compilation_options: Default::default(),
cache: None,
});
let instanced_compute_shader = crate::render::wgpu::shader_compose::compile_wgsl(
device,
"Instanced Transform Compute Shader",
include_str!("../../../../shaders/instanced_transform_compute.wgsl"),
);
let instanced_compute_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Instanced Transform Compute Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: false },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::COMPUTE,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let instanced_compute_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Instanced Transform Compute Pipeline Layout"),
bind_group_layouts: &[Some(&instanced_compute_bind_group_layout)],
immediate_size: 0,
});
let instanced_compute_pipeline =
device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor {
label: Some("Instanced Transform Compute Pipeline"),
layout: Some(&instanced_compute_pipeline_layout),
module: &instanced_compute_shader,
entry_point: Some("main"),
compilation_options: Default::default(),
cache: None,
});
let instanced_compute_uniforms_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Instanced Transform Compute Uniforms Buffer"),
size: std::mem::size_of::<InstancedTransformComputeUniforms>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let instanced_compute_staging_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Instanced Transform Compute Staging Buffer"),
size: std::mem::size_of::<InstancedTransformComputeUniforms>() as u64,
usage: wgpu::BufferUsages::COPY_SRC | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let mut pass = Self {
opaque_pipeline,
opaque_double_sided_pipeline,
overlay_opaque_pipeline,
overlay_opaque_double_sided_pipeline,
oit_pipeline,
oit_composite_pipeline,
oit_accum_texture,
oit_accum_view,
oit_reveal_texture,
oit_reveal_view,
oit_composite_bind_group,
oit_composite_bind_group_layout: composite_bind_group_layout,
oit_sampler: sampler,
overlay_depth_texture,
overlay_depth_view,
oit_texture_size: window_size,
oit_resource_cache: Vec::new(),
transmission_color_texture,
transmission_color_view,
transmission_sampler,
transmission_size: window_size,
uniform_buffer,
uniform_bind_group,
overlay_uniform_buffer,
overlay_uniform_bind_group,
instance_bind_group_layout,
texture_bind_group_layout,
scene_bind_group,
scene_bind_group_layout: scene_bind_group_layout.clone(),
shadow_sampler,
spotlight_shadow_buffer,
point_shadow_buffer,
point_shadow_sampler,
ibl_sampler,
vertex_buffer,
index_buffer,
vertex_buffer_size,
index_buffer_size,
meshes: HashMap::new(),
mesh_data: Vec::new(),
mesh_names: Vec::new(),
registered_textures: HashMap::new(),
material_array_srgb_view: None,
material_array_linear_view: None,
material_array_sampler: None,
material_bind_group: None,
material_layer_map: HashMap::new(),
current_vertex_offset: 0,
current_index_offset: 0,
compaction_frame_counter: 0,
last_vertex_utilization: 1.0,
last_index_utilization: 1.0,
culling_pipeline,
culling_bind_group_layout,
culling_uniform_buffer,
mesh_bounds_buffer,
mesh_bounds_buffer_size,
mesh_bounds_data: Vec::new(),
mesh_aabbs_buffer,
mesh_aabbs_buffer_size,
mesh_aabbs_data: Vec::new(),
mesh_lod_buffer,
mesh_lod_buffer_size,
mesh_lod_data: Vec::new(),
mesh_lod_mesh_ids: Vec::new(),
hiz_pass,
depth_prepass_pipeline,
blend_opaque_depth_prepass_pipeline,
phase1_culling_uniform_buffer,
morph_displacement_buffer,
morph_displacement_buffer_size,
current_morph_displacement_offset: 0,
brdf_lut_view: dummy_brdf_lut_view,
irradiance_view: dummy_cubemap_view.clone(),
prefiltered_view: dummy_cubemap_view.clone(),
irradiance_b_view: dummy_cubemap_view.clone(),
prefiltered_b_view: dummy_cubemap_view,
point_shadow_cubemap_view: dummy_point_shadow_view,
last_prepared_world_id: None,
current_world_id: 0,
world_states: Vec::new(),
frame_counter: 0,
resize_full_rebuild_pending: false,
cluster_bounds_buffer,
cluster_bounds_pipeline,
cluster_assign_pipeline,
_cluster_bounds_bind_group_layout: cluster_bounds_bind_group_layout,
cluster_assign_bind_group_layout,
view_matrix_buffer,
instanced_compute_pipeline,
instanced_compute_bind_group_layout,
instanced_compute_uniforms_buffer,
instanced_compute_staging_buffer,
scene_bind_group_dirty: true,
scratch_indirect_commands: Vec::new(),
scratch_indirect_reset_commands: Vec::new(),
scratch_visible_indices: Vec::new(),
scratch_mesh_updates: Vec::new(),
frame_dirty: None,
dirty_mesh_ids: HashSet::new(),
per_frame_cache: super::PerFrameMeshCache::default(),
};
pass.add_mesh(device, queue, "Cube", create_cube_mesh());
pass.add_mesh(device, queue, "Sphere", create_sphere_mesh(1.0, 16));
pass.add_mesh(device, queue, "Sphere_LOD1", create_sphere_mesh(1.0, 8));
pass.add_mesh(device, queue, "Sphere_LOD2", create_sphere_mesh(1.0, 4));
pass.add_mesh(device, queue, "Plane", create_plane_mesh(2.0));
pass.add_mesh(
device,
queue,
"SubdividedPlane",
create_subdivided_plane_mesh(2.0, 20),
);
pass.add_mesh(
device,
queue,
"Cylinder",
create_cylinder_mesh(0.5, 1.0, 16),
);
pass.add_mesh(device, queue, "Cone", create_cone_mesh(0.5, 1.0, 16));
pass.add_mesh(device, queue, "Torus", create_torus_mesh(1.0, 0.3, 16, 16));
pass
}
}