bevyengine / bevyengine/bevy

UI clipping only works for untransformed axis-aligned rectangles.

Open
#9,381 0 comments 1 reaction 0 assignees View on GitHub
A-UI C-Feature S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.