mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
Fix 2D looking blurry at odd window sizes (#13440)
# Objective This is a long-standing bug that I have experienced since many versions of Bevy ago, possibly forever. Today I finally wanted to report it, but the fix was so easy that I just went and fixed it. :) The problem is that 2D graphics looks blurry at odd-sized window resolutions. This is with the **default** 2D camera configuration! The issue will also manifest itself with any Orthographic Projection with `ScalingMode::WindowSize` where the viewport origin is not at one of the corners, such as the default where the origin point is at the center. The issue happens because the Bevy orthographic projection origin point is specified as a fraction to be multiplied by the size. For example, the default (origin at center) is `(0.5, 0.5)`. When this value is multiplied by the window size, it can result in fractional values for the actual origin of the projection, thus placing the camera "between pixels" and misaligning the entire pixel grid. With the default value, this happens at odd-numbered window resolutions. It is very easy to reproduce the issue by running any Bevy 2D app with a resizable window, and slowly resizing the window pixel by pixel. As you move the mouse to resize the window, you can see how the 2D graphics inside the window alternate between "crisp, blurry, crisp, blurry, ...". If you change the projection's origin to be at the corner (say, `(0.0, 0.0)`) and run the app again, the graphics always looks crisp, regardless of window size. Here are screenshots from **before** this PR, to illustrate the issue: Even window size: ![Screenshot_20240520_165304](https://github.com/bevyengine/bevy/assets/40234599/52619281-cf5f-490e-b85e-22bc5f9af737) Odd window size: ![Screenshot_20240520_165320](https://github.com/bevyengine/bevy/assets/40234599/27a3624c-f39e-4493-ade9-ca3533802083) ## Solution The solution is easy: just round the computed origin values for the projection. To make it work reliably for the general case, I decided to: - Only do it for `ScalingMode::WindowSize`, as it doesn't make sense for other scaling modes. - Round to the nearest multiple of the pixel scale, if it is not 1.0. This ensures the "pixels" stay aligned even if scaled. ## Testing I ran Bevy's examples as well as my own projects to ensure things look correct. I set different values for the pixel scale to test the rounding behavior and played around with resizing the window to verify that everything is consistent. --- ## Changelog Fixed: - Orthographic projection now rounds the origin point if computed from screen pixels, so that 2D graphics do not appear blurry at odd window sizes.
This commit is contained in:
parent
182fe3292e
commit
60afec2a00
1 changed files with 10 additions and 2 deletions
|
@ -440,8 +440,16 @@ impl CameraProjection for OrthographicProjection {
|
||||||
ScalingMode::Fixed { width, height } => (width, height),
|
ScalingMode::Fixed { width, height } => (width, height),
|
||||||
};
|
};
|
||||||
|
|
||||||
let origin_x = projection_width * self.viewport_origin.x;
|
let mut origin_x = projection_width * self.viewport_origin.x;
|
||||||
let origin_y = projection_height * self.viewport_origin.y;
|
let mut origin_y = projection_height * self.viewport_origin.y;
|
||||||
|
|
||||||
|
// If projection is based on window pixels,
|
||||||
|
// ensure we don't end up with fractional pixels!
|
||||||
|
if let ScalingMode::WindowSize(pixel_scale) = self.scaling_mode {
|
||||||
|
// round to nearest multiple of `pixel_scale`
|
||||||
|
origin_x = (origin_x * pixel_scale).round() / pixel_scale;
|
||||||
|
origin_y = (origin_y * pixel_scale).round() / pixel_scale;
|
||||||
|
}
|
||||||
|
|
||||||
self.area = Rect::new(
|
self.area = Rect::new(
|
||||||
self.scale * -origin_x,
|
self.scale * -origin_x,
|
||||||
|
|
Loading…
Reference in a new issue