From 17005b3c8bc7d90fce964ac3a12cbe6a5a585303 Mon Sep 17 00:00:00 2001 From: Rob Parrett Date: Tue, 12 Mar 2024 18:21:10 -0700 Subject: [PATCH] Fix blurry text (#12429) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective Fixes #12064 ## Solution Prior to #11326, the "global physical" translation of text was rounded. After #11326, only the "offset" is being rounded. This moves things around so that the "global translation" is converted to physical pixels, rounded, and then converted back to logical pixels, which is what I believe was happening before / what the comments above describe. ## Discussion This seems to work and fix an obvious mistake in some code, but I don't fully grok the ui / text pipelines / math here. ## Before / After and test example
Expand Code ```rust use std::f32::consts::FRAC_PI_2; use bevy::prelude::*; use bevy_internal::window::WindowResolution; const FONT_SIZE: f32 = 25.0; const PADDING: f32 = 5.0; fn main() { App::new() .add_plugins( DefaultPlugins.set(WindowPlugin { primary_window: Some(Window { resolution: WindowResolution::default().with_scale_factor_override(1.0), ..default() }), ..default() }), //.set(ImagePlugin::default_nearest()), ) .add_systems(Startup, setup) .run(); } fn setup(mut commands: Commands, asset_server: Res) { commands.spawn(Camera2dBundle::default()); let font = asset_server.load("fonts/FiraSans-Bold.ttf"); for x in [20.5, 140.0] { for i in 1..10 { text( &mut commands, font.clone(), x, (FONT_SIZE + PADDING) * i as f32, i, Quat::default(), 1.0, ); } } for x in [450.5, 700.0] { for i in 1..10 { text( &mut commands, font.clone(), x, ((FONT_SIZE * 2.0) + PADDING) * i as f32, i, Quat::default(), 2.0, ); } } for y in [400.0, 600.0] { for i in 1..10 { text( &mut commands, font.clone(), (FONT_SIZE + PADDING) * i as f32, y, i, Quat::from_rotation_z(FRAC_PI_2), 1.0, ); } } } fn text( commands: &mut Commands, font: Handle, x: f32, y: f32, i: usize, rot: Quat, scale: f32, ) { let text = (65..(65 + i)).map(|a| a as u8 as char).collect::(); commands.spawn(TextBundle { style: Style { position_type: PositionType::Absolute, left: Val::Px(x), top: Val::Px(y), ..default() }, text: Text::from_section( text, TextStyle { font, font_size: FONT_SIZE, ..default() }, ), transform: Transform::from_rotation(rot).with_scale(Vec2::splat(scale).extend(1.)), ..default() }); } ```
Open both images in new tabs and swap back and forth. Pay attention to the "A" and "ABCD" lines.
Before main3
After pr3
--------- Co-authored-by: François Mockers --- crates/bevy_ui/src/render/mod.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index 8ff453b7404d6..4112895a5baf5 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -596,10 +596,13 @@ pub fn extract_text_uinodes( // * Multiply by the rounded physical position by the inverse scale factor to return to logical coordinates let logical_top_left = -0.5 * uinode.size(); - let physical_nearest_pixel = (logical_top_left * scale_factor).round(); - let logical_top_left_nearest_pixel = physical_nearest_pixel * inverse_scale_factor; - let transform = Mat4::from(global_transform.affine()) - * Mat4::from_translation(logical_top_left_nearest_pixel.extend(0.)); + + let mut transform = global_transform.affine() + * bevy_math::Affine3A::from_translation(logical_top_left.extend(0.)); + + transform.translation *= scale_factor; + transform.translation = transform.translation.round(); + transform.translation *= inverse_scale_factor; let mut color = Color::WHITE; let mut current_section = usize::MAX;