Browse Source

Merge pull request #93786 from alvinhochun/viewport-pixel-snap-fix

Apply "snap 2D transforms to pixel" to viewport
Rémi Verschelde 11 months ago
parent
commit
73bf121ceb
2 changed files with 22 additions and 1 deletions
  1. 5 1
      scene/2d/parallax_2d.cpp
  2. 17 0
      servers/rendering/renderer_viewport.cpp

+ 5 - 1
scene/2d/parallax_2d.cpp

@@ -83,7 +83,11 @@ void Parallax2D::_validate_property(PropertyInfo &p_property) const {
 void Parallax2D::_camera_moved(const Transform2D &p_transform, const Point2 &p_screen_offset, const Point2 &p_adj_screen_pos) {
 	if (!ignore_camera_scroll) {
 		if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) {
-			set_screen_offset((p_adj_screen_pos + Vector2(0.5, 0.5)).floor());
+			Size2 vps = get_viewport_rect().size;
+			Vector2 offset;
+			offset.x = ((int)vps.width % 2) ? 0.0 : 0.5;
+			offset.y = ((int)vps.height % 2) ? 0.0 : 0.5;
+			set_screen_offset((p_adj_screen_pos + offset).floor());
 		} else {
 			set_screen_offset(p_adj_screen_pos);
 		}

+ 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) {