Skip to content

Commit

Permalink
StandardMaterial flat values (#3)
Browse files Browse the repository at this point in the history
StandardMaterial flat values
  • Loading branch information
superdump authored and cart committed Jul 24, 2021
1 parent b6e1bfd commit 1b81a54
Show file tree
Hide file tree
Showing 16 changed files with 341 additions and 105 deletions.
7 changes: 2 additions & 5 deletions crates/bevy_ecs/src/system/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
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

0 comments on commit 1b81a54

Please sign in to comment.