Skip to content

Commit ae7c3c0

Browse files
committed
Correctly implement background fullscreen quad.
1 parent 44c6fd4 commit ae7c3c0

File tree

4 files changed

+111
-35
lines changed

4 files changed

+111
-35
lines changed

crates/processing_render/src/render/mod.rs

Lines changed: 98 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ pub mod primitive;
55
pub mod transform;
66

77
use bevy::{
8-
camera::visibility::RenderLayers, ecs::system::SystemParam, math::Affine3A, prelude::*,
8+
camera::visibility::RenderLayers,
9+
ecs::system::SystemParam,
10+
math::{Affine3A, Mat4, Vec4},
11+
prelude::*,
912
};
1013
use command::{CommandBuffer, DrawCommand};
1114
use material::MaterialKey;
1215
use primitive::{TessellationMode, empty_mesh};
1316
use transform::TransformStack;
1417

15-
use crate::{
16-
Flush, geometry::Geometry, graphics::SurfaceSize, image::Image, render::primitive::rect,
17-
};
18+
use crate::{Flush, geometry::Geometry, image::Image, render::primitive::rect};
1819

1920
#[derive(Component)]
2021
#[relationship(relationship_target = TransientMeshes)]
@@ -94,16 +95,26 @@ pub fn flush_draw_commands(
9495
&mut CommandBuffer,
9596
&mut RenderState,
9697
&RenderLayers,
97-
&SurfaceSize,
98+
&Projection,
99+
&Transform,
98100
),
99101
With<Flush>,
100102
>,
101103
p_images: Query<&Image>,
102104
p_geometries: Query<&Geometry>,
103105
) {
104-
for (graphics_entity, mut cmd_buffer, mut state, render_layers, SurfaceSize(width, height)) in
105-
graphics.iter_mut()
106+
for (
107+
graphics_entity,
108+
mut cmd_buffer,
109+
mut state,
110+
render_layers,
111+
projection,
112+
camera_transform,
113+
) in graphics.iter_mut()
106114
{
115+
let clip_from_view = projection.get_clip_from_view();
116+
let view_from_world = camera_transform.to_matrix().inverse();
117+
let world_from_clip = (clip_from_view * view_from_world).inverse();
107118
let draw_commands = std::mem::take(&mut cmd_buffer.commands);
108119
let mut batch = BatchState::new(graphics_entity, render_layers.clone());
109120

@@ -143,18 +154,26 @@ pub fn flush_draw_commands(
143154
});
144155
}
145156
DrawCommand::BackgroundColor(color) => {
146-
add_fill(&mut res, &mut batch, &state, |mesh, _| {
147-
rect(
148-
mesh,
149-
0.0,
150-
0.0,
151-
*width as f32,
152-
*height as f32,
153-
[0.0; 4],
154-
color,
155-
TessellationMode::Fill,
156-
)
157-
});
157+
flush_batch(&mut res, &mut batch);
158+
159+
let mesh = create_ndc_background_quad(world_from_clip, color, false);
160+
let mesh_handle = res.meshes.add(mesh);
161+
162+
let material_key = MaterialKey {
163+
transparent: color.alpha() < 1.0,
164+
background_image: None,
165+
};
166+
let material_handle = res.materials.add(material_key.to_material());
167+
168+
res.commands.spawn((
169+
Mesh3d(mesh_handle),
170+
MeshMaterial3d(material_handle),
171+
BelongsToGraphics(batch.graphics_entity),
172+
Transform::IDENTITY,
173+
batch.render_layers.clone(),
174+
));
175+
176+
batch.draw_index += 1;
158177
}
159178
DrawCommand::BackgroundImage(entity) => {
160179
let Some(p_image) = p_images.get(entity).ok() else {
@@ -164,28 +183,24 @@ pub fn flush_draw_commands(
164183

165184
flush_batch(&mut res, &mut batch);
166185

186+
let mesh = create_ndc_background_quad(world_from_clip, Color::WHITE, true);
187+
let mesh_handle = res.meshes.add(mesh);
188+
167189
let material_key = MaterialKey {
168190
transparent: false,
169191
background_image: Some(p_image.handle.clone()),
170192
};
193+
let material_handle = res.materials.add(material_key.to_material());
171194

172-
batch.material_key = Some(material_key);
173-
batch.current_mesh = Some(empty_mesh());
174-
175-
if let Some(ref mut mesh) = batch.current_mesh {
176-
rect(
177-
mesh,
178-
0.0,
179-
0.0,
180-
*width as f32,
181-
*height as f32,
182-
[0.0; 4],
183-
Color::WHITE,
184-
TessellationMode::Fill,
185-
)
186-
}
195+
res.commands.spawn((
196+
Mesh3d(mesh_handle),
197+
MeshMaterial3d(material_handle),
198+
BelongsToGraphics(batch.graphics_entity),
199+
Transform::IDENTITY,
200+
batch.render_layers.clone(),
201+
));
187202

188-
flush_batch(&mut res, &mut batch);
203+
batch.draw_index += 1;
189204
}
190205
DrawCommand::PushMatrix => state.transform.push(),
191206
DrawCommand::PopMatrix => state.transform.pop(),
@@ -348,3 +363,51 @@ fn flush_batch(res: &mut RenderResources, batch: &mut BatchState) {
348363
}
349364
batch.material_key = None;
350365
}
366+
367+
/// Creates a fullscreen quad by transforming NDC fullscreen by inverse of the clip-from-world matrix
368+
/// so that when the vertex shader applies clip_from_world, the vertices end up correctly back in
369+
/// NDC space.
370+
fn create_ndc_background_quad(world_from_clip: Mat4, color: Color, with_uvs: bool) -> Mesh {
371+
use bevy::asset::RenderAssetUsages;
372+
use bevy::mesh::{Indices, PrimitiveTopology};
373+
374+
let ndc_z = 0.001; // near far plane (bevy uses reverse-z)
375+
let ndc_corners = [
376+
Vec4::new(-1.0, -1.0, ndc_z, 1.0), // bl
377+
Vec4::new(1.0, -1.0, ndc_z, 1.0), // br
378+
Vec4::new(1.0, 1.0, ndc_z, 1.0), // tr
379+
Vec4::new(-1.0, 1.0, ndc_z, 1.0), // tl
380+
];
381+
382+
let world_positions: Vec<[f32; 3]> = ndc_corners
383+
.iter()
384+
.map(|ndc| {
385+
let world = world_from_clip * *ndc;
386+
[world.x / world.w, world.y / world.w, world.z / world.w]
387+
})
388+
.collect();
389+
390+
let uvs: Vec<[f32; 2]> = vec![
391+
[0.0, 1.0], // bl
392+
[1.0, 1.0], // br
393+
[1.0, 0.0], // tr
394+
[0.0, 0.0], // tl
395+
];
396+
397+
let color_array: [f32; 4] = color.to_linear().to_f32_array();
398+
let colors: Vec<[f32; 4]> = vec![color_array; 4];
399+
400+
// two tris
401+
let indices: Vec<u32> = vec![0, 1, 2, 0, 2, 3];
402+
403+
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default());
404+
405+
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, world_positions);
406+
mesh.insert_attribute(Mesh::ATTRIBUTE_COLOR, colors);
407+
if with_uvs {
408+
mesh.insert_attribute(Mesh::ATTRIBUTE_UV_0, uvs);
409+
}
410+
mesh.insert_indices(Indices::U32(indices));
411+
412+
mesh
413+
}

examples/animated_mesh.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ fn sketch() -> error::Result<()> {
8686
}
8787

8888
graphics_begin_draw(graphics)?;
89+
graphics_record_command(
90+
graphics,
91+
DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.05, 0.05, 0.1)),
92+
)?;
8993
graphics_record_command(graphics, DrawCommand::Geometry(mesh))?;
9094
graphics_end_draw(graphics)?;
9195

examples/box.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ fn sketch() -> error::Result<()> {
3838
while glfw_ctx.poll_events() {
3939
graphics_begin_draw(graphics)?;
4040

41+
graphics_record_command(
42+
graphics,
43+
DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.1, 0.1, 0.15)),
44+
)?;
45+
4146
graphics_record_command(graphics, DrawCommand::PushMatrix)?;
4247
graphics_record_command(graphics, DrawCommand::Rotate { angle })?;
4348
graphics_record_command(graphics, DrawCommand::Geometry(box_geo))?;

examples/custom_attribute.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ fn sketch() -> error::Result<()> {
6363

6464
while glfw_ctx.poll_events() {
6565
graphics_begin_draw(graphics)?;
66+
graphics_record_command(
67+
graphics,
68+
DrawCommand::BackgroundColor(bevy::color::Color::srgb(0.1, 0.1, 0.12)),
69+
)?;
6670
graphics_record_command(graphics, DrawCommand::Geometry(mesh))?;
6771
graphics_end_draw(graphics)?;
6872
}

0 commit comments

Comments
 (0)