-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bevy_ui: Add UiImage::tiling_mode
for image tiling
#8762
base: main
Are you sure you want to change the base?
Conversation
Welcome, new contributor! Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨ |
8f606fc
to
25bb7d3
Compare
You added a new example but didn't update the readme. Please run |
1 similar comment
You added a new example but didn't update the readme. Please run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only skimmed this as I need to go to bed but it looks like this probably needs a separate widget bundle as you don't want any sort of intrinsic sizing behaviour (I think?).
Something like deriving Component
for TilingMode
and adding a TiledImageBundle
with the same components as ImageBundle
except without a ContentSize
and with TilingMode
.
I'm not quite sure what you mean, the sizing stays exactly the same as before, the api already allows you to control how/if the image should stretch etc. (by default the align_items and align_content of the Style is set to stretch). So now its just that instead of always stretching the image you can optionally tile the image when setting a different tiling_mode. |
An ImageBundle node's size is determined by a MeasureFunc that attempts to find a size for the node that respects the image's aspect ratio given the space allowed to it within the UI layout. The space allowed to it is derived from the style constraints so it can seem like you have direct control. There are still a few bugs with MeasureFuncs as well and you can see some weird results I think just by giving ImageBundle nodes some margins. |
Provide a way to tile/repeat a UiImage Adjust the UV coordinates of the image node so the image repeats. This means (1, 1) becomes (2, 2) in order to repeat the image once along the x/y axis. In order to do this we need to modify the bevy_ui systems internals, since bevy_ui does not expose any mesh or other interface we could use to adjust the UV coordinates from client code. This also requires the user to adjust the address_mode_u/v of SamplerDescriptor globally or per image. - Add a new TilingMode component that indicates if the UiImage should not tile, tile horizontally, tile vertically or tile in both directions. - Add a new TiledImageBundle bundle that has no calculated_size and image_size to prevent the image size affecting the node sizing. - During extraction, store the original image dimensions and the tiling mode in ExtractedUiNode. - During render, use the tiling mode, the original image dimensions and the calculated node dimensions to calculate a tiling factor. This happens in the new function `get_tiling_uv_factor`. Finally multiply the uv coordinates by this tiling factor. - Added example ui_image_tiling to demonstrate this feature.
Thanks that makes sense! I updated the PR to follow your recommendation of using a separate component for TilingMode and added a TiledImageBundle. I also added some more complex examples: |
Looking at this further, I see that it's doing this at the sampler level. To get my coveted ninepatches, I'd need to use nine textures rather than nine texture regions. Graphics APIs cannot wrap texture coordinates across a region in a texture. Do we think that this sort of feature will be redundant with what 5213 is attempting to do? Doing wrapping logic in-code rather than in the shader/sampler is, of course, more complex. But it encourages groups of widgets to all share the same TextureAtlas instead of each widget using its own texture. |
Objective
In bevy_ui, provide a way to tile/repeat a
UiImage
.I was using the flex layout features of bevy_ui to create a dynamically sized box with images as borders (like top-left/right,top/top-right/etc. all separate image textures with some embellished frame). For the box to be dynamically sized I want the top/bottom/left/right images to tile horizontally/vertically, but this is currently not possible with bevy_ui.
Solution
Adjust the UV coordinates of the image node so the image repeats. This means (1, 1) becomes (2, 2) in order to repeat the image once along the x/y axis. In order to do this we need to modify the bevy_ui systems internals, since bevy_ui does not expose any mesh or other interface we could use to adjust the UV coordinates from client code.
This also requires the user to adjust the address_mode_u/v of SamplerDescriptor globally or per image. So the address_mode_u/v/w (I'm not entirely sure what w is meaning in this context) is set to AddressMode::Repeat.
I also found this other PR: #7406 that does something similar for 3d textures, but since we don't have control over the UVs for the UI rendering pipeline in bevy_ui, I had to modify the internals to make it work.
Changelog
Add a new tiling_mode to UiImage that indicates if the image should not tile, tile horizontally, tile vertically or tile in both directions.get_tiling_uv_factor
. Finally multiply the uv coordinates by this tiling factor.