Text2d render quality (#1171)
improve quality of text2d rendering * remove coordinate tweaking in sprite-sheet shader * fixes glyph shimmering of animated text * reposition glyph before passing it to ab_glyph to normalize its rendering The result of layout of sequence of glyphs causes individuals to have fractional positions, but since glyph renderings are reused for future instances of that glyph, this produces errors. This change accepts the errors but repositions the glyph to "0, 0" in an effort to get the cleanest possible rendering.
This commit is contained in:
parent
a01f22e0c5
commit
b8fb462eff
@ -45,7 +45,7 @@ void main() {
|
|||||||
vec2(sprite_rect.end.x, sprite_rect.begin.y),
|
vec2(sprite_rect.end.x, sprite_rect.begin.y),
|
||||||
sprite_rect.end
|
sprite_rect.end
|
||||||
);
|
);
|
||||||
v_Uv = (atlas_positions[gl_VertexIndex] + vec2(0.01, 0.01)) / AtlasSize;
|
v_Uv = (atlas_positions[gl_VertexIndex]) / AtlasSize;
|
||||||
v_Color = TextureAtlasSprite_color;
|
v_Color = TextureAtlasSprite_color;
|
||||||
gl_Position = ViewProj * SpriteTransform * vec4(ceil(vertex_position), 1.0);
|
gl_Position = ViewProj * SpriteTransform * vec4(vertex_position, 1.0);
|
||||||
}
|
}
|
@ -23,6 +23,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.4.0", features = ["bevy"
|
|||||||
bevy_render = { path = "../bevy_render", version = "0.4.0" }
|
bevy_render = { path = "../bevy_render", version = "0.4.0" }
|
||||||
bevy_sprite = { path = "../bevy_sprite", version = "0.4.0" }
|
bevy_sprite = { path = "../bevy_sprite", version = "0.4.0" }
|
||||||
bevy_transform = { path = "../bevy_transform", version = "0.4.0" }
|
bevy_transform = { path = "../bevy_transform", version = "0.4.0" }
|
||||||
|
bevy_window = { path = "../bevy_window", version = "0.4.0" }
|
||||||
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
bevy_utils = { path = "../bevy_utils", version = "0.4.0" }
|
||||||
|
|
||||||
# other
|
# other
|
||||||
|
@ -73,8 +73,16 @@ impl GlyphBrush {
|
|||||||
|
|
||||||
let mut positioned_glyphs = Vec::new();
|
let mut positioned_glyphs = Vec::new();
|
||||||
for sg in glyphs {
|
for sg in glyphs {
|
||||||
let glyph_id = sg.glyph.id;
|
let SectionGlyph {
|
||||||
if let Some(outlined_glyph) = font.font.outline_glyph(sg.glyph) {
|
section_index: _,
|
||||||
|
byte_index: _,
|
||||||
|
mut glyph,
|
||||||
|
font_id: _,
|
||||||
|
} = sg;
|
||||||
|
let glyph_id = glyph.id;
|
||||||
|
let base_x = glyph.position.x.floor();
|
||||||
|
glyph.position.x = 0.;
|
||||||
|
if let Some(outlined_glyph) = font.font.outline_glyph(glyph) {
|
||||||
let bounds = outlined_glyph.px_bounds();
|
let bounds = outlined_glyph.px_bounds();
|
||||||
let handle_font_atlas: Handle<FontAtlasSet> = handle.as_weak();
|
let handle_font_atlas: Handle<FontAtlasSet> = handle.as_weak();
|
||||||
let font_atlas_set = font_atlas_set_storage
|
let font_atlas_set = font_atlas_set_storage
|
||||||
@ -92,10 +100,10 @@ impl GlyphBrush {
|
|||||||
let glyph_width = glyph_rect.width();
|
let glyph_width = glyph_rect.width();
|
||||||
let glyph_height = glyph_rect.height();
|
let glyph_height = glyph_rect.height();
|
||||||
|
|
||||||
let x = bounds.min.x + glyph_width / 2.0 - min_x;
|
let x = base_x + bounds.min.x + glyph_width / 2.0 - min_x;
|
||||||
// the 0.5 accounts for odd-numbered heights (bump up by 1 pixel)
|
// the 0.5 accounts for odd-numbered heights (bump up by 1 pixel)
|
||||||
// max_y = text block height, and up is negative (whereas for transform, up is positive)
|
// max_y = text block height, and up is negative (whereas for transform, up is positive)
|
||||||
let y = max_y - bounds.max.y + glyph_height / 2.0 + 0.5;
|
let y = max_y - bounds.max.y + glyph_height / 2.0;
|
||||||
let position = Vec2::new(x, y);
|
let position = Vec2::new(x, y);
|
||||||
|
|
||||||
positioned_glyphs.push(PositionedGlyph {
|
positioned_glyphs.push(PositionedGlyph {
|
||||||
|
@ -10,6 +10,7 @@ use bevy_render::{
|
|||||||
};
|
};
|
||||||
use bevy_sprite::{TextureAtlas, QUAD_HANDLE};
|
use bevy_sprite::{TextureAtlas, QUAD_HANDLE};
|
||||||
use bevy_transform::prelude::{GlobalTransform, Transform};
|
use bevy_transform::prelude::{GlobalTransform, Transform};
|
||||||
|
use bevy_window::Windows;
|
||||||
use glyph_brush_layout::{HorizontalAlign, VerticalAlign};
|
use glyph_brush_layout::{HorizontalAlign, VerticalAlign};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -56,6 +57,7 @@ pub fn draw_text2d_system(
|
|||||||
mut context: DrawContext,
|
mut context: DrawContext,
|
||||||
msaa: Res<Msaa>,
|
msaa: Res<Msaa>,
|
||||||
meshes: Res<Assets<Mesh>>,
|
meshes: Res<Assets<Mesh>>,
|
||||||
|
windows: Res<Windows>,
|
||||||
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
mut render_resource_bindings: ResMut<RenderResourceBindings>,
|
||||||
text_pipeline: Res<DefaultTextPipeline>,
|
text_pipeline: Res<DefaultTextPipeline>,
|
||||||
mut query: Query<
|
mut query: Query<
|
||||||
@ -73,6 +75,12 @@ pub fn draw_text2d_system(
|
|||||||
let font_quad = meshes.get(&QUAD_HANDLE).unwrap();
|
let font_quad = meshes.get(&QUAD_HANDLE).unwrap();
|
||||||
let vertex_buffer_descriptor = font_quad.get_vertex_buffer_descriptor();
|
let vertex_buffer_descriptor = font_quad.get_vertex_buffer_descriptor();
|
||||||
|
|
||||||
|
let scale_factor = if let Some(window) = windows.get_primary() {
|
||||||
|
window.scale_factor() as f32
|
||||||
|
} else {
|
||||||
|
1.
|
||||||
|
};
|
||||||
|
|
||||||
for (entity, mut draw, visible, text, global_transform, calculated_size) in query.iter_mut() {
|
for (entity, mut draw, visible, text, global_transform, calculated_size) in query.iter_mut() {
|
||||||
if !visible.is_visible {
|
if !visible.is_visible {
|
||||||
continue;
|
continue;
|
||||||
@ -99,7 +107,7 @@ pub fn draw_text2d_system(
|
|||||||
msaa: &msaa,
|
msaa: &msaa,
|
||||||
text_glyphs: &text_glyphs.glyphs,
|
text_glyphs: &text_glyphs.glyphs,
|
||||||
font_quad_vertex_descriptor: &vertex_buffer_descriptor,
|
font_quad_vertex_descriptor: &vertex_buffer_descriptor,
|
||||||
scale_factor: 1.,
|
scale_factor,
|
||||||
style: &text.style,
|
style: &text.style,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -114,10 +122,12 @@ pub struct QueuedText2d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the TextGlyphs with the new computed glyphs from the layout
|
/// Updates the TextGlyphs with the new computed glyphs from the layout
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn text2d_system(
|
pub fn text2d_system(
|
||||||
mut queued_text: Local<QueuedText2d>,
|
mut queued_text: Local<QueuedText2d>,
|
||||||
mut textures: ResMut<Assets<Texture>>,
|
mut textures: ResMut<Assets<Texture>>,
|
||||||
fonts: Res<Assets<Font>>,
|
fonts: Res<Assets<Font>>,
|
||||||
|
windows: Res<Windows>,
|
||||||
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
|
||||||
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
mut font_atlas_set_storage: ResMut<Assets<FontAtlasSet>>,
|
||||||
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
mut text_pipeline: ResMut<DefaultTextPipeline>,
|
||||||
@ -135,6 +145,12 @@ pub fn text2d_system(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let scale_factor = if let Some(window) = windows.get_primary() {
|
||||||
|
window.scale_factor()
|
||||||
|
} else {
|
||||||
|
1.
|
||||||
|
};
|
||||||
|
|
||||||
// Computes all text in the local queue
|
// Computes all text in the local queue
|
||||||
let mut new_queue = Vec::new();
|
let mut new_queue = Vec::new();
|
||||||
let query = text_queries.q1_mut();
|
let query = text_queries.q1_mut();
|
||||||
@ -145,7 +161,7 @@ pub fn text2d_system(
|
|||||||
text.font.clone(),
|
text.font.clone(),
|
||||||
&fonts,
|
&fonts,
|
||||||
&text.value,
|
&text.value,
|
||||||
text.style.font_size,
|
scale_value(text.style.font_size, scale_factor),
|
||||||
text.style.alignment,
|
text.style.alignment,
|
||||||
Size::new(f32::MAX, f32::MAX),
|
Size::new(f32::MAX, f32::MAX),
|
||||||
&mut *font_atlas_set_storage,
|
&mut *font_atlas_set_storage,
|
||||||
@ -163,7 +179,10 @@ pub fn text2d_system(
|
|||||||
let text_layout_info = text_pipeline.get_glyphs(&entity).expect(
|
let text_layout_info = text_pipeline.get_glyphs(&entity).expect(
|
||||||
"Failed to get glyphs from the pipeline that have just been computed",
|
"Failed to get glyphs from the pipeline that have just been computed",
|
||||||
);
|
);
|
||||||
calculated_size.size = text_layout_info.size;
|
calculated_size.size = Size {
|
||||||
|
width: scale_value(text_layout_info.size.width, 1. / scale_factor),
|
||||||
|
height: scale_value(text_layout_info.size.height, 1. / scale_factor),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,3 +190,7 @@ pub fn text2d_system(
|
|||||||
|
|
||||||
queued_text.entities = new_queue;
|
queued_text.entities = new_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scale_value(value: f32, factor: f64) -> f32 {
|
||||||
|
(value as f64 * factor) as f32
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user