2021-06-02 02:59:17 +00:00
|
|
|
mod light;
|
|
|
|
pub use light::*;
|
|
|
|
|
|
|
|
use bevy_asset::{Assets, Handle};
|
|
|
|
use bevy_ecs::{prelude::*, system::SystemState};
|
|
|
|
use bevy_math::Mat4;
|
|
|
|
use bevy_render2::{
|
|
|
|
core_pipeline::Transparent3dPhase,
|
|
|
|
mesh::Mesh,
|
|
|
|
render_graph::{Node, NodeRunError, RenderGraphContext},
|
|
|
|
render_phase::{Draw, DrawFunctions, Drawable, RenderPhase, TrackedRenderPass},
|
2021-06-21 23:28:52 +00:00
|
|
|
render_resource::*,
|
|
|
|
renderer::{RenderContext, RenderDevice},
|
|
|
|
shader::Shader,
|
|
|
|
texture::BevyDefault,
|
|
|
|
view::{ViewMeta, ViewUniform, ViewUniformOffset},
|
2021-06-02 02:59:17 +00:00
|
|
|
};
|
|
|
|
use bevy_transform::components::GlobalTransform;
|
2021-06-21 23:28:52 +00:00
|
|
|
use bevy_utils::HashMap;
|
2021-06-18 18:21:18 +00:00
|
|
|
use crevice::std140::AsStd140;
|
2021-06-21 23:28:52 +00:00
|
|
|
use std::borrow::Cow;
|
|
|
|
|
|
|
|
use crate::{StandardMaterial, StandardMaterialUniformData};
|
2021-06-02 02:59:17 +00:00
|
|
|
|
|
|
|
pub struct PbrShaders {
|
2021-06-21 23:28:52 +00:00
|
|
|
pipeline: RenderPipeline,
|
|
|
|
vertex_shader_module: ShaderModule,
|
|
|
|
view_layout: BindGroupLayout,
|
|
|
|
material_layout: BindGroupLayout,
|
|
|
|
mesh_layout: BindGroupLayout,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this pattern for initializing the shaders / pipeline isn't ideal. this should be handled by the asset system
|
|
|
|
impl FromWorld for PbrShaders {
|
|
|
|
fn from_world(world: &mut World) -> Self {
|
2021-06-21 23:28:52 +00:00
|
|
|
let render_device = world.get_resource::<RenderDevice>().unwrap();
|
|
|
|
let vertex_shader = Shader::from_glsl(ShaderStage::VERTEX, include_str!("pbr.vert"))
|
2021-06-02 02:59:17 +00:00
|
|
|
.get_spirv_shader(None)
|
|
|
|
.unwrap();
|
2021-06-21 23:28:52 +00:00
|
|
|
let fragment_shader = Shader::from_glsl(ShaderStage::FRAGMENT, include_str!("pbr.frag"))
|
2021-06-02 02:59:17 +00:00
|
|
|
.get_spirv_shader(None)
|
|
|
|
.unwrap();
|
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
let vertex_spirv = vertex_shader.get_spirv(None).unwrap();
|
|
|
|
let fragment_spirv = fragment_shader.get_spirv(None).unwrap();
|
|
|
|
|
|
|
|
let vertex_shader_module = render_device.create_shader_module(&ShaderModuleDescriptor {
|
|
|
|
flags: ShaderFlags::default(),
|
|
|
|
label: None,
|
|
|
|
source: ShaderSource::SpirV(Cow::Borrowed(&vertex_spirv)),
|
|
|
|
});
|
|
|
|
let fragment_shader_module = render_device.create_shader_module(&ShaderModuleDescriptor {
|
|
|
|
flags: ShaderFlags::default(),
|
|
|
|
label: None,
|
|
|
|
source: ShaderSource::SpirV(Cow::Borrowed(&fragment_spirv)),
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: move this into ViewMeta?
|
|
|
|
let view_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
|
|
entries: &[
|
|
|
|
// View
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: ShaderStage::VERTEX | ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Buffer {
|
|
|
|
ty: BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: true,
|
|
|
|
// TODO: verify this is correct
|
|
|
|
min_binding_size: BufferSize::new(ViewUniform::std140_size_static() as u64),
|
|
|
|
},
|
|
|
|
count: None,
|
2021-06-02 02:59:17 +00:00
|
|
|
},
|
2021-06-21 23:28:52 +00:00
|
|
|
// Lights
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 1,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Buffer {
|
|
|
|
ty: BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: true,
|
|
|
|
min_binding_size: BufferSize::new(GpuLights::std140_size_static() as u64),
|
|
|
|
},
|
|
|
|
count: None,
|
2021-06-02 02:59:17 +00:00
|
|
|
},
|
2021-06-21 23:28:52 +00:00
|
|
|
// Shadow Texture Array
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 2,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Depth,
|
|
|
|
view_dimension: TextureViewDimension::D2Array,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Shadow Texture Array Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 3,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler {
|
|
|
|
comparison: true,
|
|
|
|
filtering: true,
|
|
|
|
},
|
|
|
|
count: None,
|
2021-06-02 02:59:17 +00:00
|
|
|
},
|
|
|
|
],
|
2021-06-21 23:28:52 +00:00
|
|
|
label: None,
|
|
|
|
});
|
|
|
|
|
|
|
|
let mesh_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
|
|
entries: &[BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: ShaderStage::VERTEX,
|
|
|
|
ty: BindingType::Buffer {
|
|
|
|
ty: BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: true,
|
|
|
|
min_binding_size: BufferSize::new(Mat4::std140_size_static() as u64),
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
let material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
|
|
|
entries: &[BindGroupLayoutEntry {
|
|
|
|
binding: 0,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Buffer {
|
|
|
|
ty: BufferBindingType::Uniform,
|
|
|
|
has_dynamic_offset: false,
|
|
|
|
min_binding_size: BufferSize::new(
|
|
|
|
StandardMaterialUniformData::std140_size_static() as u64,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
let pipeline_layout = render_device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
|
|
|
label: None,
|
|
|
|
push_constant_ranges: &[],
|
|
|
|
bind_group_layouts: &[&view_layout, &mesh_layout, &material_layout],
|
|
|
|
});
|
|
|
|
|
|
|
|
let pipeline = render_device.create_render_pipeline(&RenderPipelineDescriptor {
|
|
|
|
label: None,
|
|
|
|
vertex: VertexState {
|
|
|
|
buffers: &[VertexBufferLayout {
|
|
|
|
array_stride: 32,
|
|
|
|
step_mode: InputStepMode::Vertex,
|
|
|
|
attributes: &[
|
|
|
|
// Position (GOTCHA! Vertex_Position isn't first in the buffer due to how Mesh sorts attributes (alphabetically))
|
|
|
|
VertexAttribute {
|
|
|
|
format: VertexFormat::Float32x3,
|
|
|
|
offset: 12,
|
|
|
|
shader_location: 0,
|
|
|
|
},
|
|
|
|
// Normal
|
|
|
|
VertexAttribute {
|
|
|
|
format: VertexFormat::Float32x3,
|
|
|
|
offset: 0,
|
|
|
|
shader_location: 1,
|
|
|
|
},
|
|
|
|
// Uv
|
|
|
|
VertexAttribute {
|
|
|
|
format: VertexFormat::Float32x2,
|
|
|
|
offset: 24,
|
|
|
|
shader_location: 2,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}],
|
|
|
|
module: &&vertex_shader_module,
|
|
|
|
entry_point: "main",
|
|
|
|
},
|
|
|
|
fragment: Some(FragmentState {
|
|
|
|
module: &&fragment_shader_module,
|
|
|
|
entry_point: "main",
|
|
|
|
targets: &[ColorTargetState {
|
|
|
|
format: TextureFormat::bevy_default(),
|
|
|
|
blend: Some(BlendState {
|
|
|
|
color: BlendComponent {
|
|
|
|
src_factor: BlendFactor::SrcAlpha,
|
|
|
|
dst_factor: BlendFactor::OneMinusSrcAlpha,
|
|
|
|
operation: BlendOperation::Add,
|
|
|
|
},
|
|
|
|
alpha: BlendComponent {
|
|
|
|
src_factor: BlendFactor::One,
|
|
|
|
dst_factor: BlendFactor::One,
|
|
|
|
operation: BlendOperation::Add,
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
write_mask: ColorWrite::ALL,
|
|
|
|
}],
|
|
|
|
}),
|
2021-06-02 02:59:17 +00:00
|
|
|
depth_stencil: Some(DepthStencilState {
|
|
|
|
format: TextureFormat::Depth32Float,
|
|
|
|
depth_write_enabled: true,
|
|
|
|
depth_compare: CompareFunction::Less,
|
|
|
|
stencil: StencilState {
|
|
|
|
front: StencilFaceState::IGNORE,
|
|
|
|
back: StencilFaceState::IGNORE,
|
|
|
|
read_mask: 0,
|
|
|
|
write_mask: 0,
|
|
|
|
},
|
|
|
|
bias: DepthBiasState {
|
|
|
|
constant: 0,
|
|
|
|
slope_scale: 0.0,
|
|
|
|
clamp: 0.0,
|
|
|
|
},
|
|
|
|
}),
|
2021-06-21 23:28:52 +00:00
|
|
|
layout: Some(&pipeline_layout),
|
|
|
|
multisample: MultisampleState::default(),
|
|
|
|
primitive: PrimitiveState {
|
|
|
|
topology: PrimitiveTopology::TriangleList,
|
|
|
|
strip_index_format: None,
|
|
|
|
front_face: FrontFace::Ccw,
|
|
|
|
cull_mode: Some(Face::Back),
|
|
|
|
polygon_mode: PolygonMode::Fill,
|
|
|
|
clamp_depth: false,
|
|
|
|
conservative: false,
|
|
|
|
},
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
|
|
|
|
PbrShaders {
|
|
|
|
pipeline,
|
2021-06-21 23:28:52 +00:00
|
|
|
view_layout,
|
|
|
|
material_layout,
|
|
|
|
mesh_layout,
|
|
|
|
vertex_shader_module,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ExtractedMesh {
|
|
|
|
transform: Mat4,
|
2021-06-21 23:28:52 +00:00
|
|
|
vertex_buffer: Buffer,
|
2021-06-02 02:59:17 +00:00
|
|
|
index_info: Option<IndexInfo>,
|
|
|
|
transform_binding_offset: u32,
|
2021-06-21 23:28:52 +00:00
|
|
|
material_buffer: Buffer,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct IndexInfo {
|
2021-06-21 23:28:52 +00:00
|
|
|
buffer: Buffer,
|
2021-06-02 02:59:17 +00:00
|
|
|
count: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ExtractedMeshes {
|
|
|
|
meshes: Vec<ExtractedMesh>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn extract_meshes(
|
|
|
|
mut commands: Commands,
|
|
|
|
meshes: Res<Assets<Mesh>>,
|
2021-06-18 18:21:18 +00:00
|
|
|
materials: Res<Assets<StandardMaterial>>,
|
2021-06-02 02:59:17 +00:00
|
|
|
query: Query<(&GlobalTransform, &Handle<Mesh>, &Handle<StandardMaterial>)>,
|
|
|
|
) {
|
|
|
|
let mut extracted_meshes = Vec::new();
|
2021-06-18 18:21:18 +00:00
|
|
|
for (transform, mesh_handle, material_handle) in query.iter() {
|
2021-06-02 02:59:17 +00:00
|
|
|
if let Some(mesh) = meshes.get(mesh_handle) {
|
2021-06-18 18:21:18 +00:00
|
|
|
if let Some(mesh_gpu_data) = &mesh.gpu_data() {
|
|
|
|
if let Some(material) = materials.get(material_handle) {
|
|
|
|
if let Some(material_gpu_data) = &material.gpu_data() {
|
|
|
|
extracted_meshes.push(ExtractedMesh {
|
|
|
|
transform: transform.compute_matrix(),
|
2021-06-21 23:28:52 +00:00
|
|
|
vertex_buffer: mesh_gpu_data.vertex_buffer.clone(),
|
|
|
|
index_info: mesh_gpu_data.index_buffer.as_ref().map(|i| IndexInfo {
|
|
|
|
buffer: i.clone(),
|
2021-06-18 18:21:18 +00:00
|
|
|
count: mesh.indices().unwrap().len() as u32,
|
|
|
|
}),
|
|
|
|
transform_binding_offset: 0,
|
2021-06-21 23:28:52 +00:00
|
|
|
material_buffer: material_gpu_data.buffer.clone(),
|
2021-06-18 18:21:18 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commands.insert_resource(ExtractedMeshes {
|
|
|
|
meshes: extracted_meshes,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct MeshMeta {
|
|
|
|
transform_uniforms: DynamicUniformVec<Mat4>,
|
2021-06-21 23:28:52 +00:00
|
|
|
mesh_transform_bind_group: Option<BindGroup>,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn prepare_meshes(
|
2021-06-21 23:28:52 +00:00
|
|
|
render_device: Res<RenderDevice>,
|
2021-06-02 02:59:17 +00:00
|
|
|
mut mesh_meta: ResMut<MeshMeta>,
|
|
|
|
mut extracted_meshes: ResMut<ExtractedMeshes>,
|
|
|
|
) {
|
|
|
|
mesh_meta
|
|
|
|
.transform_uniforms
|
2021-06-21 23:28:52 +00:00
|
|
|
.reserve_and_clear(extracted_meshes.meshes.len(), &render_device);
|
2021-06-02 02:59:17 +00:00
|
|
|
for extracted_mesh in extracted_meshes.meshes.iter_mut() {
|
|
|
|
extracted_mesh.transform_binding_offset =
|
|
|
|
mesh_meta.transform_uniforms.push(extracted_mesh.transform);
|
|
|
|
}
|
|
|
|
|
|
|
|
mesh_meta
|
|
|
|
.transform_uniforms
|
2021-06-21 23:28:52 +00:00
|
|
|
.write_to_staging_buffer(&render_device);
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
2021-06-18 18:21:18 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct MaterialMeta {
|
2021-06-21 23:28:52 +00:00
|
|
|
material_bind_groups: Vec<BindGroup>,
|
|
|
|
material_bind_group_indices: HashMap<BufferId, usize>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct MeshViewBindGroups {
|
|
|
|
view: BindGroup,
|
2021-06-18 18:21:18 +00:00
|
|
|
}
|
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
pub fn queue_meshes(
|
|
|
|
mut commands: Commands,
|
|
|
|
draw_functions: Res<DrawFunctions>,
|
2021-06-21 23:28:52 +00:00
|
|
|
render_device: Res<RenderDevice>,
|
2021-06-02 02:59:17 +00:00
|
|
|
pbr_shaders: Res<PbrShaders>,
|
|
|
|
shadow_shaders: Res<ShadowShaders>,
|
2021-06-21 23:28:52 +00:00
|
|
|
mesh_meta: ResMut<MeshMeta>,
|
|
|
|
material_meta: ResMut<MaterialMeta>,
|
|
|
|
mut light_meta: ResMut<LightMeta>,
|
2021-06-02 02:59:17 +00:00
|
|
|
view_meta: Res<ViewMeta>,
|
2021-06-18 18:21:18 +00:00
|
|
|
mut extracted_meshes: ResMut<ExtractedMeshes>,
|
2021-06-02 02:59:17 +00:00
|
|
|
mut views: Query<(Entity, &ViewLights, &mut RenderPhase<Transparent3dPhase>)>,
|
|
|
|
mut view_light_shadow_phases: Query<&mut RenderPhase<ShadowPhase>>,
|
|
|
|
) {
|
2021-06-21 23:28:52 +00:00
|
|
|
let mesh_meta = mesh_meta.into_inner();
|
|
|
|
let material_meta = material_meta.into_inner();
|
|
|
|
|
|
|
|
light_meta.shadow_view_bind_group.get_or_insert_with(|| {
|
|
|
|
render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: view_meta.uniforms.binding(),
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
layout: &shadow_shaders.view_layout,
|
|
|
|
})
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
if extracted_meshes.meshes.is_empty() {
|
|
|
|
return;
|
|
|
|
}
|
2021-06-21 23:28:52 +00:00
|
|
|
|
|
|
|
let transform_uniforms = &mesh_meta.transform_uniforms;
|
|
|
|
mesh_meta.mesh_transform_bind_group.get_or_insert_with(|| {
|
|
|
|
render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: transform_uniforms.binding(),
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
layout: &pbr_shaders.mesh_layout,
|
|
|
|
})
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
for (entity, view_lights, mut transparent_phase) in views.iter_mut() {
|
2021-06-21 23:28:52 +00:00
|
|
|
// TODO: cache this?
|
|
|
|
let view_bind_group = render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: view_meta.uniforms.binding(),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 1,
|
|
|
|
resource: light_meta.view_gpu_lights.binding(),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 2,
|
|
|
|
resource: BindingResource::TextureView(&view_lights.light_depth_texture_view),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 3,
|
|
|
|
resource: BindingResource::Sampler(&shadow_shaders.light_sampler),
|
|
|
|
},
|
|
|
|
],
|
|
|
|
label: None,
|
|
|
|
layout: &pbr_shaders.view_layout,
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
|
|
|
|
commands.entity(entity).insert(MeshViewBindGroups {
|
2021-06-21 23:28:52 +00:00
|
|
|
view: view_bind_group,
|
2021-06-02 02:59:17 +00:00
|
|
|
});
|
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
// TODO: free old bind groups after a few frames without use?
|
2021-06-18 18:21:18 +00:00
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
let draw_pbr = draw_functions.read().get_id::<DrawPbr>().unwrap();
|
2021-06-21 23:28:52 +00:00
|
|
|
let material_bind_groups = &mut material_meta.material_bind_groups;
|
2021-06-18 18:21:18 +00:00
|
|
|
for (i, mesh) in extracted_meshes.meshes.iter_mut().enumerate() {
|
2021-06-21 23:28:52 +00:00
|
|
|
let material_bind_group_index = *material_meta
|
|
|
|
.material_bind_group_indices
|
|
|
|
.entry(mesh.material_buffer.id())
|
2021-06-18 18:21:18 +00:00
|
|
|
.or_insert_with(|| {
|
2021-06-21 23:28:52 +00:00
|
|
|
let index = material_bind_groups.len();
|
|
|
|
let material_bind_group =
|
|
|
|
render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: mesh.material_buffer.as_entire_binding(),
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
layout: &pbr_shaders.material_layout,
|
|
|
|
});
|
|
|
|
material_bind_groups.push(material_bind_group);
|
2021-06-18 18:21:18 +00:00
|
|
|
index
|
|
|
|
});
|
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
// TODO: currently there is only "transparent phase". this should pick transparent vs opaque according to the mesh material
|
|
|
|
transparent_phase.add(Drawable {
|
|
|
|
draw_function: draw_pbr,
|
|
|
|
draw_key: i,
|
2021-06-18 18:21:18 +00:00
|
|
|
sort_key: material_bind_group_index, // TODO: sort back-to-front, sorting by material for now
|
2021-06-02 02:59:17 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// ultimately lights should check meshes for relevancy (ex: light views can "see" different meshes than the main view can)
|
|
|
|
let draw_shadow_mesh = draw_functions.read().get_id::<DrawShadowMesh>().unwrap();
|
|
|
|
for view_light_entity in view_lights.lights.iter().copied() {
|
|
|
|
let mut shadow_phase = view_light_shadow_phases.get_mut(view_light_entity).unwrap();
|
|
|
|
// TODO: this should only queue up meshes that are actually visible by each "light view"
|
|
|
|
for i in 0..extracted_meshes.meshes.len() {
|
|
|
|
shadow_phase.add(Drawable {
|
|
|
|
draw_function: draw_shadow_mesh,
|
|
|
|
draw_key: i,
|
|
|
|
sort_key: 0, // TODO: sort back-to-front
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: this logic can be moved to prepare_meshes once wgpu::Queue is exposed directly
|
|
|
|
pub struct PbrNode;
|
|
|
|
|
|
|
|
impl Node for PbrNode {
|
|
|
|
fn run(
|
|
|
|
&self,
|
|
|
|
_graph: &mut RenderGraphContext,
|
2021-06-21 23:28:52 +00:00
|
|
|
render_context: &mut RenderContext,
|
2021-06-02 02:59:17 +00:00
|
|
|
world: &World,
|
|
|
|
) -> Result<(), NodeRunError> {
|
|
|
|
let mesh_meta = world.get_resource::<MeshMeta>().unwrap();
|
|
|
|
let light_meta = world.get_resource::<LightMeta>().unwrap();
|
|
|
|
mesh_meta
|
|
|
|
.transform_uniforms
|
2021-06-21 23:28:52 +00:00
|
|
|
.write_to_uniform_buffer(&mut render_context.command_encoder);
|
2021-06-02 02:59:17 +00:00
|
|
|
light_meta
|
|
|
|
.view_gpu_lights
|
2021-06-21 23:28:52 +00:00
|
|
|
.write_to_uniform_buffer(&mut render_context.command_encoder);
|
2021-06-02 02:59:17 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
type DrawPbrParams<'s, 'w> = (
|
|
|
|
Res<'w, PbrShaders>,
|
|
|
|
Res<'w, MaterialMeta>,
|
|
|
|
Res<'w, MeshMeta>,
|
|
|
|
Res<'w, ExtractedMeshes>,
|
|
|
|
Query<
|
|
|
|
'w,
|
|
|
|
's,
|
|
|
|
(
|
|
|
|
&'w ViewUniformOffset,
|
|
|
|
&'w ViewLights,
|
|
|
|
&'w MeshViewBindGroups,
|
|
|
|
),
|
|
|
|
>,
|
2021-06-02 02:59:17 +00:00
|
|
|
);
|
2021-06-21 23:28:52 +00:00
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
pub struct DrawPbr {
|
2021-06-21 23:28:52 +00:00
|
|
|
params: SystemState<DrawPbrParams<'static, 'static>>,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl DrawPbr {
|
|
|
|
pub fn new(world: &mut World) -> Self {
|
|
|
|
Self {
|
|
|
|
params: SystemState::new(world),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Draw for DrawPbr {
|
2021-06-21 23:28:52 +00:00
|
|
|
fn draw<'w, 's>(
|
|
|
|
&'s mut self,
|
|
|
|
world: &'w World,
|
|
|
|
pass: &mut TrackedRenderPass<'w>,
|
2021-06-02 02:59:17 +00:00
|
|
|
view: Entity,
|
|
|
|
draw_key: usize,
|
2021-06-18 18:21:18 +00:00
|
|
|
sort_key: usize,
|
2021-06-02 02:59:17 +00:00
|
|
|
) {
|
2021-06-21 23:28:52 +00:00
|
|
|
let (pbr_shaders, material_meta, mesh_meta, extracted_meshes, views) =
|
|
|
|
self.params.get(world);
|
|
|
|
let (view_uniforms, view_lights, mesh_view_bind_groups) = views.get(view).unwrap();
|
|
|
|
let extracted_mesh = &extracted_meshes.into_inner().meshes[draw_key];
|
|
|
|
pass.set_render_pipeline(&pbr_shaders.into_inner().pipeline);
|
2021-06-02 02:59:17 +00:00
|
|
|
pass.set_bind_group(
|
|
|
|
0,
|
2021-06-21 23:28:52 +00:00
|
|
|
&mesh_view_bind_groups.view,
|
|
|
|
&[view_uniforms.offset, view_lights.gpu_light_binding_index],
|
2021-06-02 02:59:17 +00:00
|
|
|
);
|
|
|
|
pass.set_bind_group(
|
|
|
|
1,
|
2021-06-21 23:28:52 +00:00
|
|
|
mesh_meta
|
|
|
|
.into_inner()
|
|
|
|
.mesh_transform_bind_group
|
|
|
|
.as_ref()
|
|
|
|
.unwrap(),
|
|
|
|
&[extracted_mesh.transform_binding_offset],
|
2021-06-02 02:59:17 +00:00
|
|
|
);
|
2021-06-18 18:21:18 +00:00
|
|
|
pass.set_bind_group(
|
|
|
|
2,
|
2021-06-21 23:28:52 +00:00
|
|
|
&material_meta.into_inner().material_bind_groups[sort_key],
|
|
|
|
&[],
|
2021-06-18 18:21:18 +00:00
|
|
|
);
|
2021-06-21 23:28:52 +00:00
|
|
|
pass.set_vertex_buffer(0, extracted_mesh.vertex_buffer.slice(..));
|
2021-06-02 02:59:17 +00:00
|
|
|
if let Some(index_info) = &extracted_mesh.index_info {
|
2021-06-21 23:28:52 +00:00
|
|
|
pass.set_index_buffer(index_info.buffer.slice(..), 0, IndexFormat::Uint32);
|
2021-06-02 02:59:17 +00:00
|
|
|
pass.draw_indexed(0..index_info.count, 0, 0..1);
|
|
|
|
} else {
|
|
|
|
panic!("non-indexed drawing not supported yet")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|