2021-06-02 02:59:17 +00:00
|
|
|
mod light;
|
|
|
|
pub use light::*;
|
|
|
|
|
2021-08-25 19:44:20 +00:00
|
|
|
use crate::{NotShadowCaster, NotShadowReceiver, StandardMaterial, StandardMaterialUniformData};
|
2021-06-02 02:59:17 +00:00
|
|
|
use bevy_asset::{Assets, Handle};
|
2021-07-28 21:29:32 +00:00
|
|
|
use bevy_core_pipeline::Transparent3dPhase;
|
2021-06-02 02:59:17 +00:00
|
|
|
use bevy_ecs::{prelude::*, system::SystemState};
|
|
|
|
use bevy_math::Mat4;
|
|
|
|
use bevy_render2::{
|
|
|
|
mesh::Mesh,
|
2021-06-26 22:35:07 +00:00
|
|
|
render_asset::RenderAssets,
|
2021-06-02 02:59:17 +00:00
|
|
|
render_graph::{Node, NodeRunError, RenderGraphContext},
|
|
|
|
render_phase::{Draw, DrawFunctions, Drawable, RenderPhase, TrackedRenderPass},
|
2021-06-21 23:28:52 +00:00
|
|
|
render_resource::*,
|
2021-06-27 23:10:23 +00:00
|
|
|
renderer::{RenderContext, RenderDevice, RenderQueue},
|
2021-06-21 23:28:52 +00:00
|
|
|
shader::Shader,
|
2021-06-27 23:10:23 +00:00
|
|
|
texture::{BevyDefault, GpuImage, Image, TextureFormatPixelInfo},
|
2021-06-28 22:36:50 +00:00
|
|
|
view::{ExtractedView, ViewMeta, ViewUniformOffset},
|
2021-06-02 02:59:17 +00:00
|
|
|
};
|
|
|
|
use bevy_transform::components::GlobalTransform;
|
2021-06-26 22:35:07 +00:00
|
|
|
use bevy_utils::slab::{FrameSlabMap, FrameSlabMapKey};
|
2021-06-18 18:21:18 +00:00
|
|
|
use crevice::std140::AsStd140;
|
2021-06-27 23:10:23 +00:00
|
|
|
use wgpu::{
|
|
|
|
Extent3d, ImageCopyTexture, ImageDataLayout, Origin3d, TextureDimension, TextureFormat,
|
|
|
|
TextureViewDescriptor,
|
|
|
|
};
|
2021-06-21 23:28:52 +00:00
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
pub struct PbrShaders {
|
2021-06-21 23:28:52 +00:00
|
|
|
pipeline: RenderPipeline,
|
|
|
|
view_layout: BindGroupLayout,
|
|
|
|
material_layout: BindGroupLayout,
|
|
|
|
mesh_layout: BindGroupLayout,
|
2021-06-27 23:10:23 +00:00
|
|
|
// This dummy white texture is to be used in place of optional StandardMaterial textures
|
|
|
|
dummy_white_gpu_image: GpuImage,
|
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();
|
2021-06-28 22:36:50 +00:00
|
|
|
let shader = Shader::from_wgsl(include_str!("pbr.wgsl"));
|
|
|
|
let shader_module = render_device.create_shader_module(&shader);
|
2021-06-21 23:28:52 +00:00
|
|
|
|
|
|
|
// 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,
|
2021-06-28 22:36:50 +00:00
|
|
|
// TODO: change this to ViewUniform::std140_size_static once crevice fixes this!
|
|
|
|
// Context: https://github.com/LPGhatguy/crevice/issues/29
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
min_binding_size: BufferSize::new(144),
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
|
|
|
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,
|
2021-07-08 02:49:33 +00:00
|
|
|
// TODO: change this to GpuLights::std140_size_static once crevice fixes this!
|
2021-06-28 22:36:50 +00:00
|
|
|
// Context: https://github.com/LPGhatguy/crevice/issues/29
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
min_binding_size: BufferSize::new(1424),
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
|
|
|
count: None,
|
2021-06-02 02:59:17 +00:00
|
|
|
},
|
2021-07-08 02:49:33 +00:00
|
|
|
// Point Shadow Texture Cube Array
|
2021-06-21 23:28:52 +00:00
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 2,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Depth,
|
2021-07-01 23:48:55 +00:00
|
|
|
view_dimension: TextureViewDimension::CubeArray,
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
2021-07-08 02:49:33 +00:00
|
|
|
// Point Shadow Texture Array Sampler
|
2021-06-21 23:28:52 +00:00
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 3,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler {
|
|
|
|
comparison: true,
|
|
|
|
filtering: true,
|
|
|
|
},
|
|
|
|
count: None,
|
2021-06-02 02:59:17 +00:00
|
|
|
},
|
2021-07-08 02:49:33 +00:00
|
|
|
// Directional Shadow Texture Array
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 4,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Depth,
|
|
|
|
view_dimension: TextureViewDimension::D2Array,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Directional Shadow Texture Array Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 5,
|
|
|
|
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 material_layout = render_device.create_bind_group_layout(&BindGroupLayoutDescriptor {
|
2021-06-27 23:10:23 +00:00
|
|
|
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,
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
2021-06-27 23:10:23 +00:00
|
|
|
// Base Color Texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 1,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Float { filterable: true },
|
|
|
|
view_dimension: TextureViewDimension::D2,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Base Color Texture Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 2,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler {
|
|
|
|
comparison: false,
|
|
|
|
filtering: true,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Emissive Texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 3,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Float { filterable: true },
|
|
|
|
view_dimension: TextureViewDimension::D2,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Emissive Texture Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 4,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler {
|
|
|
|
comparison: false,
|
|
|
|
filtering: true,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Metallic Roughness Texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 5,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Float { filterable: true },
|
|
|
|
view_dimension: TextureViewDimension::D2,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Metallic Roughness Texture Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 6,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler {
|
|
|
|
comparison: false,
|
|
|
|
filtering: true,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Occlusion Texture
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 7,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Texture {
|
|
|
|
multisampled: false,
|
|
|
|
sample_type: TextureSampleType::Float { filterable: true },
|
|
|
|
view_dimension: TextureViewDimension::D2,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
// Occlusion Texture Sampler
|
|
|
|
BindGroupLayoutEntry {
|
|
|
|
binding: 8,
|
|
|
|
visibility: ShaderStage::FRAGMENT,
|
|
|
|
ty: BindingType::Sampler {
|
|
|
|
comparison: false,
|
|
|
|
filtering: true,
|
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
},
|
|
|
|
],
|
2021-06-21 23:28:52 +00:00
|
|
|
label: None,
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
|
2021-08-25 20:10:43 +00:00
|
|
|
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,
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
// TODO: change this to MeshUniform::std140_size_static once crevice fixes this!
|
|
|
|
// Context: https://github.com/LPGhatguy/crevice/issues/29
|
|
|
|
min_binding_size: BufferSize::new(144),
|
2021-08-25 20:10:43 +00:00
|
|
|
},
|
|
|
|
count: None,
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
});
|
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
let pipeline_layout = render_device.create_pipeline_layout(&PipelineLayoutDescriptor {
|
|
|
|
label: None,
|
|
|
|
push_constant_ranges: &[],
|
2021-08-25 20:10:43 +00:00
|
|
|
bind_group_layouts: &[&view_layout, &material_layout, &mesh_layout],
|
2021-06-21 23:28:52 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
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,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
}],
|
2021-06-28 22:36:50 +00:00
|
|
|
module: &shader_module,
|
|
|
|
entry_point: "vertex",
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
|
|
|
fragment: Some(FragmentState {
|
2021-06-28 22:36:50 +00:00
|
|
|
module: &shader_module,
|
|
|
|
entry_point: "fragment",
|
2021-06-21 23:28:52 +00:00
|
|
|
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,
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
depth_compare: CompareFunction::Greater,
|
2021-06-02 02:59:17 +00:00
|
|
|
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
|
|
|
|
2021-06-27 23:10:23 +00:00
|
|
|
// A 1x1x1 'all 1.0' texture to use as a dummy texture to use in place of optional StandardMaterial textures
|
|
|
|
let dummy_white_gpu_image = {
|
|
|
|
let image = Image::new_fill(
|
|
|
|
Extent3d::default(),
|
|
|
|
TextureDimension::D2,
|
|
|
|
&[255u8; 4],
|
|
|
|
TextureFormat::bevy_default(),
|
|
|
|
);
|
|
|
|
let texture = render_device.create_texture(&image.texture_descriptor);
|
|
|
|
let sampler = render_device.create_sampler(&image.sampler_descriptor);
|
|
|
|
|
|
|
|
let format_size = image.texture_descriptor.format.pixel_size();
|
|
|
|
let render_queue = world.get_resource_mut::<RenderQueue>().unwrap();
|
|
|
|
render_queue.write_texture(
|
|
|
|
ImageCopyTexture {
|
|
|
|
texture: &texture,
|
|
|
|
mip_level: 0,
|
|
|
|
origin: Origin3d::ZERO,
|
|
|
|
},
|
|
|
|
&image.data,
|
|
|
|
ImageDataLayout {
|
|
|
|
offset: 0,
|
|
|
|
bytes_per_row: Some(
|
|
|
|
std::num::NonZeroU32::new(
|
|
|
|
image.texture_descriptor.size.width * format_size as u32,
|
|
|
|
)
|
|
|
|
.unwrap(),
|
|
|
|
),
|
|
|
|
rows_per_image: None,
|
|
|
|
},
|
|
|
|
image.texture_descriptor.size,
|
|
|
|
);
|
|
|
|
|
|
|
|
let texture_view = texture.create_view(&TextureViewDescriptor::default());
|
|
|
|
GpuImage {
|
|
|
|
texture,
|
|
|
|
texture_view,
|
|
|
|
sampler,
|
|
|
|
}
|
|
|
|
};
|
2021-06-02 02:59:17 +00:00
|
|
|
PbrShaders {
|
|
|
|
pipeline,
|
2021-06-21 23:28:52 +00:00
|
|
|
view_layout,
|
|
|
|
material_layout,
|
|
|
|
mesh_layout,
|
2021-06-27 23:10:23 +00:00
|
|
|
dummy_white_gpu_image,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ExtractedMesh {
|
|
|
|
transform: Mat4,
|
2021-06-26 22:35:07 +00:00
|
|
|
mesh: Handle<Mesh>,
|
|
|
|
transform_binding_offset: u32,
|
2021-06-27 23:10:23 +00:00
|
|
|
material_handle: Handle<StandardMaterial>,
|
2021-08-25 19:44:20 +00:00
|
|
|
casts_shadows: bool,
|
|
|
|
receives_shadows: bool,
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-27 23:10:23 +00:00
|
|
|
images: Res<Assets<Image>>,
|
2021-08-25 19:44:20 +00:00
|
|
|
query: Query<(
|
|
|
|
&GlobalTransform,
|
|
|
|
&Handle<Mesh>,
|
|
|
|
&Handle<StandardMaterial>,
|
|
|
|
Option<&NotShadowCaster>,
|
|
|
|
Option<&NotShadowReceiver>,
|
|
|
|
)>,
|
2021-06-02 02:59:17 +00:00
|
|
|
) {
|
|
|
|
let mut extracted_meshes = Vec::new();
|
2021-08-25 19:44:20 +00:00
|
|
|
for (
|
|
|
|
transform,
|
|
|
|
mesh_handle,
|
|
|
|
material_handle,
|
|
|
|
maybe_not_shadow_caster,
|
|
|
|
maybe_not_shadow_receiver,
|
|
|
|
) in query.iter()
|
|
|
|
{
|
2021-06-26 22:35:07 +00:00
|
|
|
if !meshes.contains(mesh_handle) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-06-27 23:10:23 +00:00
|
|
|
|
2021-06-26 22:35:07 +00:00
|
|
|
if let Some(material) = materials.get(material_handle) {
|
2021-06-27 23:10:23 +00:00
|
|
|
if let Some(ref image) = material.base_color_texture {
|
|
|
|
if !images.contains(image) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(ref image) = material.emissive_texture {
|
|
|
|
if !images.contains(image) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(ref image) = material.metallic_roughness_texture {
|
|
|
|
if !images.contains(image) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let Some(ref image) = material.occlusion_texture {
|
|
|
|
if !images.contains(image) {
|
|
|
|
continue;
|
|
|
|
}
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
2021-06-27 23:10:23 +00:00
|
|
|
extracted_meshes.push(ExtractedMesh {
|
|
|
|
transform: transform.compute_matrix(),
|
|
|
|
mesh: mesh_handle.clone_weak(),
|
|
|
|
transform_binding_offset: 0,
|
|
|
|
material_handle: material_handle.clone_weak(),
|
2021-08-25 19:44:20 +00:00
|
|
|
// NOTE: Double-negative is so that meshes cast and receive shadows by default
|
|
|
|
// Not not shadow caster means that this mesh is a shadow caster
|
|
|
|
casts_shadows: maybe_not_shadow_caster.is_none(),
|
|
|
|
receives_shadows: maybe_not_shadow_receiver.is_none(),
|
2021-06-27 23:10:23 +00:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
continue;
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
commands.insert_resource(ExtractedMeshes {
|
|
|
|
meshes: extracted_meshes,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-06-26 22:35:07 +00:00
|
|
|
struct MeshDrawInfo {
|
|
|
|
// TODO: compare cost of doing this vs cloning the BindGroup?
|
|
|
|
material_bind_group_key: FrameSlabMapKey<BufferId, BindGroup>,
|
|
|
|
}
|
|
|
|
|
2021-08-25 19:44:20 +00:00
|
|
|
#[derive(Debug, AsStd140)]
|
|
|
|
pub struct MeshUniform {
|
|
|
|
model: Mat4,
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
inverse_transpose_model: Mat4,
|
2021-08-25 19:44:20 +00:00
|
|
|
flags: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: These must match the bit flags in bevy_pbr2/src/render/pbr.wgsl!
|
|
|
|
bitflags::bitflags! {
|
|
|
|
#[repr(transparent)]
|
|
|
|
struct MeshFlags: u32 {
|
|
|
|
const SHADOW_RECEIVER = (1 << 0);
|
|
|
|
const NONE = 0;
|
|
|
|
const UNINITIALIZED = 0xFFFF;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-02 02:59:17 +00:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct MeshMeta {
|
2021-08-25 19:44:20 +00:00
|
|
|
transform_uniforms: DynamicUniformVec<MeshUniform>,
|
2021-06-26 22:35:07 +00:00
|
|
|
material_bind_groups: FrameSlabMap<BufferId, BindGroup>,
|
2021-07-01 23:03:33 +00:00
|
|
|
mesh_transform_bind_group: FrameSlabMap<BufferId, BindGroup>,
|
|
|
|
mesh_transform_bind_group_key: Option<FrameSlabMapKey<BufferId, BindGroup>>,
|
2021-06-26 22:35:07 +00:00
|
|
|
mesh_draw_info: Vec<MeshDrawInfo>,
|
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() {
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
let model = extracted_mesh.transform;
|
|
|
|
let inverse_transpose_model = model.inverse().transpose();
|
2021-08-25 19:44:20 +00:00
|
|
|
let flags = if extracted_mesh.receives_shadows {
|
|
|
|
MeshFlags::SHADOW_RECEIVER
|
|
|
|
} else {
|
|
|
|
MeshFlags::NONE
|
|
|
|
};
|
|
|
|
extracted_mesh.transform_binding_offset = mesh_meta.transform_uniforms.push(MeshUniform {
|
Use the infinite reverse right-handed perspective projection (#2543)
# Objective
Forward perspective projections have poor floating point precision distribution over the depth range. Reverse projections fair much better, and instead of having to have a far plane, with the reverse projection, using an infinite far plane is not a problem. The infinite reverse perspective projection has become the industry standard. The renderer rework is a great time to migrate to it.
## Solution
All perspective projections, including point lights, have been moved to using `glam::Mat4::perspective_infinite_reverse_rh()` and so have no far plane. As various depth textures are shared between orthographic and perspective projections, a quirk of this PR is that the near and far planes of the orthographic projection are swapped when the Mat4 is computed. This has no impact on 2D/3D orthographic projection usage, and provides consistency in shaders, texture clear values, etc. throughout the codebase.
## Known issues
For some reason, when looking along -Z, all geometry is black. The camera can be translated up/down / strafed left/right and geometry will still be black. Moving forward/backward or rotating the camera away from looking exactly along -Z causes everything to work as expected.
I have tried to debug this issue but both in macOS and Windows I get crashes when doing pixel debugging. If anyone could reproduce this and debug it I would be very grateful. Otherwise I will have to try to debug it further without pixel debugging, though the projections and such all looked fine to me.
2021-08-27 20:15:09 +00:00
|
|
|
model,
|
|
|
|
inverse_transpose_model,
|
2021-08-25 19:44:20 +00:00
|
|
|
flags: flags.bits,
|
|
|
|
});
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-21 23:28:52 +00:00
|
|
|
|
|
|
|
pub struct MeshViewBindGroups {
|
|
|
|
view: BindGroup,
|
2021-06-18 18:21:18 +00:00
|
|
|
}
|
|
|
|
|
2021-06-27 23:10:23 +00:00
|
|
|
fn image_handle_to_view_sampler<'a>(
|
|
|
|
pbr_shaders: &'a PbrShaders,
|
|
|
|
gpu_images: &'a RenderAssets<Image>,
|
|
|
|
image_option: &Option<Handle<Image>>,
|
|
|
|
) -> (&'a TextureView, &'a Sampler) {
|
|
|
|
image_option.as_ref().map_or(
|
|
|
|
(
|
|
|
|
&pbr_shaders.dummy_white_gpu_image.texture_view,
|
|
|
|
&pbr_shaders.dummy_white_gpu_image.sampler,
|
|
|
|
),
|
|
|
|
|image_handle| {
|
2021-06-28 22:36:50 +00:00
|
|
|
let gpu_image = gpu_images
|
|
|
|
.get(image_handle)
|
|
|
|
.expect("only materials with valid textures should be drawn");
|
2021-06-27 23:10:23 +00:00
|
|
|
(&gpu_image.texture_view, &gpu_image.sampler)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2021-07-02 01:05:20 +00:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
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>,
|
|
|
|
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-27 23:10:23 +00:00
|
|
|
gpu_images: Res<RenderAssets<Image>>,
|
|
|
|
render_materials: Res<RenderAssets<StandardMaterial>>,
|
|
|
|
mut views: Query<(
|
|
|
|
Entity,
|
|
|
|
&ExtractedView,
|
|
|
|
&ViewLights,
|
|
|
|
&mut RenderPhase<Transparent3dPhase>,
|
|
|
|
)>,
|
2021-06-02 02:59:17 +00:00
|
|
|
mut view_light_shadow_phases: Query<&mut RenderPhase<ShadowPhase>>,
|
|
|
|
) {
|
2021-06-21 23:28:52 +00:00
|
|
|
let mesh_meta = mesh_meta.into_inner();
|
|
|
|
|
2021-07-02 01:05:20 +00:00
|
|
|
if view_meta.uniforms.is_empty() {
|
2021-07-01 23:23:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-06-21 23:28:52 +00:00
|
|
|
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;
|
2021-07-01 23:03:33 +00:00
|
|
|
mesh_meta.mesh_transform_bind_group.next_frame();
|
|
|
|
mesh_meta.mesh_transform_bind_group_key =
|
|
|
|
Some(mesh_meta.mesh_transform_bind_group.get_or_insert_with(
|
|
|
|
transform_uniforms.uniform_buffer().unwrap().id(),
|
|
|
|
|| {
|
|
|
|
render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: transform_uniforms.binding(),
|
|
|
|
}],
|
|
|
|
label: None,
|
|
|
|
layout: &pbr_shaders.mesh_layout,
|
|
|
|
})
|
|
|
|
},
|
|
|
|
));
|
2021-06-27 23:10:23 +00:00
|
|
|
for (entity, view, 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,
|
2021-07-08 02:49:33 +00:00
|
|
|
resource: BindingResource::TextureView(
|
|
|
|
&view_lights.point_light_depth_texture_view,
|
|
|
|
),
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 3,
|
2021-07-08 02:49:33 +00:00
|
|
|
resource: BindingResource::Sampler(&shadow_shaders.point_light_sampler),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 4,
|
|
|
|
resource: BindingResource::TextureView(
|
|
|
|
&view_lights.directional_light_depth_texture_view,
|
|
|
|
),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 5,
|
|
|
|
resource: BindingResource::Sampler(&shadow_shaders.directional_light_sampler),
|
2021-06-21 23:28:52 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
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
|
|
|
});
|
|
|
|
|
|
|
|
let draw_pbr = draw_functions.read().get_id::<DrawPbr>().unwrap();
|
2021-06-26 22:35:07 +00:00
|
|
|
mesh_meta.mesh_draw_info.clear();
|
|
|
|
mesh_meta.material_bind_groups.next_frame();
|
|
|
|
|
2021-06-27 23:10:23 +00:00
|
|
|
let view_matrix = view.transform.compute_matrix();
|
|
|
|
let view_row_2 = view_matrix.row(2);
|
2021-06-18 18:21:18 +00:00
|
|
|
for (i, mesh) in extracted_meshes.meshes.iter_mut().enumerate() {
|
2021-06-27 23:10:23 +00:00
|
|
|
let gpu_material = &render_materials
|
|
|
|
.get(&mesh.material_handle)
|
|
|
|
.expect("Failed to get StandardMaterial PreparedAsset");
|
|
|
|
let material_bind_group_key =
|
|
|
|
mesh_meta
|
|
|
|
.material_bind_groups
|
|
|
|
.get_or_insert_with(gpu_material.buffer.id(), || {
|
|
|
|
let (base_color_texture_view, base_color_sampler) =
|
|
|
|
image_handle_to_view_sampler(
|
|
|
|
&pbr_shaders,
|
|
|
|
&gpu_images,
|
|
|
|
&gpu_material.base_color_texture,
|
|
|
|
);
|
|
|
|
|
|
|
|
let (emissive_texture_view, emissive_sampler) =
|
|
|
|
image_handle_to_view_sampler(
|
|
|
|
&pbr_shaders,
|
|
|
|
&gpu_images,
|
|
|
|
&gpu_material.emissive_texture,
|
|
|
|
);
|
|
|
|
|
|
|
|
let (metallic_roughness_texture_view, metallic_roughness_sampler) =
|
|
|
|
image_handle_to_view_sampler(
|
|
|
|
&pbr_shaders,
|
|
|
|
&gpu_images,
|
|
|
|
&gpu_material.metallic_roughness_texture,
|
|
|
|
);
|
|
|
|
let (occlusion_texture_view, occlusion_sampler) =
|
|
|
|
image_handle_to_view_sampler(
|
|
|
|
&pbr_shaders,
|
|
|
|
&gpu_images,
|
|
|
|
&gpu_material.occlusion_texture,
|
|
|
|
);
|
|
|
|
render_device.create_bind_group(&BindGroupDescriptor {
|
|
|
|
entries: &[
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 0,
|
|
|
|
resource: gpu_material.buffer.as_entire_binding(),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 1,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::TextureView(base_color_texture_view),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 2,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::Sampler(base_color_sampler),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 3,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::TextureView(emissive_texture_view),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 4,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::Sampler(emissive_sampler),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 5,
|
|
|
|
resource: BindingResource::TextureView(
|
2021-07-30 03:17:27 +00:00
|
|
|
metallic_roughness_texture_view,
|
2021-06-27 23:10:23 +00:00
|
|
|
),
|
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 6,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::Sampler(metallic_roughness_sampler),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 7,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::TextureView(occlusion_texture_view),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
BindGroupEntry {
|
|
|
|
binding: 8,
|
2021-07-30 03:17:27 +00:00
|
|
|
resource: BindingResource::Sampler(occlusion_sampler),
|
2021-06-27 23:10:23 +00:00
|
|
|
},
|
|
|
|
],
|
|
|
|
label: None,
|
|
|
|
layout: &pbr_shaders.material_layout,
|
|
|
|
})
|
|
|
|
});
|
2021-06-26 22:35:07 +00:00
|
|
|
|
|
|
|
mesh_meta.mesh_draw_info.push(MeshDrawInfo {
|
|
|
|
material_bind_group_key,
|
|
|
|
});
|
2021-06-18 18:21:18 +00:00
|
|
|
|
2021-06-27 23:10:23 +00:00
|
|
|
// NOTE: row 2 of the view matrix dotted with column 3 of the model matrix
|
|
|
|
// gives the z component of translation of the mesh in view space
|
|
|
|
let mesh_z = view_row_2.dot(mesh.transform.col(3));
|
|
|
|
// FIXME: Switch from usize to u64 for portability and use sort key encoding
|
|
|
|
// similar to https://realtimecollisiondetection.net/blog/?p=86 as appropriate
|
|
|
|
// FIXME: What is the best way to map from view space z to a number of bits of unsigned integer?
|
|
|
|
let sort_key = (((mesh_z * 1000.0) as usize) << 10)
|
|
|
|
| (material_bind_group_key.index() & ((1 << 10) - 1));
|
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-27 23:10:23 +00:00
|
|
|
sort_key,
|
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"
|
2021-08-25 19:44:20 +00:00
|
|
|
for (i, mesh) in extracted_meshes.meshes.iter().enumerate() {
|
|
|
|
if mesh.casts_shadows {
|
|
|
|
shadow_phase.add(Drawable {
|
|
|
|
draw_function: draw_shadow_mesh,
|
|
|
|
draw_key: i,
|
|
|
|
sort_key: 0, // TODO: sort back-to-front
|
|
|
|
});
|
|
|
|
}
|
2021-06-02 02:59:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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, MeshMeta>,
|
|
|
|
Res<'w, ExtractedMeshes>,
|
2021-06-26 22:35:07 +00:00
|
|
|
Res<'w, RenderAssets<Mesh>>,
|
2021-06-21 23:28:52 +00:00
|
|
|
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-26 22:35:07 +00:00
|
|
|
_sort_key: usize,
|
2021-06-02 02:59:17 +00:00
|
|
|
) {
|
2021-06-26 22:35:07 +00:00
|
|
|
let (pbr_shaders, mesh_meta, extracted_meshes, meshes, views) = self.params.get(world);
|
2021-06-21 23:28:52 +00:00
|
|
|
let (view_uniforms, view_lights, mesh_view_bind_groups) = views.get(view).unwrap();
|
|
|
|
let extracted_mesh = &extracted_meshes.into_inner().meshes[draw_key];
|
2021-06-26 22:35:07 +00:00
|
|
|
let mesh_meta = mesh_meta.into_inner();
|
2021-06-21 23:28:52 +00:00
|
|
|
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
|
|
|
);
|
2021-08-25 20:10:43 +00:00
|
|
|
let mesh_draw_info = &mesh_meta.mesh_draw_info[draw_key];
|
2021-06-02 02:59:17 +00:00
|
|
|
pass.set_bind_group(
|
|
|
|
1,
|
2021-08-25 20:10:43 +00:00
|
|
|
// &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,
|
2021-07-01 23:03:33 +00:00
|
|
|
mesh_meta
|
|
|
|
.mesh_transform_bind_group
|
|
|
|
.get_value(mesh_meta.mesh_transform_bind_group_key.unwrap())
|
|
|
|
.unwrap(),
|
2021-06-21 23:28:52 +00:00
|
|
|
&[extracted_mesh.transform_binding_offset],
|
2021-06-02 02:59:17 +00:00
|
|
|
);
|
2021-06-26 22:35:07 +00:00
|
|
|
|
|
|
|
let gpu_mesh = meshes.into_inner().get(&extracted_mesh.mesh).unwrap();
|
|
|
|
pass.set_vertex_buffer(0, gpu_mesh.vertex_buffer.slice(..));
|
|
|
|
if let Some(index_info) = &gpu_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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|