Pipelined separate shadow vertex shader (#2727)

# Objective

- Avoid unnecessary work in the vertex shader of the numerous shadow passes
- Have the natural order of bind groups in the pbr shader: view, material, mesh

## Solution

- Separate out the vertex stage of pbr.wgsl into depth.wgsl
- Remove the unnecessary calculation of uv and normal, as well as removing the unnecessary vertex inputs and outputs
- Use the depth.wgsl for shadow passes
- Reorder the bind groups in pbr.wgsl and PbrShaders to be 0 - view, 1 - material, 2 - mesh in decreasing order of rebind frequency
This commit is contained in:
Robert Swain 2021-08-25 20:10:43 +00:00
parent f4aa3284a8
commit dd32cd029d
4 changed files with 68 additions and 35 deletions

View file

@ -0,0 +1,30 @@
[[block]]
struct View {
view_proj: mat4x4<f32>;
world_position: vec3<f32>;
};
[[group(0), binding(0)]]
var view: View;
[[block]]
struct Mesh {
transform: mat4x4<f32>;
};
[[group(1), binding(0)]]
var mesh: Mesh;
struct Vertex {
[[location(0)]] position: vec3<f32>;
};
struct VertexOutput {
[[builtin(position)]] clip_position: vec4<f32>;
};
[[stage(vertex)]]
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
out.clip_position = view.view_proj * mesh.transform * vec4<f32>(vertex.position, 1.0);
return out;
}

View file

@ -14,6 +14,7 @@ use bevy_render2::{
render_phase::{Draw, DrawFunctions, RenderPhase, TrackedRenderPass}, render_phase::{Draw, DrawFunctions, RenderPhase, TrackedRenderPass},
render_resource::*, render_resource::*,
renderer::{RenderContext, RenderDevice}, renderer::{RenderContext, RenderDevice},
shader::Shader,
texture::*, texture::*,
view::{ExtractedView, ViewUniformOffset}, view::{ExtractedView, ViewUniformOffset},
}; };
@ -93,6 +94,7 @@ pub const DIRECTIONAL_SHADOW_LAYERS: u32 = MAX_DIRECTIONAL_LIGHTS as u32;
pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float; pub const SHADOW_FORMAT: TextureFormat = TextureFormat::Depth32Float;
pub struct ShadowShaders { pub struct ShadowShaders {
pub shader_module: ShaderModule,
pub pipeline: RenderPipeline, pub pipeline: RenderPipeline,
pub view_layout: BindGroupLayout, pub view_layout: BindGroupLayout,
pub point_light_sampler: Sampler, pub point_light_sampler: Sampler,
@ -104,6 +106,8 @@ impl FromWorld for ShadowShaders {
fn from_world(world: &mut World) -> Self { fn from_world(world: &mut World) -> Self {
let render_device = world.get_resource::<RenderDevice>().unwrap(); let render_device = world.get_resource::<RenderDevice>().unwrap();
let pbr_shaders = world.get_resource::<PbrShaders>().unwrap(); let pbr_shaders = world.get_resource::<PbrShaders>().unwrap();
let shader = Shader::from_wgsl(include_str!("depth.wgsl"));
let shader_module = render_device.create_shader_module(&shader);
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[ entries: &[
@ -157,7 +161,7 @@ impl FromWorld for ShadowShaders {
}, },
], ],
}], }],
module: &pbr_shaders.shader_module, module: &shader_module,
entry_point: "vertex", entry_point: "vertex",
}, },
fragment: None, fragment: None,
@ -191,6 +195,7 @@ impl FromWorld for ShadowShaders {
}); });
ShadowShaders { ShadowShaders {
shader_module,
pipeline, pipeline,
view_layout, view_layout,
point_light_sampler: render_device.create_sampler(&SamplerDescriptor { point_light_sampler: render_device.create_sampler(&SamplerDescriptor {

View file

@ -27,7 +27,6 @@ use wgpu::{
pub struct PbrShaders { pub struct PbrShaders {
pipeline: RenderPipeline, pipeline: RenderPipeline,
shader_module: ShaderModule,
view_layout: BindGroupLayout, view_layout: BindGroupLayout,
material_layout: BindGroupLayout, material_layout: BindGroupLayout,
mesh_layout: BindGroupLayout, mesh_layout: BindGroupLayout,
@ -117,20 +116,6 @@ impl FromWorld for PbrShaders {
label: None, label: None,
}); });
let mesh_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStage::VERTEX | ShaderStage::FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: BufferSize::new(80),
},
count: None,
}],
label: None,
});
let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[ entries: &[
BindGroupLayoutEntry { BindGroupLayoutEntry {
@ -233,10 +218,24 @@ impl FromWorld for PbrShaders {
label: None, label: None,
}); });
let mesh_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStage::VERTEX | ShaderStage::FRAGMENT,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: true,
min_binding_size: BufferSize::new(80),
},
count: None,
}],
label: None,
});
let pipeline_layout = render_device.create_pipeline_layout(&PipelineLayoutDescriptor { let pipeline_layout = render_device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: None, label: None,
push_constant_ranges: &[], push_constant_ranges: &[],
bind_group_layouts: &[&view_layout, &mesh_layout, &material_layout], bind_group_layouts: &[&view_layout, &material_layout, &mesh_layout],
}); });
let pipeline = render_device.create_render_pipeline(&RenderPipelineDescriptor { let pipeline = render_device.create_render_pipeline(&RenderPipelineDescriptor {
@ -360,7 +359,6 @@ impl FromWorld for PbrShaders {
}; };
PbrShaders { PbrShaders {
pipeline, pipeline,
shader_module,
view_layout, view_layout,
material_layout, material_layout,
mesh_layout, mesh_layout,
@ -818,21 +816,21 @@ impl Draw for DrawPbr {
&mesh_view_bind_groups.view, &mesh_view_bind_groups.view,
&[view_uniforms.offset, view_lights.gpu_light_binding_index], &[view_uniforms.offset, view_lights.gpu_light_binding_index],
); );
let mesh_draw_info = &mesh_meta.mesh_draw_info[draw_key];
pass.set_bind_group( pass.set_bind_group(
1, 1,
// &mesh_meta.material_bind_groups[sort_key & ((1 << 10) - 1)],
&mesh_meta.material_bind_groups[mesh_draw_info.material_bind_group_key],
&[],
);
pass.set_bind_group(
2,
mesh_meta mesh_meta
.mesh_transform_bind_group .mesh_transform_bind_group
.get_value(mesh_meta.mesh_transform_bind_group_key.unwrap()) .get_value(mesh_meta.mesh_transform_bind_group_key.unwrap())
.unwrap(), .unwrap(),
&[extracted_mesh.transform_binding_offset], &[extracted_mesh.transform_binding_offset],
); );
let mesh_draw_info = &mesh_meta.mesh_draw_info[draw_key];
pass.set_bind_group(
2,
// &mesh_meta.material_bind_groups[sort_key & ((1 << 10) - 1)],
&mesh_meta.material_bind_groups[mesh_draw_info.material_bind_group_key],
&[],
);
let gpu_mesh = meshes.into_inner().get(&extracted_mesh.mesh).unwrap(); let gpu_mesh = meshes.into_inner().get(&extracted_mesh.mesh).unwrap();
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..)); pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));

