|
1 |
| -use crate::{ClearColor, Transparent3d}; |
| 1 | +use crate::{AlphaMask3d, ClearColor, Opaque3d, Transparent3d}; |
2 | 2 | use bevy_ecs::prelude::*;
|
3 | 3 | use bevy_render2::{
|
4 | 4 | render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
|
5 | 5 | render_phase::{DrawFunctions, RenderPhase, TrackedRenderPass},
|
6 |
| - render_resource::{ |
7 |
| - LoadOp, Operations, RenderPassColorAttachment, RenderPassDepthStencilAttachment, |
8 |
| - RenderPassDescriptor, |
9 |
| - }, |
| 6 | + render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor}, |
10 | 7 | renderer::RenderContext,
|
11 | 8 | view::{ExtractedView, ViewDepthTexture, ViewTarget},
|
12 | 9 | };
|
13 | 10 |
|
14 | 11 | pub struct MainPass3dNode {
|
15 | 12 | query: QueryState<
|
16 | 13 | (
|
| 14 | + &'static RenderPhase<Opaque3d>, |
| 15 | + &'static RenderPhase<AlphaMask3d>, |
17 | 16 | &'static RenderPhase<Transparent3d>,
|
18 | 17 | &'static ViewTarget,
|
19 | 18 | &'static ViewDepthTexture,
|
@@ -48,52 +47,119 @@ impl Node for MainPass3dNode {
|
48 | 47 | world: &World,
|
49 | 48 | ) -> Result<(), NodeRunError> {
|
50 | 49 | let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
|
51 |
| - let (transparent_phase, target, depth) = self |
| 50 | + let (opaque_phase, alpha_mask_phase, transparent_phase, target, depth) = self |
52 | 51 | .query
|
53 | 52 | .get_manual(world, view_entity)
|
54 | 53 | .expect("view entity should exist");
|
55 | 54 | let clear_color = world.get_resource::<ClearColor>().unwrap();
|
56 |
| - let pass_descriptor = RenderPassDescriptor { |
57 |
| - label: Some("main_pass_3d"), |
58 |
| - color_attachments: &[RenderPassColorAttachment { |
59 |
| - view: if let Some(sampled_target) = &target.sampled_target { |
60 |
| - sampled_target |
61 |
| - } else { |
62 |
| - &target.view |
63 |
| - }, |
64 |
| - resolve_target: if target.sampled_target.is_some() { |
65 |
| - Some(&target.view) |
66 |
| - } else { |
67 |
| - None |
68 |
| - }, |
69 |
| - ops: Operations { |
| 55 | + |
| 56 | + { |
| 57 | + // Run the opaque pass, sorted front-to-back |
| 58 | + // NOTE: Scoped to drop the mutable borrow of render_context |
| 59 | + let pass_descriptor = RenderPassDescriptor { |
| 60 | + label: Some("main_opaque_pass_3d"), |
| 61 | + // NOTE: The opaque pass clears and initializes the color |
| 62 | + // buffer as well as writing to it. |
| 63 | + color_attachments: &[target.get_color_attachment(Operations { |
70 | 64 | load: LoadOp::Clear(clear_color.0.into()),
|
71 | 65 | store: true,
|
72 |
| - }, |
73 |
| - }], |
74 |
| - depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { |
75 |
| - view: &depth.view, |
76 |
| - depth_ops: Some(Operations { |
77 |
| - load: LoadOp::Clear(0.0), |
| 66 | + })], |
| 67 | + depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { |
| 68 | + view: &depth.view, |
| 69 | + // NOTE: The opaque main pass clears and writes to the depth buffer. |
| 70 | + depth_ops: Some(Operations { |
| 71 | + load: LoadOp::Clear(0.0), |
| 72 | + store: true, |
| 73 | + }), |
| 74 | + stencil_ops: None, |
| 75 | + }), |
| 76 | + }; |
| 77 | + |
| 78 | + let draw_functions = world.get_resource::<DrawFunctions<Opaque3d>>().unwrap(); |
| 79 | + |
| 80 | + let render_pass = render_context |
| 81 | + .command_encoder |
| 82 | + .begin_render_pass(&pass_descriptor); |
| 83 | + let mut draw_functions = draw_functions.write(); |
| 84 | + let mut tracked_pass = TrackedRenderPass::new(render_pass); |
| 85 | + for item in opaque_phase.items.iter() { |
| 86 | + let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); |
| 87 | + draw_function.draw(world, &mut tracked_pass, view_entity, item); |
| 88 | + } |
| 89 | + } |
| 90 | + |
| 91 | + { |
| 92 | + // Run the alpha mask pass, sorted front-to-back |
| 93 | + // NOTE: Scoped to drop the mutable borrow of render_context |
| 94 | + let pass_descriptor = RenderPassDescriptor { |
| 95 | + label: Some("main_alpha_mask_pass_3d"), |
| 96 | + // NOTE: The alpha_mask pass loads the color buffer as well as overwriting it where appropriate. |
| 97 | + color_attachments: &[target.get_color_attachment(Operations { |
| 98 | + load: LoadOp::Load, |
78 | 99 | store: true,
|
| 100 | + })], |
| 101 | + depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { |
| 102 | + view: &depth.view, |
| 103 | + // NOTE: The alpha mask pass loads the depth buffer and possibly overwrites it |
| 104 | + depth_ops: Some(Operations { |
| 105 | + load: LoadOp::Load, |
| 106 | + store: true, |
| 107 | + }), |
| 108 | + stencil_ops: None, |
79 | 109 | }),
|
80 |
| - stencil_ops: None, |
81 |
| - }), |
82 |
| - }; |
83 |
| - |
84 |
| - let draw_functions = world |
85 |
| - .get_resource::<DrawFunctions<Transparent3d>>() |
86 |
| - .unwrap(); |
87 |
| - |
88 |
| - let render_pass = render_context |
89 |
| - .command_encoder |
90 |
| - .begin_render_pass(&pass_descriptor); |
91 |
| - let mut draw_functions = draw_functions.write(); |
92 |
| - let mut tracked_pass = TrackedRenderPass::new(render_pass); |
93 |
| - for item in transparent_phase.items.iter() { |
94 |
| - let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); |
95 |
| - draw_function.draw(world, &mut tracked_pass, view_entity, item); |
| 110 | + }; |
| 111 | + |
| 112 | + let draw_functions = world.get_resource::<DrawFunctions<AlphaMask3d>>().unwrap(); |
| 113 | + |
| 114 | + let render_pass = render_context |
| 115 | + .command_encoder |
| 116 | + .begin_render_pass(&pass_descriptor); |
| 117 | + let mut draw_functions = draw_functions.write(); |
| 118 | + let mut tracked_pass = TrackedRenderPass::new(render_pass); |
| 119 | + for item in alpha_mask_phase.items.iter() { |
| 120 | + let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); |
| 121 | + draw_function.draw(world, &mut tracked_pass, view_entity, item); |
| 122 | + } |
96 | 123 | }
|
| 124 | + |
| 125 | + { |
| 126 | + // Run the transparent pass, sorted back-to-front |
| 127 | + // NOTE: Scoped to drop the mutable borrow of render_context |
| 128 | + let pass_descriptor = RenderPassDescriptor { |
| 129 | + label: Some("main_transparent_pass_3d"), |
| 130 | + // NOTE: The transparent pass loads the color buffer as well as overwriting it where appropriate. |
| 131 | + color_attachments: &[target.get_color_attachment(Operations { |
| 132 | + load: LoadOp::Load, |
| 133 | + store: true, |
| 134 | + })], |
| 135 | + depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { |
| 136 | + view: &depth.view, |
| 137 | + // NOTE: For the transparent pass we load the depth buffer but do not write to it. |
| 138 | + // As the opaque and alpha mask passes run first, opaque meshes can occlude |
| 139 | + // transparent ones. |
| 140 | + depth_ops: Some(Operations { |
| 141 | + load: LoadOp::Load, |
| 142 | + store: false, |
| 143 | + }), |
| 144 | + stencil_ops: None, |
| 145 | + }), |
| 146 | + }; |
| 147 | + |
| 148 | + let draw_functions = world |
| 149 | + .get_resource::<DrawFunctions<Transparent3d>>() |
| 150 | + .unwrap(); |
| 151 | + |
| 152 | + let render_pass = render_context |
| 153 | + .command_encoder |
| 154 | + .begin_render_pass(&pass_descriptor); |
| 155 | + let mut draw_functions = draw_functions.write(); |
| 156 | + let mut tracked_pass = TrackedRenderPass::new(render_pass); |
| 157 | + for item in transparent_phase.items.iter() { |
| 158 | + let draw_function = draw_functions.get_mut(item.draw_function).unwrap(); |
| 159 | + draw_function.draw(world, &mut tracked_pass, view_entity, item); |
| 160 | + } |
| 161 | + } |
| 162 | + |
97 | 163 | Ok(())
|
98 | 164 | }
|
99 | 165 | }
|
0 commit comments