Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

StandardMaterial flat values #3

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions crates/bevy_ecs/src/system/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,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,
Expand Down Expand Up @@ -318,8 +316,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);
}
Expand Down
6 changes: 5 additions & 1 deletion crates/bevy_ecs/src/system/exclusive_system.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
1 change: 0 additions & 1 deletion crates/bevy_ecs/src/world/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ impl World {
&mut self.entities
}


/// Retrieves this world's [Archetypes] collection
#[inline]
pub fn archetypes(&self) -> &Archetypes {
Expand Down
2 changes: 1 addition & 1 deletion crates/crevice/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,4 @@ pub mod internal;

mod mint;

mod glam;
mod glam;
24 changes: 20 additions & 4 deletions examples/3d/3d_scene_pipelined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,23 +37,39 @@ 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()
})
.insert(Movable);
// 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()
})
Expand Down
4 changes: 2 additions & 2 deletions pipelined/bevy_pbr2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand All @@ -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>();

Expand Down
176 changes: 173 additions & 3 deletions pipelined/bevy_pbr2/src/material.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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);
}
}
76 changes: 39 additions & 37 deletions pipelined/bevy_pbr2/src/render/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

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,
);
}
},
);
sample_count: 1,
};

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,
);
}
},
);
}
}

Ok(())
Expand Down
Loading