Skip to content

UI clipping only works for untransformed axis-aligned rectangles. #9381

Open
@ickshonpe

Description

@ickshonpe

Bevy version

All Bevy versions.

What is wrong

The CalculatedClip component wraps a clip: Rect field that defines the viewable area in absolute logical coordinates, where anything outside that Rect is clipped. No clipping is performed if the CalculatedClip component is not present on a UI node entity.

CalculatedClip components aren't part of any UI node bundle and are added automatically to UI node entities. Users control clipping using the Overflow style property:

  • overflow: Overflow::clip_x() clips all items that overflow the node on the x-axis.
  • overflow: Overflow::clip_y() clips all items that overflow the node on the y-axis.
  • overflow: Overflow::cip() clips overflowing items on both axis.

The system that manages this is update_clipping_system.

The major problems are:

  • The clipping Rect's size takes its bounds from the unscaled size of the UI node. If the UI node's Transform has a scaling it will be clipped incorrectly. If the scaling on an axis is greater than 1, the node's content could exceed the bounds on that axis without being clipped, and with a scaling of less than 1 content could be clipped despite being completely within the clipping bounds.

  • If the node's transform has a rotation prepare_ui_nodes attempts to clip its content as though the content is unrotated, resulting in a distorted mess due to incorrect UV coordinates.

What solution would you like?

The clipping-scaling issues should be fixable by applying the node entity's scale to the size of the clipping Rect.

Rotation is much more difficult. A minimal fix would be just to ignore the Overflow setting for any UI node with a rotation and its descendants. I think it doesn't make sense to allow rotation of individual UI nodes though and that the option to do this should be removed. Taffy only supports axis-aligned nodes. Instead with support for multiple layouts, each UI layout could have its own rotation that applies to all its nodes (so an entire layout can be rotated but all the nodes in that layout are aligned with each other).

Clipping of rotated content does seem like something we should support. There seem to be a couple of approaches but I don't know enough about rendering to know which is best:

  • Pass in the clipping rect as a uniform and discard any fragments outside. Seems simple to implement with minimal changes, but it might not be very efficient?
  • Use a stencil buffer, might be overkill if the clipping regions are always axis-aligned rectangles?
  • Use a depth buffer with the UI stack indices.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-UIGraphical user interfaces, styles, layouts, and widgetsC-FeatureA new feature, making something new possibleS-Needs-DesignThis issue requires design work to think about how it would best be accomplished

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions