Description
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.