Selaa lähdekoodia

Apply snap 2D transforms to pixel to viewport

We shall not leave the viewport transform to be rounded by the code for
rounding canvas items. Since the viewport transform is inverse to the
camera transform, we get incorrect rounding at the halfway point that
misaligns the viewport and the canvas item which the camera is
following.

Instead, reintroduce viewport rounding, but do it in a way that matches
the rounding of canvas items. Also take into account the half-pixel
offset of the centre point when viewport dimension is not divisible by
two.  For `CanvasLayer`s that follows viewport, take into account the
scale when rounding. Overall this should work better compared to the
rounding in Godot 4.2 (and earlier).
Alvin Wong 1 vuosi sitten
vanhempi
commit
1bd66af54c
1 muutettua tiedostoa jossa 17 lisäystä ja 0 poistoa
  1. 17 0
      servers/rendering/renderer_viewport.cpp

+ 17 - 0
servers/rendering/renderer_viewport.cpp

@@ -41,14 +41,31 @@
 static Transform2D _canvas_get_transform(RendererViewport::Viewport *p_viewport, RendererCanvasCull::Canvas *p_canvas, RendererViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) {
 	Transform2D xf = p_viewport->global_transform;
 
+	Vector2 pixel_snap_offset;
+	if (p_viewport->snap_2d_transforms_to_pixel) {
+		// We use `floor(p + 0.5)` to snap canvas items, but `ceil(p - 0.5)`
+		// to snap viewport transform because the viewport transform is inverse
+		// to the camera transform. Also, if the viewport size is not divisible
+		// by 2, the center point is offset by 0.5 px and we need to add 0.5
+		// before rounding to cancel it out.
+		pixel_snap_offset.x = (p_viewport->size.width % 2) ? 0.0 : -0.5;
+		pixel_snap_offset.y = (p_viewport->size.height % 2) ? 0.0 : -0.5;
+	}
+
 	float scale = 1.0;
 	if (p_viewport->canvas_map.has(p_canvas->parent)) {
 		Transform2D c_xform = p_viewport->canvas_map[p_canvas->parent].transform;
+		if (p_viewport->snap_2d_transforms_to_pixel) {
+			c_xform.columns[2] = (c_xform.columns[2] * p_canvas->parent_scale + pixel_snap_offset).ceil() / p_canvas->parent_scale;
+		}
 		xf = xf * c_xform;
 		scale = p_canvas->parent_scale;
 	}
 
 	Transform2D c_xform = p_canvas_data->transform;
+	if (p_viewport->snap_2d_transforms_to_pixel) {
+		c_xform.columns[2] = (c_xform.columns[2] + pixel_snap_offset).ceil();
+	}
 	xf = xf * c_xform;
 
 	if (scale != 1.0 && !RSG::canvas->disable_scale) {