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

Add FullscreenPassNode for postprocessing #1988

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from 7 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
2 changes: 1 addition & 1 deletion crates/bevy_pbr/src/render_graph/pbr_pipeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub(crate) fn build_pbr_pipeline(shaders: &mut Assets<Shader>) -> PipelineDescri
clamp_depth: false,
}),
color_target_states: vec![ColorTargetState {
format: TextureFormat::default(),
format: TextureFormat::Bgra8Unorm,
color_blend: BlendState {
src_factor: BlendFactor::SrcAlpha,
dst_factor: BlendFactor::OneMinusSrcAlpha,
Expand Down
41 changes: 0 additions & 41 deletions crates/bevy_pbr/src/render_graph/pbr_pipeline/pbr.frag
Original file line number Diff line number Diff line change
Expand Up @@ -240,41 +240,6 @@ float perceptualRoughnessToRoughness(float perceptualRoughness) {
return clampedPerceptualRoughness * clampedPerceptualRoughness;
}

// from https://64.github.io/tonemapping/
// reinhard on RGB oversaturates colors
vec3 reinhard(vec3 color) {
return color / (1.0 + color);
}

vec3 reinhard_extended(vec3 color, float max_white) {
vec3 numerator = color * (1.0f + (color / vec3(max_white * max_white)));
return numerator / (1.0 + color);
}

// luminance coefficients from Rec. 709.
// https://en.wikipedia.org/wiki/Rec._709
float luminance(vec3 v) {
return dot(v, vec3(0.2126, 0.7152, 0.0722));
}

vec3 change_luminance(vec3 c_in, float l_out) {
float l_in = luminance(c_in);
return c_in * (l_out / l_in);
}

vec3 reinhard_luminance(vec3 color) {
float l_old = luminance(color);
float l_new = l_old / (1.0f + l_old);
return change_luminance(color, l_new);
}

vec3 reinhard_extended_luminance(vec3 color, float max_white_l) {
float l_old = luminance(color);
float numerator = l_old * (1.0f + (l_old / (max_white_l * max_white_l)));
float l_new = numerator / (1.0f + l_old);
return change_luminance(color, l_new);
}

#endif

void main() {
Expand Down Expand Up @@ -400,12 +365,6 @@ void main() {
output_color.rgb = light_accum;
output_color.rgb += (diffuse_ambient + specular_ambient) * AmbientColor.xyz * occlusion;
output_color.rgb += emissive.rgb * output_color.a;

// tone_mapping
output_color.rgb = reinhard_luminance(output_color.rgb);
// Gamma correction.
// Not needed with sRGB buffer
// output_color.rgb = pow(output_color.rgb, vec3(1.0 / 2.2));
#endif

o_Target = output_color;
Expand Down
228 changes: 206 additions & 22 deletions crates/bevy_render/src/render_graph/base.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
use super::{
CameraNode, PassNode, RenderGraph, SharedBuffersNode, TextureCopyNode, WindowSwapChainNode,
WindowTextureNode,
fullscreen_pass_node, CameraNode, FullscreenPassNode, PassNode, RenderGraph, SharedBuffersNode,
TextureCopyNode, WindowSwapChainNode, WindowTextureNode,
};
use crate::{
pass::{
LoadOp, Operations, PassDescriptor, RenderPassColorAttachmentDescriptor,
RenderPassDepthStencilAttachmentDescriptor, TextureAttachment,
},
texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage},
pipeline::{
BlendFactor, BlendOperation, BlendState, ColorTargetState, ColorWrite, PipelineDescriptor,
},
shader::{Shader, ShaderStage, ShaderStages},
texture::{
Extent3d, SamplerDescriptor, TextureDescriptor, TextureDimension, TextureFormat,
TextureUsage,
},
Color,
};
use bevy_asset::Assets;
use bevy_ecs::{reflect::ReflectComponent, world::World};
use bevy_reflect::Reflect;
use bevy_window::WindowId;
Expand Down Expand Up @@ -61,6 +69,7 @@ pub struct BaseRenderGraphConfig {
pub add_main_pass: bool,
pub connect_main_pass_to_swapchain: bool,
pub connect_main_pass_to_main_depth_texture: bool,
pub add_post_pass: bool,
}

pub mod node {
Expand All @@ -69,16 +78,28 @@ pub mod node {
pub const CAMERA_2D: &str = "camera_2d";
pub const TEXTURE_COPY: &str = "texture_copy";
pub const MAIN_DEPTH_TEXTURE: &str = "main_pass_depth_texture";
pub const MAIN_RENDER_TEXTURE: &str = "main_pass_render_texture";
pub const MAIN_SAMPLED_COLOR_ATTACHMENT: &str = "main_pass_sampled_color_attachment";
pub const MAIN_PASS: &str = "main_pass";
pub const SHARED_BUFFERS: &str = "shared_buffers";
pub const POST_PASS: &str = "post_pass";
}

pub mod camera {
pub const CAMERA_3D: &str = "Camera3d";
pub const CAMERA_2D: &str = "Camera2d";
}

pub mod texture {
use crate::Texture;
use bevy_asset::HandleUntyped;
use bevy_reflect::TypeUuid;

pub const MAIN_RENDER_TEXTURE_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Texture::TYPE_UUID, 13378939762009864029);
pub const MAIN_DEPTH_TEXTURE_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Texture::TYPE_UUID, 13378939762009864027);
}

impl Default for BaseRenderGraphConfig {
fn default() -> Self {
BaseRenderGraphConfig {
Expand All @@ -88,6 +109,7 @@ impl Default for BaseRenderGraphConfig {
add_main_depth_texture: true,
connect_main_pass_to_swapchain: true,
connect_main_pass_to_main_depth_texture: true,
add_post_pass: true,
}
}
}
Expand All @@ -110,7 +132,8 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World)
}

graph.add_node(node::SHARED_BUFFERS, SharedBuffersNode::default());
if config.add_main_depth_texture {

if config.add_main_depth_texture && !config.add_post_pass {
graph.add_node(
node::MAIN_DEPTH_TEXTURE,
WindowTextureNode::new(
Expand All @@ -128,20 +151,35 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World)
* bit depth for better performance */
usage: TextureUsage::OUTPUT_ATTACHMENT,
},
None,
None,
),
);
}

if config.add_main_pass {
let mut main_pass_node = PassNode::<&MainPass>::new(PassDescriptor {
color_attachments: vec![msaa.color_attachment_descriptor(
let color_attachments = if config.add_post_pass {
vec![RenderPassColorAttachmentDescriptor {
attachment: TextureAttachment::Input("color_attachment".to_string()),
resolve_target: None,
ops: Operations {
load: LoadOp::Clear(Color::rgb(0.1, 0.2, 0.3)),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a resource for clear color we could use here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Good point.

store: true,
},
}]
} else {
vec![msaa.color_attachment_descriptor(
TextureAttachment::Input("color_attachment".to_string()),
TextureAttachment::Input("color_resolve_target".to_string()),
Operations {
load: LoadOp::Clear(Color::rgb(0.1, 0.1, 0.1)),
store: true,
},
)],
)]
};

let mut main_pass_node = PassNode::<&MainPass>::new(PassDescriptor {
color_attachments,
depth_stencil_attachment: Some(RenderPassDepthStencilAttachmentDescriptor {
attachment: TextureAttachment::Input("depth".to_string()),
depth_ops: Some(Operations {
Expand Down Expand Up @@ -185,12 +223,145 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World)
}
}

if config.add_post_pass {
let main_render_texture_node = WindowTextureNode::new(
WindowId::primary(),
TextureDescriptor {
size: Extent3d::new(1, 1, 1),
mip_level_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::Bgra8Unorm,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when a user wants a different buffer format?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair question, that's one for the how do we compose a rendergraph discussion.

usage: TextureUsage::OUTPUT_ATTACHMENT | TextureUsage::SAMPLED,
},
Some(SamplerDescriptor::default()),
Some(texture::MAIN_RENDER_TEXTURE_HANDLE),
);

graph.add_node(node::MAIN_RENDER_TEXTURE, main_render_texture_node);

let main_depth_texture_node = WindowTextureNode::new(
WindowId::primary(),
TextureDescriptor {
size: Extent3d::new(1, 1, 1),
mip_level_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float,
usage: TextureUsage::OUTPUT_ATTACHMENT | TextureUsage::SAMPLED,
},
Some(SamplerDescriptor::default()),
Some(texture::MAIN_DEPTH_TEXTURE_HANDLE),
);

graph.add_node(node::MAIN_DEPTH_TEXTURE, main_depth_texture_node);

let mut shaders = world.get_resource_mut::<Assets<Shader>>().unwrap();
let mut pipelines = world
.get_resource_mut::<Assets<PipelineDescriptor>>()
.unwrap();

let pipeline_descriptor = PipelineDescriptor {
depth_stencil: None,
color_target_states: vec![ColorTargetState {
format: TextureFormat::Bgra8UnormSrgb,
color_blend: BlendState {
src_factor: BlendFactor::SrcAlpha,
dst_factor: BlendFactor::OneMinusSrcAlpha,
operation: BlendOperation::Add,
},
alpha_blend: BlendState {
src_factor: BlendFactor::One,
dst_factor: BlendFactor::One,
operation: BlendOperation::Add,
},
write_mask: ColorWrite::ALL,
}],
..PipelineDescriptor::new(ShaderStages {
vertex: shaders.add(Shader::from_glsl(
ShaderStage::Vertex,
fullscreen_pass_node::shaders::VERTEX_SHADER,
)),
fragment: Some(shaders.add(Shader::from_glsl(
ShaderStage::Fragment,
fullscreen_pass_node::shaders::REINHARD_FRAGMENT_SHADER,
))),
})
};

let pipeline_handle = pipelines.add(pipeline_descriptor);

let pass_descriptor = PassDescriptor {
color_attachments: vec![msaa.color_attachment_descriptor(
TextureAttachment::Input("color_attachment".to_string()),
TextureAttachment::Input("color_resolve_target".to_string()),
Operations {
load: LoadOp::Load,
store: true,
},
)],
depth_stencil_attachment: None,
sample_count: msaa.samples,
};

let post_pass_node = FullscreenPassNode::new(
pass_descriptor,
pipeline_handle,
vec!["color_texture".into()],
);

graph.add_node(node::POST_PASS, post_pass_node);

graph
.add_node_edge(node::MAIN_PASS, node::POST_PASS)
.unwrap();

graph
.add_slot_edge(
node::MAIN_RENDER_TEXTURE,
WindowTextureNode::OUT_TEXTURE,
node::POST_PASS,
"color_texture",
)
.unwrap();
graph
.add_slot_edge(
node::MAIN_RENDER_TEXTURE,
WindowTextureNode::OUT_SAMPLER,
node::POST_PASS,
"color_texture_sampler",
)
.unwrap();
}

graph.add_node(
node::PRIMARY_SWAP_CHAIN,
WindowSwapChainNode::new(WindowId::primary()),
);

if config.connect_main_pass_to_swapchain {
if config.add_post_pass {
graph
.add_slot_edge(
node::MAIN_RENDER_TEXTURE,
WindowTextureNode::OUT_TEXTURE,
node::MAIN_PASS,
"color_attachment",
)
.unwrap();

graph
.add_slot_edge(
node::PRIMARY_SWAP_CHAIN,
WindowSwapChainNode::OUT_TEXTURE,
node::POST_PASS,
if msaa.samples > 1 {
"color_resolve_target"
} else {
"color_attachment"
},
)
.unwrap();
} else if config.connect_main_pass_to_swapchain {
graph
.add_slot_edge(
node::PRIMARY_SWAP_CHAIN,
Expand All @@ -213,29 +384,42 @@ pub(crate) fn add_base_graph(config: &BaseRenderGraphConfig, world: &mut World)
TextureDescriptor {
size: Extent3d {
depth: 1,
width: 1,
height: 1,
width: 2560,
height: 1440,
mtsr marked this conversation as resolved.
Show resolved Hide resolved
},
mip_level_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::default(),
usage: TextureUsage::OUTPUT_ATTACHMENT,
format: TextureFormat::Bgra8UnormSrgb,
usage: TextureUsage::OUTPUT_ATTACHMENT | TextureUsage::SAMPLED,
},
Some(SamplerDescriptor::default()),
Some(texture::MAIN_RENDER_TEXTURE_HANDLE),
),
);

graph
.add_slot_edge(
node::MAIN_SAMPLED_COLOR_ATTACHMENT,
WindowSwapChainNode::OUT_TEXTURE,
node::MAIN_PASS,
"color_attachment",
)
.unwrap();
if config.add_post_pass {
graph
.add_slot_edge(
node::MAIN_SAMPLED_COLOR_ATTACHMENT,
WindowTextureNode::OUT_TEXTURE,
node::POST_PASS,
"color_attachment",
)
.unwrap();
} else if config.connect_main_pass_to_swapchain {
graph
.add_slot_edge(
node::MAIN_SAMPLED_COLOR_ATTACHMENT,
WindowSwapChainNode::OUT_TEXTURE,
node::MAIN_PASS,
"color_attachment",
)
.unwrap();
}
}

if config.connect_main_pass_to_main_depth_texture {
if config.add_post_pass || config.connect_main_pass_to_main_depth_texture {
graph
.add_slot_edge(
node::MAIN_DEPTH_TEXTURE,
Expand Down
Loading