UI CPU clipping implementation supporting rotation and scaling#24148
UI CPU clipping implementation supporting rotation and scaling#24148ickshonpe wants to merge 31 commits into
Conversation
`CalculatedClip` is now an enum with `Rects` and `FullyClipped` variants. `Rects` holds a list of `Rect` in node local coords and `Affine2` world-to-local transform. `bevy_ui_render` has a new `clipping` module with a `clip_polygon` function that intersects UI elements with the clipping rects and chops off the non-visible regions and returns a list of vertices that forms a triangle fan. New example `overflow_transform`.
| @@ -0,0 +1,132 @@ | |||
| //! Demonstrates nested transformed UI clipping. | |||
There was a problem hiding this comment.
I think this probably belongs in testbed. It's a great test, but not very educational.
There was a problem hiding this comment.
Yeah maybe, I might expand it further though.
There was a problem hiding this comment.
kk! It's also fancy enough that I don't mind it being in the main examples.
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
…into overflow-transform
|
It looks like your PR has been selected for a highlight in the next release blog post, but you didn't provide a release note. Please review the instructions for writing release notes, then expand or revise the content in the release notes directory to showcase your changes. |
…into overflow-transform
…into overflow-transform
…ate function with the value taken from the parley `Layout`, not the caller. * `TextLayoutInfo::size` should be in physical pixels, like the rest of the layout properties, and, again, set b he text layout update function, not the caller.
| @@ -0,0 +1,133 @@ | |||
| //! Demonstrates nested transformed UI clipping. | |||
There was a problem hiding this comment.
This could be clearer. We should actually describe what this supports, and why it matters for users.
| wasm = true | ||
|
|
||
| [[example]] | ||
| name = "overflow_transform" |
There was a problem hiding this comment.
This is a weak name: at a glance even I have trouble understanding what this is trying to teach or why I might care.
alice-i-cecile
left a comment
There was a problem hiding this comment.
I've finally had a chance to review this. Very on-board! Performed basic testing and did not spot any bugs or architectural concerns, but we all know how well code review works for that.
This needs a release note still before we merge it; although like always a stub is fine. The example description / title could probably be cleaned up too, but just try your best.
Once that's done this LGTM.
|
Some time ago, as I encountered an issue with a rounded corners node not clipping its children, I looked at that part of Bevy’s code, and discovered incidentally that clipping was actually limited to axis aligned rects. At the time I concluded that solving this would probably require a rasterization based approach, so I am very interested by the solution proposed by this PR. |
| /// | ||
| /// # Arguments | ||
| /// * `clip` - The clipping regions to apply. If `None`, the input polygon is returned unchanged. | ||
| /// * `vertices` - The polygon vertices and associated attribute values. The vertices should be in boundary order (either direction), forming a convex polygon. |
There was a problem hiding this comment.
I think technically this handles non convex polygons just fine. However the list produced with such a polygon cannot be drawn with a simple fan.
goodartistscopy
left a comment
There was a problem hiding this comment.
I like how this makes the code quite a bit easier to follow, and the added clipping code is also pretty clear. This does not handle clipping the rounded corners, because those are not represented as geometry, but this doesn’t make it any less useful.
As mentioned in the description a possible optimization would be to cache the intersection of the transformed rects that now make up the clipping path (previously caching was as trivial as accumulating Rects into the single CalculatedClip rect). The intersection is always convex so the same algorithm could be used.
Objective
Get clipping working with transformed nodes.
Fixes #17630
Fixes #21775
(and probably quite a few others)
Solution
CalculatedClipis now an enum withRectsandFullyClippedvariants.Rectsholds a list ofRectin node local coords andAffine2world-to-local transform.bevy_ui_renderhas a newclippingmodule with aclip_polygonfunction that intersects UI elements with the clipping rects and chops off the non-visible regions and returns a list of vertices that forms a triangle fan. Uses a simplified version of the Sutherland–Hodgman algorithm.Performance isn't too bad, but text suffers a bit when clipped as there's no broad phase atm, instead it tests and breaks up each glyph individually. The clipping geometry also needs to be cached somewhere and updated incrementally.
I didn't try to optimise this branch too much yet as I suspect the required changes would probably end up being much larger and more complicated than the clipping implementation itself, and it might better to leave them for follow up PRs.
Currently this only supports rectangular clipping regions but it can easily be expanded to support any covex shapes.
--
Ideally we'd do clipping on the GPU which would allow for arbitrary clipping geometry and better performance. That would need a complete rewrite of the UI renderer and might have compatibility issues. I think this is good enough as an improving step, it works reliably and the code is also simpler and easier to understand, in particular UV interpolation is much simpler now.
Testing
Showcase