View file

@ -17,7 +17,7 @@ let MESH_FLAGS_SHADOW_RECEIVER_BIT: u32 = 1u;
[[group(0), binding(0)]] [[group(0), binding(0)]]
var view: View; var view: View;
[[group(1), binding(0)]] [[group(2), binding(0)]]
var mesh: Mesh; var mesh: Mesh;
struct Vertex { struct Vertex {
@ -142,23 +142,23 @@ var directional_shadow_textures: texture_depth_2d_array;
[[group(0), binding(5)]] [[group(0), binding(5)]]
var directional_shadow_textures_sampler: sampler_comparison; var directional_shadow_textures_sampler: sampler_comparison;
[[group(2), binding(0)]] [[group(1), binding(0)]]
var material: StandardMaterial; var material: StandardMaterial;
[[group(2), binding(1)]] [[group(1), binding(1)]]
var base_color_texture: texture_2d<f32>; var base_color_texture: texture_2d<f32>;
[[group(2), binding(2)]] [[group(1), binding(2)]]
var base_color_sampler: sampler; var base_color_sampler: sampler;
[[group(2), binding(3)]] [[group(1), binding(3)]]
var emissive_texture: texture_2d<f32>; var emissive_texture: texture_2d<f32>;
[[group(2), binding(4)]] [[group(1), binding(4)]]
var emissive_sampler: sampler; var emissive_sampler: sampler;
[[group(2), binding(5)]] [[group(1), binding(5)]]
var metallic_roughness_texture: texture_2d<f32>; var metallic_roughness_texture: texture_2d<f32>;
[[group(2), binding(6)]] [[group(1), binding(6)]]
var metallic_roughness_sampler: sampler; var metallic_roughness_sampler: sampler;
[[group(2), binding(7)]] [[group(1), binding(7)]]
var occlusion_texture: texture_2d<f32>; var occlusion_texture: texture_2d<f32>;
[[group(2), binding(8)]] [[group(1), binding(8)]]
var occlusion_sampler: sampler; var occlusion_sampler: sampler;
let PI: f32 = 3.141592653589793; let PI: f32 = 3.141592653589793;