mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
parent
579c769f7c
commit
01116b1fdb
16 changed files with 339 additions and 103 deletions
|
@ -59,9 +59,7 @@ impl<'a> Commands<'a> {
|
|||
}
|
||||
|
||||
pub fn get_or_spawn(&mut self, entity: Entity) -> EntityCommands<'a, '_> {
|
||||
self.add(GetOrSpawn {
|
||||
entity,
|
||||
});
|
||||
self.add(GetOrSpawn { entity });
|
||||
EntityCommands {
|
||||
entity,
|
||||
commands: self,
|
||||
|
@ -292,8 +290,7 @@ pub struct GetOrSpawn {
|
|||
entity: Entity,
|
||||
}
|
||||
|
||||
impl Command for GetOrSpawn
|
||||
{
|
||||
impl Command for GetOrSpawn {
|
||||
fn write(self: Box<Self>, world: &mut World) {
|
||||
world.get_or_spawn(self.entity);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::{archetype::ArchetypeGeneration, system::{check_system_change_tick, BoxedSystem, IntoSystem, System, SystemId}, world::World};
|
||||
use crate::{
|
||||
archetype::ArchetypeGeneration,
|
||||
system::{check_system_change_tick, BoxedSystem, IntoSystem, System, SystemId},
|
||||
world::World,
|
||||
};
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub trait ExclusiveSystem: Send + Sync + 'static {
|
||||
|
|
|
@ -100,7 +100,6 @@ impl World {
|
|||
&mut self.entities
|
||||
}
|
||||
|
||||
|
||||
/// Retrieves this world's [Archetypes] collection
|
||||
#[inline]
|
||||
pub fn archetypes(&self) -> &Archetypes {
|
||||
|
|
|
@ -139,4 +139,4 @@ pub mod internal;
|
|||
|
||||
mod mint;
|
||||
|
||||
mod glam;
|
||||
mod glam;
|
||||
|
|
|
@ -37,14 +37,24 @@ fn setup(
|
|||
// plane
|
||||
commands.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Plane { size: 5.0 })),
|
||||
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
|
||||
material: materials.add(StandardMaterial {
|
||||
color: Color::INDIGO,
|
||||
roughness: 1.0,
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
});
|
||||
// cube
|
||||
commands
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
|
||||
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
|
||||
material: materials.add(StandardMaterial {
|
||||
color: Color::PINK,
|
||||
roughness: 0.0,
|
||||
metallic: 1.0,
|
||||
reflectance: 1.0,
|
||||
..Default::default()
|
||||
}),
|
||||
transform: Transform::from_xyz(0.0, 1.0, 0.0),
|
||||
..Default::default()
|
||||
})
|
||||
|
@ -52,8 +62,14 @@ fn setup(
|
|||
// sphere
|
||||
commands
|
||||
.spawn_bundle(PbrBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::UVSphere { radius: 0.5, ..Default::default() })),
|
||||
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
|
||||
mesh: meshes.add(Mesh::from(shape::UVSphere {
|
||||
radius: 0.5,
|
||||
..Default::default()
|
||||
})),
|
||||
material: materials.add(StandardMaterial {
|
||||
color: Color::LIME_GREEN,
|
||||
..Default::default()
|
||||
}),
|
||||
transform: Transform::from_xyz(1.5, 1.0, 1.5),
|
||||
..Default::default()
|
||||
})
|
||||
|
|
|
@ -9,7 +9,6 @@ pub use material::*;
|
|||
pub use render::*;
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
use bevy_asset::AddAsset;
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_render2::{
|
||||
core_pipeline,
|
||||
|
@ -29,7 +28,7 @@ pub struct PbrPlugin;
|
|||
|
||||
impl Plugin for PbrPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_asset::<StandardMaterial>();
|
||||
app.add_plugin(StandardMaterialPlugin);
|
||||
|
||||
let render_app = app.sub_app_mut(0);
|
||||
render_app
|
||||
|
@ -50,6 +49,7 @@ impl Plugin for PbrPlugin {
|
|||
.add_system_to_stage(RenderStage::Cleanup, render::cleanup_view_lights.system())
|
||||
.init_resource::<PbrShaders>()
|
||||
.init_resource::<ShadowShaders>()
|
||||
.init_resource::<MaterialMeta>()
|
||||
.init_resource::<MeshMeta>()
|
||||
.init_resource::<LightMeta>();
|
||||
|
||||
|
|
|
@ -1,10 +1,71 @@
|
|||
use bevy_reflect::{Reflect, TypeUuid};
|
||||
use bevy_render2::color::Color;
|
||||
use bevy_app::{App, CoreStage, EventReader, Plugin};
|
||||
use bevy_asset::{AddAsset, AssetEvent, Assets, Handle};
|
||||
use bevy_ecs::prelude::*;
|
||||
use bevy_math::Vec4;
|
||||
use bevy_reflect::TypeUuid;
|
||||
use bevy_render2::{
|
||||
color::Color,
|
||||
render_command::RenderCommandQueue,
|
||||
render_resource::{BufferId, BufferInfo, BufferUsage},
|
||||
renderer::{RenderResourceContext, RenderResources},
|
||||
};
|
||||
use bevy_utils::HashSet;
|
||||
use crevice::std140::{AsStd140, Std140};
|
||||
|
||||
#[derive(Debug, Default, Clone, TypeUuid, Reflect)]
|
||||
// TODO: this shouldn't live in the StandardMaterial type
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct StandardMaterialGpuData {
|
||||
pub buffer: BufferId,
|
||||
}
|
||||
|
||||
/// A material with "standard" properties used in PBR lighting
|
||||
/// Standard property values with pictures here https://google.github.io/filament/Material%20Properties.pdf
|
||||
#[derive(Debug, Clone, TypeUuid)]
|
||||
#[uuid = "7494888b-c082-457b-aacf-517228cc0c22"]
|
||||
pub struct StandardMaterial {
|
||||
/// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything
|
||||
/// in between.
|
||||
pub color: Color,
|
||||
/// Linear perceptual roughness, clamped to [0.089, 1.0] in the shader
|
||||
/// Defaults to minimum of 0.089
|
||||
pub roughness: f32,
|
||||
/// From [0.0, 1.0], dielectric to pure metallic
|
||||
pub metallic: f32,
|
||||
/// Specular intensity for non-metals on a linear scale of [0.0, 1.0]
|
||||
/// defaults to 0.5 which is mapped to 4% reflectance in the shader
|
||||
pub reflectance: f32,
|
||||
// Use a color for user friendliness even though we technically don't use the alpha channel
|
||||
// Might be used in the future for exposure correction in HDR
|
||||
pub emissive: Color,
|
||||
pub gpu_data: Option<StandardMaterialGpuData>,
|
||||
}
|
||||
|
||||
impl StandardMaterial {
|
||||
pub fn gpu_data(&self) -> Option<&StandardMaterialGpuData> {
|
||||
self.gpu_data.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StandardMaterial {
|
||||
fn default() -> Self {
|
||||
StandardMaterial {
|
||||
color: Color::rgb(1.0, 1.0, 1.0),
|
||||
// This is the minimum the roughness is clamped to in shader code
|
||||
// See https://google.github.io/filament/Filament.html#materialsystem/parameterization/
|
||||
// It's the minimum floating point value that won't be rounded down to 0 in the
|
||||
// calculations used. Although technically for 32-bit floats, 0.045 could be
|
||||
// used.
|
||||
roughness: 0.089,
|
||||
// Few materials are purely dielectric or metallic
|
||||
// This is just a default for mostly-dielectric
|
||||
metallic: 0.01,
|
||||
// Minimum real-world reflectance is 2%, most materials between 2-5%
|
||||
// Expressed in a linear scale and equivalent to 4% reflectance see https://google.github.io/filament/Material%20Properties.pdf
|
||||
reflectance: 0.5,
|
||||
emissive: Color::BLACK,
|
||||
gpu_data: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Color> for StandardMaterial {
|
||||
|
@ -15,3 +76,112 @@ impl From<Color> for StandardMaterial {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, AsStd140)]
|
||||
pub struct StandardMaterialUniformData {
|
||||
/// Doubles as diffuse albedo for non-metallic, specular for metallic and a mix for everything
|
||||
/// in between.
|
||||
pub color: Vec4,
|
||||
/// Linear perceptual roughness, clamped to [0.089, 1.0] in the shader
|
||||
/// Defaults to minimum of 0.089
|
||||
pub roughness: f32,
|
||||
/// From [0.0, 1.0], dielectric to pure metallic
|
||||
pub metallic: f32,
|
||||
/// Specular intensity for non-metals on a linear scale of [0.0, 1.0]
|
||||
/// defaults to 0.5 which is mapped to 4% reflectance in the shader
|
||||
pub reflectance: f32,
|
||||
// Use a color for user friendliness even though we technically don't use the alpha channel
|
||||
// Might be used in the future for exposure correction in HDR
|
||||
pub emissive: Vec4,
|
||||
}
|
||||
|
||||
pub struct StandardMaterialPlugin;
|
||||
|
||||
impl Plugin for StandardMaterialPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_asset::<StandardMaterial>().add_system_to_stage(
|
||||
CoreStage::PostUpdate,
|
||||
standard_material_resource_system.system(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn standard_material_resource_system(
|
||||
render_resource_context: Res<RenderResources>,
|
||||
mut render_command_queue: ResMut<RenderCommandQueue>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut material_events: EventReader<AssetEvent<StandardMaterial>>,
|
||||
) {
|
||||
let mut changed_materials = HashSet::default();
|
||||
let render_resource_context = &**render_resource_context;
|
||||
for event in material_events.iter() {
|
||||
match event {
|
||||
AssetEvent::Created { ref handle } => {
|
||||
changed_materials.insert(handle.clone_weak());
|
||||
}
|
||||
AssetEvent::Modified { ref handle } => {
|
||||
changed_materials.insert(handle.clone_weak());
|
||||
// TODO: uncomment this to support mutated materials
|
||||
// remove_current_material_resources(render_resource_context, handle, &mut materials);
|
||||
}
|
||||
AssetEvent::Removed { ref handle } => {
|
||||
remove_current_material_resources(render_resource_context, handle, &mut materials);
|
||||
// if material was modified and removed in the same update, ignore the modification
|
||||
// events are ordered so future modification events are ok
|
||||
changed_materials.remove(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update changed material data
|
||||
for changed_material_handle in changed_materials.iter() {
|
||||
if let Some(material) = materials.get_mut(changed_material_handle) {
|
||||
// TODO: this avoids creating new materials each frame because storing gpu data in the material flags it as
|
||||
// modified. this prevents hot reloading and therefore can't be used in an actual impl.
|
||||
if material.gpu_data.is_some() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = StandardMaterialUniformData {
|
||||
color: material.color.into(),
|
||||
roughness: material.roughness,
|
||||
metallic: material.metallic,
|
||||
reflectance: material.reflectance,
|
||||
emissive: material.emissive.into(),
|
||||
};
|
||||
let value_std140 = value.as_std140();
|
||||
|
||||
let size = StandardMaterialUniformData::std140_size_static();
|
||||
|
||||
let staging_buffer = render_resource_context.create_buffer_with_data(
|
||||
BufferInfo {
|
||||
size,
|
||||
buffer_usage: BufferUsage::COPY_SRC | BufferUsage::MAP_WRITE,
|
||||
mapped_at_creation: true,
|
||||
},
|
||||
value_std140.as_bytes(),
|
||||
);
|
||||
|
||||
let buffer = render_resource_context.create_buffer(BufferInfo {
|
||||
size,
|
||||
buffer_usage: BufferUsage::COPY_DST | BufferUsage::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
render_command_queue.copy_buffer_to_buffer(staging_buffer, 0, buffer, 0, size as u64);
|
||||
render_command_queue.free_buffer(staging_buffer);
|
||||
|
||||
material.gpu_data = Some(StandardMaterialGpuData { buffer });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_current_material_resources(
|
||||
render_resource_context: &dyn RenderResourceContext,
|
||||
handle: &Handle<StandardMaterial>,
|
||||
materials: &mut Assets<StandardMaterial>,
|
||||
) {
|
||||
if let Some(gpu_data) = materials.get_mut(handle).and_then(|t| t.gpu_data.take()) {
|
||||
render_resource_context.remove_buffer(gpu_data.buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,44 +325,46 @@ impl Node for ShadowPassNode {
|
|||
world: &World,
|
||||
) -> Result<(), NodeRunError> {
|
||||
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
|
||||
let view_lights = self.main_view_query.get_manual(world, view_entity).unwrap();
|
||||
for view_light_entity in view_lights.lights.iter().copied() {
|
||||
let (view_light, shadow_phase) = self
|
||||
.view_light_query
|
||||
.get_manual(world, view_light_entity)
|
||||
.unwrap();
|
||||
let pass_descriptor = PassDescriptor {
|
||||
color_attachments: Vec::new(),
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||
attachment: TextureAttachment::Id(view_light.depth_texture),
|
||||
depth_ops: Some(Operations {
|
||||
load: LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
if let Some(view_lights) = self.main_view_query.get_manual(world, view_entity).ok() {
|
||||
for view_light_entity in view_lights.lights.iter().copied() {
|
||||
let (view_light, shadow_phase) = self
|
||||
.view_light_query
|
||||
.get_manual(world, view_light_entity)
|
||||
.unwrap();
|
||||
let pass_descriptor = PassDescriptor {
|
||||
color_attachments: Vec::new(),
|
||||
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
|
||||
attachment: TextureAttachment::Id(view_light.depth_texture),
|
||||
depth_ops: Some(Operations {
|
||||
load: LoadOp::Clear(1.0),
|
||||
store: true,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
stencil_ops: None,
|
||||
}),
|
||||
sample_count: 1,
|
||||
};
|
||||
sample_count: 1,
|
||||
};
|
||||
|
||||
let draw_functions = world.get_resource::<DrawFunctions>().unwrap();
|
||||
let draw_functions = world.get_resource::<DrawFunctions>().unwrap();
|
||||
|
||||
render_context.begin_render_pass(
|
||||
&pass_descriptor,
|
||||
&mut |render_pass: &mut dyn RenderPass| {
|
||||
let mut draw_functions = draw_functions.write();
|
||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
||||
for drawable in shadow_phase.drawn_things.iter() {
|
||||
let draw_function = draw_functions.get_mut(drawable.draw_function).unwrap();
|
||||
draw_function.draw(
|
||||
world,
|
||||
&mut tracked_pass,
|
||||
view_light_entity,
|
||||
drawable.draw_key,
|
||||
drawable.sort_key,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
render_context.begin_render_pass(
|
||||
&pass_descriptor,
|
||||
&mut |render_pass: &mut dyn RenderPass| {
|
||||
let mut draw_functions = draw_functions.write();
|
||||
let mut tracked_pass = TrackedRenderPass::new(render_pass);
|
||||
for drawable in shadow_phase.drawn_things.iter() {
|
||||
let draw_function =
|
||||
draw_functions.get_mut(drawable.draw_function).unwrap();
|
||||
draw_function.draw(
|
||||
world,
|
||||
&mut tracked_pass,
|
||||
view_light_entity,
|
||||
drawable.draw_key,
|
||||
drawable.sort_key,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
mod light;
|
||||
use bevy_utils::HashMap;
|
||||
pub use light::*;
|
||||
|
||||
use crate::StandardMaterial;
|
||||
use crate::{StandardMaterial, StandardMaterialUniformData};
|
||||
use bevy_asset::{Assets, Handle};
|
||||
use bevy_ecs::{prelude::*, system::SystemState};
|
||||
use bevy_math::Mat4;
|
||||
|
@ -11,13 +12,16 @@ use bevy_render2::{
|
|||
pipeline::*,
|
||||
render_graph::{Node, NodeRunError, RenderGraphContext},
|
||||
render_phase::{Draw, DrawFunctions, Drawable, RenderPhase, TrackedRenderPass},
|
||||
render_resource::{BindGroupBuilder, BindGroupId, BufferId, DynamicUniformVec},
|
||||
render_resource::{
|
||||
BindGroupBuilder, BindGroupId, BufferId, DynamicUniformVec, RenderResourceBinding,
|
||||
},
|
||||
renderer::{RenderContext, RenderResources},
|
||||
shader::{Shader, ShaderStage, ShaderStages},
|
||||
texture::{TextureFormat, TextureSampleType},
|
||||
view::{ViewMeta, ViewUniform},
|
||||
};
|
||||
use bevy_transform::components::GlobalTransform;
|
||||
use crevice::std140::AsStd140;
|
||||
|
||||
pub struct PbrShaders {
|
||||
pipeline: PipelineId,
|
||||
|
@ -143,6 +147,7 @@ struct ExtractedMesh {
|
|||
vertex_buffer: BufferId,
|
||||
index_info: Option<IndexInfo>,
|
||||
transform_binding_offset: u32,
|
||||
material_buffer: BufferId,
|
||||
}
|
||||
|
||||
struct IndexInfo {
|
||||
|
@ -157,22 +162,27 @@ pub struct ExtractedMeshes {
|
|||
pub fn extract_meshes(
|
||||
mut commands: Commands,
|
||||
meshes: Res<Assets<Mesh>>,
|
||||
_materials: Res<Assets<StandardMaterial>>,
|
||||
materials: Res<Assets<StandardMaterial>>,
|
||||
query: Query<(&GlobalTransform, &Handle<Mesh>, &Handle<StandardMaterial>)>,
|
||||
) {
|
||||
let mut extracted_meshes = Vec::new();
|
||||
for (transform, mesh_handle, _material_handle) in query.iter() {
|
||||
for (transform, mesh_handle, material_handle) in query.iter() {
|
||||
if let Some(mesh) = meshes.get(mesh_handle) {
|
||||
if let Some(gpu_data) = &mesh.gpu_data() {
|
||||
extracted_meshes.push(ExtractedMesh {
|
||||
transform: transform.compute_matrix(),
|
||||
vertex_buffer: gpu_data.vertex_buffer,
|
||||
index_info: gpu_data.index_buffer.map(|i| IndexInfo {
|
||||
buffer: i,
|
||||
count: mesh.indices().unwrap().len() as u32,
|
||||
}),
|
||||
transform_binding_offset: 0,
|
||||
})
|
||||
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(),
|
||||
vertex_buffer: mesh_gpu_data.vertex_buffer,
|
||||
index_info: mesh_gpu_data.index_buffer.map(|i| IndexInfo {
|
||||
buffer: i,
|
||||
count: mesh.indices().unwrap().len() as u32,
|
||||
}),
|
||||
transform_binding_offset: 0,
|
||||
material_buffer: material_gpu_data.buffer,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -211,6 +221,11 @@ struct MeshViewBindGroups {
|
|||
mesh_transform_bind_group: BindGroupId,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct MaterialMeta {
|
||||
material_bind_groups: Vec<BindGroupId>,
|
||||
}
|
||||
|
||||
pub fn queue_meshes(
|
||||
mut commands: Commands,
|
||||
draw_functions: Res<DrawFunctions>,
|
||||
|
@ -218,9 +233,10 @@ pub fn queue_meshes(
|
|||
pbr_shaders: Res<PbrShaders>,
|
||||
shadow_shaders: Res<ShadowShaders>,
|
||||
mesh_meta: Res<MeshMeta>,
|
||||
mut material_meta: ResMut<MaterialMeta>,
|
||||
light_meta: Res<LightMeta>,
|
||||
view_meta: Res<ViewMeta>,
|
||||
extracted_meshes: Res<ExtractedMeshes>,
|
||||
mut extracted_meshes: ResMut<ExtractedMeshes>,
|
||||
mut views: Query<(Entity, &ViewLights, &mut RenderPhase<Transparent3dPhase>)>,
|
||||
mut view_light_shadow_phases: Query<&mut RenderPhase<ShadowPhase>>,
|
||||
) {
|
||||
|
@ -249,13 +265,38 @@ pub fn queue_meshes(
|
|||
mesh_transform_bind_group: mesh_transform_bind_group.id,
|
||||
});
|
||||
|
||||
// TODO: free old bind groups? clear_unused_bind_groups() currently does this for us? Moving to RAII would also do this for us?
|
||||
material_meta.material_bind_groups.clear();
|
||||
let mut material_bind_group_indices = HashMap::default();
|
||||
|
||||
let draw_pbr = draw_functions.read().get_id::<DrawPbr>().unwrap();
|
||||
for i in 0..extracted_meshes.meshes.len() {
|
||||
for (i, mesh) in extracted_meshes.meshes.iter_mut().enumerate() {
|
||||
let material_bind_group_index = *material_bind_group_indices
|
||||
.entry(mesh.material_buffer)
|
||||
.or_insert_with(|| {
|
||||
let index = material_meta.material_bind_groups.len();
|
||||
let material_bind_group = BindGroupBuilder::default()
|
||||
.add_binding(
|
||||
0,
|
||||
RenderResourceBinding::Buffer {
|
||||
buffer: mesh.material_buffer,
|
||||
range: 0..StandardMaterialUniformData::std140_size_static() as u64,
|
||||
},
|
||||
)
|
||||
.finish();
|
||||
render_resources
|
||||
.create_bind_group(layout.bind_group(2).id, &material_bind_group);
|
||||
material_meta
|
||||
.material_bind_groups
|
||||
.push(material_bind_group.id);
|
||||
index
|
||||
});
|
||||
|
||||
// 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,
|
||||
sort_key: 0, // TODO: sort back-to-front
|
||||
sort_key: material_bind_group_index, // TODO: sort back-to-front, sorting by material for now
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -312,6 +353,7 @@ impl Node for PbrNode {
|
|||
|
||||
type DrawPbrParams<'a> = (
|
||||
Res<'a, PbrShaders>,
|
||||
Res<'a, MaterialMeta>,
|
||||
Res<'a, ExtractedMeshes>,
|
||||
Query<'a, (&'a ViewUniform, &'a MeshViewBindGroups, &'a ViewLights)>,
|
||||
);
|
||||
|
@ -334,9 +376,9 @@ impl Draw for DrawPbr {
|
|||
pass: &mut TrackedRenderPass,
|
||||
view: Entity,
|
||||
draw_key: usize,
|
||||
_sort_key: usize,
|
||||
sort_key: usize,
|
||||
) {
|
||||
let (pbr_shaders, extracted_meshes, views) = self.params.get(world);
|
||||
let (pbr_shaders, material_meta, extracted_meshes, views) = self.params.get(world);
|
||||
let (view_uniforms, mesh_view_bind_groups, view_lights) = views.get(view).unwrap();
|
||||
let layout = &pbr_shaders.pipeline_descriptor.layout;
|
||||
let extracted_mesh = &extracted_meshes.meshes[draw_key];
|
||||
|
@ -356,6 +398,12 @@ impl Draw for DrawPbr {
|
|||
mesh_view_bind_groups.mesh_transform_bind_group,
|
||||
Some(&[extracted_mesh.transform_binding_offset]),
|
||||
);
|
||||
pass.set_bind_group(
|
||||
2,
|
||||
layout.bind_group(2).id,
|
||||
material_meta.material_bind_groups[sort_key],
|
||||
None,
|
||||
);
|
||||
pass.set_vertex_buffer(0, extracted_mesh.vertex_buffer, 0);
|
||||
if let Some(index_info) = &extracted_mesh.index_info {
|
||||
pass.set_index_buffer(index_info.buffer, 0, IndexFormat::Uint32);
|
||||
|
|
|
@ -18,6 +18,7 @@ struct PointLight {
|
|||
// TODO: this can be removed if we move to storage buffers for light arrays
|
||||
const int MAX_POINT_LIGHTS = 10;
|
||||
|
||||
// View bindings - set 0
|
||||
layout(set = 0, binding = 0) uniform View {
|
||||
mat4 ViewProj;
|
||||
vec3 ViewWorldPosition;
|
||||
|
@ -29,6 +30,18 @@ layout(std140, set = 0, binding = 1) uniform Lights {
|
|||
layout(set = 0, binding = 2) uniform texture2DArray t_Shadow;
|
||||
layout(set = 0, binding = 3) uniform samplerShadow s_Shadow;
|
||||
|
||||
// Material bindings - set 2
|
||||
struct StandardMaterial_t {
|
||||
vec4 color;
|
||||
float roughness;
|
||||
float metallic;
|
||||
float reflectance;
|
||||
vec4 emissive;
|
||||
};
|
||||
layout(set = 2, binding = 0) uniform StandardMaterial {
|
||||
StandardMaterial_t Material;
|
||||
};
|
||||
|
||||
# define saturate(x) clamp(x, 0.0, 1.0)
|
||||
const float PI = 3.141592653589793;
|
||||
|
||||
|
@ -252,11 +265,11 @@ float fetch_shadow(int light_id, vec4 homogeneous_coords) {
|
|||
}
|
||||
|
||||
void main() {
|
||||
vec4 color = vec4(0.6, 0.6, 0.6, 1.0);
|
||||
float metallic = 0.01;
|
||||
float reflectance = 0.5;
|
||||
float perceptual_roughness = 0.089;
|
||||
vec3 emissive = vec3(0.0, 0.0, 0.0);
|
||||
vec4 color = Material.color;
|
||||
float metallic = Material.metallic;
|
||||
float reflectance = Material.reflectance;
|
||||
float perceptual_roughness = Material.roughness;
|
||||
vec3 emissive = Material.emissive.xyz;
|
||||
vec3 ambient_color = vec3(0.1, 0.1, 0.1);
|
||||
float occlusion = 1.0;
|
||||
|
||||
|
|
|
@ -8,11 +8,13 @@ layout(location = 0) out vec4 v_WorldPosition;
|
|||
layout(location = 1) out vec3 v_WorldNormal;
|
||||
layout(location = 2) out vec2 v_Uv;
|
||||
|
||||
// View bindings - set 0
|
||||
layout(set = 0, binding = 0) uniform View {
|
||||
mat4 ViewProj;
|
||||
vec3 ViewWorldPosition;
|
||||
};
|
||||
|
||||
// Object bindings - set 1
|
||||
layout(set = 1, binding = 0) uniform MeshTransform {
|
||||
mat4 Model;
|
||||
};
|
||||
|
|
|
@ -47,7 +47,7 @@ pub enum RenderStage {
|
|||
Queue,
|
||||
|
||||
// TODO: This could probably be moved in favor of a system ordering abstraction in Render or Queue
|
||||
/// Sort RenderPhases here
|
||||
/// Sort RenderPhases here
|
||||
PhaseSort,
|
||||
|
||||
/// Actual rendering happens here. In most cases, only the render backend should insert resources here
|
||||
|
|
|
@ -25,13 +25,11 @@ impl PipelineLayout {
|
|||
}
|
||||
|
||||
pub fn bind_group(&self, index: u32) -> &BindGroupDescriptor {
|
||||
self.get_bind_group(index)
|
||||
.expect("bind group exists")
|
||||
self.get_bind_group(index).expect("bind group exists")
|
||||
}
|
||||
|
||||
pub fn bind_group_mut(&mut self, index: u32) -> &mut BindGroupDescriptor {
|
||||
self.get_bind_group_mut(index)
|
||||
.expect("bind group exists")
|
||||
self.get_bind_group_mut(index).expect("bind group exists")
|
||||
}
|
||||
|
||||
pub fn from_shader_layouts(shader_layouts: &mut [ShaderLayout]) -> Self {
|
||||
|
@ -85,7 +83,7 @@ impl PipelineLayout {
|
|||
vertex_buffer_descriptors,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn update_bind_group_ids(&mut self) {
|
||||
for bind_group in self.bind_groups.iter_mut() {
|
||||
bind_group.update_id();
|
||||
|
|
|
@ -4,8 +4,8 @@ mod draw_state;
|
|||
pub use draw::*;
|
||||
pub use draw_state::*;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use bevy_ecs::prelude::Query;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
// TODO: make this configurable per phase?
|
||||
pub struct Drawable {
|
||||
|
@ -39,9 +39,8 @@ impl<T> RenderPhase<T> {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn sort_phase_system<T: 'static>(mut render_phases: Query<&mut RenderPhase<T>>) {
|
||||
for mut phase in render_phases.iter_mut() {
|
||||
phase.sort();
|
||||
}
|
||||
}
|
||||
for mut phase in render_phases.iter_mut() {
|
||||
phase.sort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,13 +55,7 @@ impl BindGroupBuilder {
|
|||
}
|
||||
|
||||
pub fn add_buffer(self, index: u32, buffer: BufferId, range: Range<u64>) -> Self {
|
||||
self.add_binding(
|
||||
index,
|
||||
RenderResourceBinding::Buffer {
|
||||
buffer,
|
||||
range,
|
||||
},
|
||||
)
|
||||
self.add_binding(index, RenderResourceBinding::Buffer { buffer, range })
|
||||
}
|
||||
|
||||
pub fn finish(mut self) -> BindGroup {
|
||||
|
@ -75,10 +69,7 @@ impl BindGroupBuilder {
|
|||
|
||||
fn hash_binding(&mut self, binding: &RenderResourceBinding) {
|
||||
match binding {
|
||||
RenderResourceBinding::Buffer {
|
||||
buffer,
|
||||
range,
|
||||
} => {
|
||||
RenderResourceBinding::Buffer { buffer, range } => {
|
||||
RenderResourceId::Buffer(*buffer).hash(&mut self.hasher);
|
||||
range.hash(&mut self.hasher);
|
||||
}
|
||||
|
|
|
@ -3,10 +3,7 @@ use std::ops::Range;
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub enum RenderResourceBinding {
|
||||
Buffer {
|
||||
buffer: BufferId,
|
||||
range: Range<u64>,
|
||||
},
|
||||
Buffer { buffer: BufferId, range: Range<u64> },
|
||||
TextureView(TextureViewId),
|
||||
Sampler(SamplerId),
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue