Skip to content

Commit 5e444b3

Browse files
authored
Correctly implement background fullscreen quad. (#50)
1 parent 44c6fd4 commit 5e444b3

File tree

4 files changed

+107
-34
lines changed

4 files changed

+107
-34
lines changed

crates/processing_render/src/render/mod.rs

Lines changed: 94 additions & 34 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,20 @@ 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
106+
for (graphics_entity, mut cmd_buffer, mut state, render_layers, projection, camera_transform) in
105107
graphics.iter_mut()
106108
{
109+
let clip_from_view = projection.get_clip_from_view();
110+
let view_from_world = camera_transform.to_matrix().inverse();
111+
let world_from_clip = (clip_from_view * view_from_world).inverse();
107112
let draw_commands = std::mem::take(&mut cmd_buffer.commands);
108113
let mut batch = BatchState::new(graphics_entity, render_layers.clone());
109114

@@ -143,18 +148,26 @@ pub fn flush_draw_commands(
143148
});
144149
}
145150
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-
});
151+
flush_batch(&mut res, &mut batch);
152+
153+
let mesh = create_ndc_background_quad(world_from_clip, color, false);
154+
let mesh_handle = res.meshes.add(mesh);
155+
156+
let material_key = MaterialKey {
157+
transparent: color.alpha() < 1.0,
158+
background_image: None,
159+
};
160+
let material_handle = res.materials.add(material_key.to_material());
161+
162+
res.commands.spawn((
163+
Mesh3d(mesh_handle),
164+
MeshMaterial3d(material_handle),
165+
BelongsToGraphics(batch.graphics_entity),
166+
Transform::IDENTITY,
167+
batch.render_layers.clone(),
168+
));
169+
170+
batch.draw_index += 1;
158171
}
159172
DrawCommand::BackgroundImage(entity) => {
160173
let Some(p_image) = p_images.get(entity).ok() else {
@@ -164,28 +177,24 @@ pub fn flush_draw_commands(
164177

165178
flush_batch(&mut res, &mut batch);
166179

180+
let mesh = create_ndc_background_quad(world_from_clip, Color::WHITE, true);
181+
let mesh_handle = res.meshes.add(mesh);
182+
167183
let material_key = MaterialKey {
168184
transparent: false,
169185
background_image: Some(p_image.handle.clone()),
170186
};
187+
let material_handle = res.materials.add(material_key.to_material());
171188

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-
}
189+
res.commands.spawn((
190+
Mesh3d(mesh_handle),
191+
MeshMaterial3d(material_handle),
192+
BelongsToGraphics(batch.graphics_entity),
193+
Transform::IDENTITY,
194+
batch.render_layers.clone(),
195+
));
187196

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

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)