use super::*;
impl ViewportGpuResources {
pub fn new(
device: &wgpu::Device,
target_format: wgpu::TextureFormat,
sample_count: u32,
) -> Self {
use wgpu;
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("mesh_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/mesh.wgsl").into()),
});
let camera_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("camera_bgl"),
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,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
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: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Comparison),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
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,
},
wgpu::BindGroupLayoutEntry {
binding: 4,
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,
},
wgpu::BindGroupLayoutEntry {
binding: 5,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 6,
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,
},
wgpu::BindGroupLayoutEntry {
binding: 7,
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: 8,
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: 9,
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: 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: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
],
});
let object_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("object_bgl"),
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,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
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: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
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: 4,
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: 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::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: 7,
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: 8,
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: 9,
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: 10,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let texture_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("texture_bgl"),
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::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("mesh_pipeline_layout"),
bind_group_layouts: &[&camera_bgl, &object_bgl],
push_constant_ranges: &[],
});
let depth_stencil = wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
};
let solid_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("solid_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Back),
unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(depth_stencil.clone()),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let solid_two_sided_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("solid_two_sided_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None, unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(depth_stencil.clone()),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let transparent_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("transparent_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState {
color: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::SrcAlpha,
dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
operation: wgpu::BlendOperation::Add,
},
alpha: wgpu::BlendComponent {
src_factor: wgpu::BlendFactor::One,
dst_factor: wgpu::BlendFactor::Zero,
operation: wgpu::BlendOperation::Add,
},
}),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None, unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false, depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let wireframe_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("wireframe_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::LineList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None, unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(depth_stencil),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let camera_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("camera_uniform_buf"),
size: std::mem::size_of::<CameraUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let light_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("light_uniform_buf"),
size: std::mem::size_of::<LightUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let clip_planes_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("clip_planes_uniform_buf"),
size: std::mem::size_of::<ClipPlanesUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let clip_volume_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("clip_volume_uniform_buf"),
size: std::mem::size_of::<ClipVolumesUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let shadow_map_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("shadow_atlas"),
size: wgpu::Extent3d {
width: SHADOW_ATLAS_SIZE,
height: SHADOW_ATLAS_SIZE,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let shadow_map_view =
shadow_map_texture.create_view(&wgpu::TextureViewDescriptor::default());
let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("shadow_sampler"),
compare: Some(wgpu::CompareFunction::LessEqual),
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
..Default::default()
});
let shadow_info_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("shadow_info_buf"),
size: std::mem::size_of::<ShadowAtlasUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let ibl_fallback_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("ibl_fallback_black"),
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 | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let ibl_fallback_view =
ibl_fallback_texture.create_view(&wgpu::TextureViewDescriptor::default());
let ibl_fallback_brdf_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("ibl_fallback_brdf"),
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 | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let ibl_fallback_brdf_view =
ibl_fallback_brdf_texture.create_view(&wgpu::TextureViewDescriptor::default());
let ibl_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("ibl_sampler"),
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Linear,
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::ClampToEdge,
..Default::default()
});
let camera_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("camera_bind_group"),
layout: &camera_bgl,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: camera_uniform_buf.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&shadow_map_view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(&shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 3,
resource: light_uniform_buf.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 4,
resource: clip_planes_uniform_buf.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 5,
resource: shadow_info_buf.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 6,
resource: clip_volume_uniform_buf.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 7,
resource: wgpu::BindingResource::TextureView(&ibl_fallback_view),
},
wgpu::BindGroupEntry {
binding: 8,
resource: wgpu::BindingResource::TextureView(&ibl_fallback_view),
},
wgpu::BindGroupEntry {
binding: 9,
resource: wgpu::BindingResource::TextureView(&ibl_fallback_brdf_view),
},
wgpu::BindGroupEntry {
binding: 10,
resource: wgpu::BindingResource::Sampler(&ibl_sampler),
},
wgpu::BindGroupEntry {
binding: 11,
resource: wgpu::BindingResource::TextureView(&ibl_fallback_view),
},
],
});
let shadow_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("shadow_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/shadow.wgsl").into()),
});
let shadow_camera_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("shadow_camera_bgl"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: None,
},
count: None,
}],
});
let shadow_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("shadow_pipeline_layout"),
bind_group_layouts: &[&shadow_camera_bgl, &object_bgl],
push_constant_ranges: &[],
});
let shadow_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("shadow_pipeline"),
layout: Some(&shadow_pipeline_layout),
vertex: wgpu::VertexState {
module: &shadow_shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: None, primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: Some(wgpu::Face::Front), unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState {
constant: 2,
slope_scale: 0.0,
clamp: 0.0,
},
}),
multisample: wgpu::MultisampleState {
count: 1, mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
const SHADOW_SLOT_STRIDE: u64 = 256;
let shadow_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("shadow_uniform_buf"),
size: 4 * SHADOW_SLOT_STRIDE,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let shadow_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("shadow_bind_group"),
layout: &shadow_camera_bgl,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &shadow_uniform_buf,
offset: 0,
size: Some(
wgpu::BufferSize::new(std::mem::size_of::<[[f32; 4]; 4]>() as u64).unwrap(),
),
}),
}],
});
let gizmo_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("gizmo_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/gizmo.wgsl").into()),
});
let gizmo_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("gizmo_bgl"),
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
});
let gizmo_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("gizmo_pipeline_layout"),
bind_group_layouts: &[&camera_bgl, &gizmo_bgl],
push_constant_ranges: &[],
});
let gizmo_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("gizmo_pipeline"),
layout: Some(&gizmo_pipeline_layout),
vertex: wgpu::VertexState {
module: &gizmo_shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &gizmo_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None, unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always, stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let (gizmo_verts, gizmo_indices) = crate::interaction::gizmo::build_gizmo_mesh(
crate::interaction::gizmo::GizmoMode::Translate,
crate::interaction::gizmo::GizmoAxis::None,
glam::Quat::IDENTITY,
);
let gizmo_vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("gizmo_vertex_buf"),
size: (std::mem::size_of::<Vertex>() * gizmo_verts.len().max(1)) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: true,
});
gizmo_vertex_buffer
.slice(..)
.get_mapped_range_mut()
.copy_from_slice(bytemuck::cast_slice(&gizmo_verts));
gizmo_vertex_buffer.unmap();
let gizmo_index_count = gizmo_indices.len() as u32;
let gizmo_index_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("gizmo_index_buf"),
size: (std::mem::size_of::<u32>() * gizmo_indices.len().max(1)) as u64,
usage: wgpu::BufferUsages::INDEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: true,
});
gizmo_index_buffer
.slice(..)
.get_mapped_range_mut()
.copy_from_slice(bytemuck::cast_slice(&gizmo_indices));
gizmo_index_buffer.unmap();
let gizmo_uniform = crate::interaction::gizmo::GizmoUniform {
model: glam::Mat4::IDENTITY.to_cols_array_2d(),
};
let gizmo_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("gizmo_uniform_buf"),
size: std::mem::size_of::<crate::interaction::gizmo::GizmoUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: true,
});
gizmo_uniform_buf
.slice(..)
.get_mapped_range_mut()
.copy_from_slice(bytemuck::cast_slice(&[gizmo_uniform]));
gizmo_uniform_buf.unmap();
let gizmo_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("gizmo_bind_group"),
layout: &gizmo_bgl,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: gizmo_uniform_buf.as_entire_binding(),
}],
});
let overlay_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("overlay_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/overlay.wgsl").into()),
});
let overlay_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("overlay_bgl"),
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 overlay_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("overlay_pipeline_layout"),
bind_group_layouts: &[&camera_bgl, &overlay_bgl],
push_constant_ranges: &[],
});
let overlay_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("overlay_pipeline"),
layout: Some(&overlay_pipeline_layout),
vertex: wgpu::VertexState {
module: &overlay_shader,
entry_point: Some("vs_main"),
buffers: &[OverlayVertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &overlay_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None, unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false, depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let overlay_line_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("overlay_line_pipeline"),
layout: Some(&overlay_pipeline_layout),
vertex: wgpu::VertexState {
module: &overlay_shader,
entry_point: Some("vs_main"),
buffers: &[OverlayVertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &overlay_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::LineList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let grid_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("grid_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/grid.wgsl").into()),
});
let grid_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("grid_bgl"),
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 grid_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("grid_pipeline_layout"),
bind_group_layouts: &[&grid_bgl],
push_constant_ranges: &[],
});
let grid_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("grid_pipeline"),
layout: Some(&grid_pipeline_layout),
vertex: wgpu::VertexState {
module: &grid_shader,
entry_point: Some("vs_main"),
buffers: &[], compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &grid_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::LessEqual,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState {
constant: 4,
slope_scale: 0.0,
clamp: 0.0,
},
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let grid_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("grid_uniform_buf"),
size: std::mem::size_of::<GridUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let grid_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("grid_bind_group"),
layout: &grid_bgl,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: grid_uniform_buf.as_entire_binding(),
}],
});
let ground_plane_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("ground_plane_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/ground_plane.wgsl").into()),
});
let ground_plane_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("ground_plane_bgl"),
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,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
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: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Comparison),
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let ground_plane_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("ground_plane_pipeline_layout"),
bind_group_layouts: &[&ground_plane_bgl],
push_constant_ranges: &[],
});
let ground_plane_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("ground_plane_pipeline"),
layout: Some(&ground_plane_pipeline_layout),
vertex: wgpu::VertexState {
module: &ground_plane_shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &ground_plane_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::LessEqual,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let ground_plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("ground_plane_uniform_buf"),
size: std::mem::size_of::<GroundPlaneUniform>() as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let ground_plane_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("ground_plane_bind_group"),
layout: &ground_plane_bgl,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: ground_plane_uniform_buf.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(&shadow_map_view),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::Sampler(&shadow_sampler),
},
wgpu::BindGroupEntry {
binding: 3,
resource: shadow_info_buf.as_entire_binding(),
},
],
});
let axes_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("axes_overlay_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/axes_overlay.wgsl").into()),
});
let axes_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("axes_pipeline_layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let axes_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("axes_pipeline"),
layout: Some(&axes_pipeline_layout),
vertex: wgpu::VertexState {
module: &axes_shader,
entry_point: Some("vs_main"),
buffers: &[crate::widgets::axes_indicator::AxesVertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &axes_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
cull_mode: None,
unclipped_depth: false,
polygon_mode: wgpu::PolygonMode::Fill,
conservative: false,
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let axes_vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("axes_vertex_buf"),
size: (std::mem::size_of::<crate::widgets::axes_indicator::AxesVertex>() * 2048) as u64,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let material_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("material_sampler"),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
let lut_sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("lut_sampler"),
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
let fallback_normal_map = device.create_texture(&wgpu::TextureDescriptor {
label: Some("fallback_normal_map"),
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::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let fallback_normal_map_view =
fallback_normal_map.create_view(&wgpu::TextureViewDescriptor::default());
let fallback_ao_map = device.create_texture(&wgpu::TextureDescriptor {
label: Some("fallback_ao_map"),
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::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let fallback_ao_map_view =
fallback_ao_map.create_view(&wgpu::TextureViewDescriptor::default());
let fallback_texture = {
let tex = device.create_texture(&wgpu::TextureDescriptor {
label: Some("fallback_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::Rgba8UnormSrgb,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let view = tex.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("fallback_texture_sampler"),
address_mode_u: wgpu::AddressMode::Repeat,
address_mode_v: wgpu::AddressMode::Repeat,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("fallback_texture_bg"),
layout: &texture_bgl,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&sampler),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(&fallback_normal_map_view),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::TextureView(&fallback_ao_map_view),
},
],
});
GpuTexture {
texture: tex,
view,
sampler,
bind_group,
}
};
let fallback_lut_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("fallback_lut_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::Rgba8Unorm,
usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
view_formats: &[],
});
let fallback_lut_view =
fallback_lut_texture.create_view(&wgpu::TextureViewDescriptor::default());
let fallback_scalar_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("fallback_scalar_buf"),
size: 4,
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: true,
});
{
let mut view = fallback_scalar_buf.slice(..).get_mapped_range_mut();
view.copy_from_slice(&[0u8; 4]);
}
fallback_scalar_buf.unmap();
let fallback_face_colour_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("fallback_face_colour_buf"),
size: 16, usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: true,
});
{
let mut view = fallback_face_colour_buf.slice(..).get_mapped_range_mut();
view.copy_from_slice(&[0u8; 16]);
}
fallback_face_colour_buf.unmap();
let fallback_warp_buf = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("fallback_warp_buf"),
size: 12, usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: true,
});
{
let mut view = fallback_warp_buf.slice(..).get_mapped_range_mut();
view.copy_from_slice(&[0u8; 12]);
}
fallback_warp_buf.unmap();
let (cube_verts, cube_indices) = build_unit_cube();
let cube_mesh = Self::create_mesh(
device,
&object_bgl,
&fallback_texture.view,
&fallback_normal_map_view,
&fallback_ao_map_view,
&fallback_texture.sampler,
&lut_sampler,
&fallback_lut_view,
&fallback_scalar_buf,
&fallback_texture.view,
&fallback_face_colour_buf,
&fallback_warp_buf,
&cube_verts,
&cube_indices,
);
let outline_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("outline_bgl"),
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 outline_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("outline_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/outline.wgsl").into()),
});
let outline_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("outline_pipeline_layout"),
bind_group_layouts: &[&camera_bgl, &outline_bgl],
push_constant_ranges: &[],
});
let outline_mask_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("outline_mask_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/outline_mask.wgsl").into()),
});
let outline_mask_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("outline_mask_pipeline"),
layout: Some(&outline_pipeline_layout),
vertex: wgpu::VertexState {
module: &outline_mask_shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &outline_mask_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::R8Unorm,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: Some(wgpu::Face::Back),
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let outline_mask_two_sided_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("outline_mask_two_sided_pipeline"),
layout: Some(&outline_pipeline_layout),
vertex: wgpu::VertexState {
module: &outline_mask_shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &outline_mask_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::R8Unorm,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let splat_outline_mask_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("splat_outline_mask_shader"),
source: wgpu::ShaderSource::Wgsl(
include_str!("../shaders/splat_outline_mask.wgsl").into(),
),
});
let splat_outline_pos_attrs = [wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x3,
}];
let splat_outline_pos_layout = wgpu::VertexBufferLayout {
array_stride: 12, step_mode: wgpu::VertexStepMode::Instance,
attributes: &splat_outline_pos_attrs,
};
let splat_outline_size_attrs = [wgpu::VertexAttribute {
offset: 0,
shader_location: 1,
format: wgpu::VertexFormat::Float32,
}];
let splat_outline_size_layout = wgpu::VertexBufferLayout {
array_stride: 4, step_mode: wgpu::VertexStepMode::Instance,
attributes: &splat_outline_size_attrs,
};
let splat_outline_mask_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("splat_outline_mask_pipeline"),
layout: Some(&outline_pipeline_layout),
vertex: wgpu::VertexState {
module: &splat_outline_mask_shader,
entry_point: Some("vs_main"),
buffers: &[splat_outline_pos_layout, splat_outline_size_layout],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &splat_outline_mask_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::R8Unorm,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Less,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let outline_edge_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("outline_edge_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/outline_edge.wgsl").into()),
});
let outline_edge_bgl = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("outline_edge_bgl"),
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::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
],
});
let outline_edge_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("outline_edge_layout"),
bind_group_layouts: &[&outline_edge_bgl],
push_constant_ranges: &[],
});
let outline_edge_pipeline =
device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("outline_edge_pipeline"),
layout: Some(&outline_edge_layout),
vertex: wgpu::VertexState {
module: &outline_edge_shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &outline_edge_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
});
let xray_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("xray_pipeline"),
layout: Some(&outline_pipeline_layout),
vertex: wgpu::VertexState {
module: &outline_shader,
entry_point: Some("vs_main"),
buffers: &[Vertex::buffer_layout()],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &outline_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
let skybox_shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("skybox_shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/skybox.wgsl").into()),
});
let skybox_pipeline_layout =
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("skybox_pipeline_layout"),
bind_group_layouts: &[&camera_bgl],
push_constant_ranges: &[],
});
let skybox_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("skybox_pipeline"),
layout: Some(&skybox_pipeline_layout),
vertex: wgpu::VertexState {
module: &skybox_shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &skybox_shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Rgba16Float,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
cull_mode: None,
..Default::default()
},
depth_stencil: Some(wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth24PlusStencil8,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Equal,
stencil: wgpu::StencilState::default(),
bias: wgpu::DepthBiasState::default(),
}),
multisample: wgpu::MultisampleState::default(),
multiview: None,
cache: None,
});
Self {
target_format,
sample_count,
solid_pipeline,
solid_two_sided_pipeline,
transparent_pipeline,
wireframe_pipeline,
camera_uniform_buf,
light_uniform_buf,
camera_bind_group,
camera_bind_group_layout: camera_bgl,
object_bind_group_layout: object_bgl,
mesh_store: {
let mut store = crate::resources::mesh_store::MeshStore::new();
store.insert(cube_mesh);
store
},
shadow_map_texture,
shadow_map_view,
shadow_sampler,
shadow_pipeline,
shadow_uniform_buf,
shadow_bind_group,
shadow_info_buf,
shadow_atlas_size: SHADOW_ATLAS_SIZE,
gizmo_pipeline,
gizmo_vertex_buffer,
gizmo_index_buffer,
gizmo_index_count,
gizmo_uniform_buf,
gizmo_bind_group,
gizmo_bind_group_layout: gizmo_bgl,
overlay_pipeline,
overlay_line_pipeline,
grid_pipeline,
grid_uniform_buf,
grid_bind_group,
grid_bind_group_layout: grid_bgl,
ground_plane_pipeline,
_ground_plane_bgl: ground_plane_bgl,
ground_plane_uniform_buf,
ground_plane_bind_group,
overlay_bind_group_layout: overlay_bgl,
constraint_line_buffers: Vec::new(),
axes_pipeline,
axes_vertex_buffer,
axes_vertex_count: 0,
texture_bind_group_layout: texture_bgl,
fallback_texture,
fallback_normal_map,
fallback_normal_map_view,
fallback_ao_map,
fallback_ao_map_view,
material_sampler,
lut_sampler,
material_bind_groups: std::collections::HashMap::new(),
textures: Vec::new(),
matcap_textures: Vec::new(),
matcap_views: Vec::new(),
matcap_sampler: None,
fallback_matcap_view: None,
matcaps_initialized: false,
builtin_matcap_ids: None,
fallback_textures_uploaded: false,
fxaa_texture: None,
fxaa_view: None,
fxaa_pipeline: None,
fxaa_bgl: None,
fxaa_bind_group: None,
ssaa_resolve_pipeline: None,
ssaa_resolve_bgl: None,
fxaa_sampler: None,
clip_planes_uniform_buf,
clip_volume_uniform_buf,
outline_bind_group_layout: outline_bgl,
outline_mask_pipeline,
outline_mask_two_sided_pipeline,
outline_edge_pipeline,
outline_edge_bgl,
xray_pipeline,
splat_outline_mask_pipeline,
volume_outline_mask_pipeline: None,
glyph_outline_mask_pipeline: None,
tensor_glyph_outline_mask_pipeline: None,
outline_colour_texture: None,
outline_colour_view: None,
outline_depth_texture: None,
outline_depth_view: None,
outline_target_size: [0, 0],
outline_composite_pipeline_single: None,
outline_composite_pipeline_msaa: None,
outline_composite_pipeline_hdr: None,
outline_composite_bgl: None,
outline_composite_bind_group: None,
outline_composite_sampler: None,
instance_bind_group_layout: None,
instance_storage_buf: None,
instance_storage_capacity: 0,
instance_bind_groups: std::collections::HashMap::new(),
solid_instanced_pipeline: None,
transparent_instanced_pipeline: None,
shadow_instanced_pipeline: None,
shadow_instanced_cascade_bufs: [None, None, None, None],
shadow_instanced_cascade_bgs: [None, None, None, None],
instance_aabb_buf: None,
instance_aabb_capacity: 0,
batch_meta_buf: None,
batch_counter_buf: None,
batch_meta_capacity: 0,
visibility_index_buf: None,
visibility_index_capacity: 0,
indirect_args_buf: None,
shadow_indirect_bufs: [None, None, None, None],
instance_cull_bind_group_layout: None,
instance_cull_bind_groups: std::collections::HashMap::new(),
hdr_solid_instanced_cull_pipeline: None,
oit_instanced_cull_pipeline: None,
shadow_instanced_cull_pipeline: None,
shadow_cull_instance_bgl: None,
shadow_vis_bufs: [None, None, None, None],
shadow_cull_instance_bgs: [None, None, None, None],
bloom_bgl: None,
ssao_bgl: None,
ssao_blur_bgl: None,
hdr_texture: None,
hdr_view: None,
hdr_depth_texture: None,
hdr_depth_view: None,
hdr_depth_only_view: None,
hdr_size: [0, 0],
tone_map_pipeline: None,
tone_map_bgl: None,
tone_map_bind_group: None,
tone_map_uniform_buf: None,
bloom_threshold_texture: None,
bloom_threshold_view: None,
bloom_ping_texture: None,
bloom_ping_view: None,
bloom_pong_texture: None,
bloom_pong_view: None,
bloom_threshold_pipeline: None,
bloom_blur_pipeline: None,
bloom_threshold_bg: None,
bloom_blur_h_bg: None,
bloom_blur_v_bg: None,
bloom_blur_h_pong_bg: None,
bloom_uniform_buf: None,
bloom_h_uniform_buf: None,
bloom_v_uniform_buf: None,
ssao_texture: None,
ssao_view: None,
ssao_blur_texture: None,
ssao_blur_view: None,
ssao_noise_texture: None,
ssao_noise_view: None,
ssao_kernel_buf: None,
ssao_pipeline: None,
ssao_blur_pipeline: None,
ssao_bg: None,
ssao_blur_bg: None,
ssao_uniform_buf: None,
dof_pipeline: None,
dof_bgl: None,
contact_shadow_texture: None,
contact_shadow_view: None,
contact_shadow_pipeline: None,
contact_shadow_bgl: None,
contact_shadow_bg: None,
contact_shadow_uniform_buf: None,
lic_surface_pipeline: None,
lic_surface_bgl: None,
lic_advect_pipeline: None,
lic_advect_bgl: None,
lic_noise_sampler: None,
lic_placeholder_view: None,
bloom_placeholder_view: None,
ao_placeholder_view: None,
cs_placeholder_view: None,
pp_linear_sampler: None,
pp_nearest_sampler: None,
hdr_solid_pipeline: None,
hdr_solid_two_sided_pipeline: None,
hdr_transparent_pipeline: None,
hdr_wireframe_pipeline: None,
hdr_solid_instanced_pipeline: None,
hdr_transparent_instanced_pipeline: None,
hdr_overlay_pipeline: None,
colourmap_textures: Vec::new(),
colourmap_views: Vec::new(),
colourmaps_cpu: Vec::new(),
fallback_lut_texture,
fallback_lut_view,
fallback_scalar_buf,
fallback_face_colour_buf,
fallback_warp_buf,
builtin_colourmap_ids: None,
colourmaps_initialized: false,
gaussian_splat_pipeline: None,
gaussian_splat_bgl: None,
gaussian_splat_depth_pipeline: None,
gaussian_splat_sort_clear_pipeline: None,
gaussian_splat_sort_histogram_pipeline: None,
gaussian_splat_sort_prefix_pipeline: None,
gaussian_splat_sort_scatter_pipeline: None,
gaussian_splat_sort_init_pipeline: None,
gaussian_splat_depth_bgl: None,
gaussian_splat_sort_bgl: None,
gaussian_splat_store: crate::resources::types::GaussianSplatStore::new(),
sprite_pipeline: None,
sprite_pipeline_depth_write: None,
sprite_bgl: None,
sprite_outline_mask_pipeline: None,
polyline_outline_mask_pipeline: None,
point_cloud_pipeline: None,
glyph_pipeline: None,
glyph_wireframe_pipeline: None,
point_cloud_bgl: None,
glyph_bgl: None,
glyph_instance_bgl: None,
glyph_arrow_mesh: None,
glyph_sphere_mesh: None,
glyph_cube_mesh: None,
tensor_glyph_pipeline: None,
tensor_glyph_wireframe_pipeline: None,
tensor_glyph_bgl: None,
tensor_glyph_instance_bgl: None,
volume_textures: Vec::new(),
volume_pipeline: None,
volume_bgl: None,
volume_cube_vb: None,
volume_cube_ib: None,
volume_default_opacity_lut: None,
volume_default_opacity_lut_view: None,
polyline_pipeline: None,
polyline_no_clip_pipeline: None,
polyline_bgl: None,
polyline_wireframe_pipeline: None,
polyline_wireframe_bgl: None,
streamtube_pipeline: None,
streamtube_wireframe_pipeline: None,
ribbon_pipeline: None,
ribbon_wireframe_pipeline: None,
streamtube_bgl: None,
image_slice_pipeline: None,
image_slice_bgl: None,
volume_surface_slice_pipeline: None,
volume_surface_slice_bgl: None,
compute_filter_pipeline: None,
compute_filter_bgl: None,
oit_accum_texture: None,
oit_accum_view: None,
oit_reveal_texture: None,
oit_reveal_view: None,
oit_pipeline: None,
oit_instanced_pipeline: None,
oit_composite_pipeline: None,
oit_composite_bgl: None,
oit_composite_bind_group: None,
oit_composite_sampler: None,
oit_size: [0, 0],
pt_pipeline: None,
pt_bind_group_layout: None,
projected_tet_store: Vec::new(),
ibl_irradiance_view: None,
ibl_prefiltered_view: None,
ibl_brdf_lut_view: None,
ibl_sampler,
ibl_skybox_view: None,
ibl_fallback_texture,
ibl_fallback_view,
ibl_fallback_brdf_texture,
ibl_fallback_brdf_view,
ibl_irradiance_texture: None,
ibl_prefiltered_texture: None,
ibl_brdf_lut_texture: None,
ibl_skybox_texture: None,
skybox_pipeline,
pick_pipeline: None,
pick_bind_group_layout_1: None,
pick_camera_bgl: None,
implicit_pipeline: None,
implicit_bgl: None,
implicit_outline_mask_pipeline: None,
mc_classify_pipeline: None,
mc_prefix_sum_pipeline: None,
mc_generate_pipeline: None,
mc_surface_pipeline: None,
mc_wireframe_pipeline: None,
mc_wireframe_render_bgl: None,
mc_classify_bgl: None,
mc_prefix_sum_bgl: None,
mc_generate_bgl: None,
mc_render_bgl: None,
mc_case_count_buf: None,
mc_case_table_buf: None,
mc_volumes: Vec::new(),
mc_outline_mask_pipeline: None,
screen_image_pipeline: None,
screen_image_bgl: None,
screen_image_dc_pipeline: None,
screen_image_dc_bgl: None,
screen_rect_outline_mask_pipeline: None,
screen_rect_outline_bgl: None,
sub_highlight_fill_pipeline: None,
sub_highlight_edge_pipeline: None,
sub_highlight_sprite_pipeline: None,
sub_highlight_fill_ldr_pipeline: None,
sub_highlight_edge_ldr_pipeline: None,
sub_highlight_sprite_ldr_pipeline: None,
sub_highlight_bgl: None,
glyph_atlas: super::font::GlyphAtlas::new(device),
overlay_text_pipeline: None,
overlay_text_bgl: None,
overlay_text_sampler: None,
frame_upload_bytes: 0,
dyn_res_upscale_pipeline: None,
dyn_res_upscale_ds_pipeline: None,
dyn_res_upscale_bgl: None,
dyn_res_linear_sampler: None,
}
}
}