Search Unity

Official Feedback wanted : Sprite assets support

Discussion in 'UI Toolkit' started by antoine-unity, Sep 2, 2020.

  1. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    780
    In 1.0.0-preview.8 we have introduced support for sprite assets, which means that you can assign sprites to VisualElement’s background property as well as the source of Image elements.

    One of the main advantages of using sprites instead of plain textures is to benefit from the Sprite Atlas workflow. This can greatly reduce draw call batch breaking when different textures as used within the UI.

    We have attached a sample which demonstrates this in more detail. It illustrates that you can keep a low draw call count while continuing to address images normally in C# and USS.



    How to use Sprites
    When a texture is imported in “Sprite (2D and UI)” mode, a sprite asset will be generated. This sprite can be used by UI Toolkit in two ways.

    Option 1: Using USS styles

    When referring to a texture asset in a USS file, if that texture contains a sprite asset, it will be used instead of the Texture2D imported asset.

    background-image: url("/Assets/Tools.png");

    If the texture is imported in multiple sprite mode, the above syntax will import the first sprite asset. To refer to a specific sprite asset, you can use the “anchor” syntax:

    background-image: url("/Assets/Tools.png#Sword");

    The above syntax will load the “Sword” sprite asset from the “Tools.png” file.

    Using sprites that are included in a SpriteAtlas can be used and will work transparently in UI Toolkit.

    Note: using url() to import Sprite assets is only available in 2020.2 due to limitations of our package in 2020.1. As a workaround, you can use the resource() function to target Sprite assets (though there is no equivalent "anchor" syntax). See the "Assets" section of this page for more information about these two approaches.

    Option 2: Setting the sprite in code

    The background style now has constructor that takes sprite object:
    visualElement.style.backgroundImage = new StyleBackground(sprite);

    Also, the Image class now has a sprite property:
    image.sprite = sprite;


    Supported Sprite Features

    Sprite borders (aka 9-slices) are supported by UI Toolkit. When using borders, resizing a VisualElement size will adjust the borders exactly like the 2D runtime sprite system. Since UI Toolkit also provides a slice style, it is possible to have conflicting values between the sprite borders and the UI Toolkit slices. A warning is issued in that situation and the values of Sprite will take precedence.

    More features may be supported in the future, such as sprite pivots or better support for sprite sheet based animations.

    Example project

    In order to get the actual draw call count lowered as shown the screen shot, ensure that the value of Project Settings > Editor > Sprite Packer is set to Sprite Atlas V1 - Always Enabled.

    This project uses assets from Ravenmore's Icon Pack 2.0 created by Krzysztof Dycha.

    ---

    We're excited to hear about your feedback on this feature and would like to know if it fits your needs.
    Note that a future version of the UI builder will add support for Sprites in the authoring environment.
     

    Attached Files:

    Last edited: Sep 2, 2020
    ModLunar, marcospgp and chris-z562 like this.
  2. igors_unity

    igors_unity

    Joined:
    Apr 10, 2020
    Posts:
    2
    This seems great, although I do have one observation to share. We noticed that the desired workflow in our teams is for artists to create, put UI images into project and use them in UI directly. Then at some later time some developer would take a look on the created screen and its performance and decide if some of the used images should go into Atlas. At that point developer should be able to create an atlas and assign images to it without having to go through all the UI screens created with those images and correcting their paths to target the atlas. In other words there should be automatic redirection of old paths so they now target the atlas.

    Of course the issue with that workflow is the case where you want to put the same image into multiple atlases and one atlas should be used on one screen but another atlas on another screen even if original image path is the same. I think this could be solved with some additional property like "PreferredAtlasName" on the controls and there are probably other solutions as well.

    I think your Addressables are providing this kind of abstraction so that nothing needs to change at the place where assets are used when they are moved into or out of asset bundle (but I am not sure about that).
     
    floriankorsakissok likes this.
  3. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    This is basically how it works when you create a Sprite Atlas asset. You can add sprites to an atlas, but you still refer to the original sprite in your USS files. When doing so, the atlassed sprites will be used at runtime transparently.
     
    floriankorsakissok likes this.
  4. leutnant_kane

    leutnant_kane

    Joined:
    Apr 29, 2015
    Posts:
    40
    Since Addressables we're just mentioned. Any plans/existing workflows how ui Toolkit will work with Addressables (addressable sprites/sprite atlasses in this example)?
     
    spakment likes this.
  5. awmuncy

    awmuncy

    Joined:
    Jan 27, 2020
    Posts:
    4
    Is there a way to specify draw mode for the sprites?
     
  6. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    No, mostly because they are not necessary for UI Toolkit. If your sprite has borders defined, then UI Toolkit will display them as a sliced-sprite, the draw mode doesn't have to be explicitly defined.

    That said, there's no equivalent of "tiled" mode at this time for UI Toolkit sprites.
     
  7. awmuncy

    awmuncy

    Joined:
    Jan 27, 2020
    Posts:
    4
    Ahh, okay. Tiled mode specifically was what I was looking for.
     
  8. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Proper tiled mode support would probably require us to implement the
    background-repeat
    style property, which I think is planned for later. I'm taking note to make sure it's there.

    In the meantime, there's a couple of alternatives:
    1. Make multiple elements in a grid pattern to duplicate the texture (not ideal if you need a lot of those)
    2. Use the mesh API to make a large quad with custom UVs to display a texture with "repeat" wrap-mode
    EDIT: If you consider using option #2, you'll have to make sure that your texture is not dynamically atlassed by UI Toolkit. Otherwise, the "repeat" wrap mode will be ignored. A custom filter would be necessary right now.
     
    Last edited: Oct 6, 2020
    awmuncy likes this.
  9. spiralogy

    spiralogy

    Joined:
    Oct 10, 2013
    Posts:
    11
    So I have an actual sprite atlas, just a single image from which other sprites are generated and can be expanded in the project view. Using the old-style Canvas Renderer/Image, I could assign any of those sprites to the background image--however, with UIElements, I'm unable to drag and drop/assign any of the sprites, but I can assign the entire image/atlas, which... obviously isn't what I want. Is this intended or am I doing something wrong?
     
  10. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    You can refer to the individual sprites (which are sub-assets of your atlas) using the
    #spritename
    syntax.

    For example, the following would assign the "Sword" sprite which is part of the main "Tools.png" atlas:
    Code (CSharp):
    1. background-image: url("/Assets/Tools.png#Sword");
    Hope this helps.
     
    spiralogy likes this.
  11. spiralogy

    spiralogy

    Joined:
    Oct 10, 2013
    Posts:
    11
    I did see that, but it's not really particularly useful for me--I don't wanna have to hand-edit UXML files or specify the sprites programmatically or worry about the names of the sprites/images at all, really. It seems that this somewhat defeats the purpose and ease of using the UI Builder in the first place. It would be really useful to be able to have the same drag-and-drop functionality as the older style UI, if possible.
     
    mr-Fox likes this.
  12. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Yes, UI Builder doesn't have support for sprites right now, but I've heard that this will come later.
     
    ModLunar and spiralogy like this.
  13. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
    Hi spiralogy,

    The next version UI Builder (look out for the latest release in the next couple of days) does support Sprites via the background-image USS property. Thanks!
     
    spiralogy likes this.
  14. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    184
    spiralogy likes this.
  15. dujimache

    dujimache

    Joined:
    Dec 17, 2011
    Posts:
    89
    hi, how to prevent a texture dynamically built to an atlas??
     
  16. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
  17. orb_9

    orb_9

    Joined:
    Feb 10, 2010
    Posts:
    47
    This feature is not working as expected. Tested with SpriteAtlas V1.
    Unity 2021.1.24f1
    UI Builder-1.0.0-preview18
    UI Toolkit-1.0.0-preview18

    I can assign a sprite from an atlas via the UI Builder.
    upload_2021-10-14_17-54-7.png

    This gives the following UXML code:

    Code (csharp):
    1. <ui:VisualElement name="Icon" class="unseen-collectiblelistentry__icon" style="background-image: url(&apos;/Assets/_LocationBasedXR/Textures/UI/Design-LocBased/Icons/Tours/x2/icon-tour-jurassic@2x.png#icon-tour-jurassic@2x&apos;);" />
    "icon-tour-jurassic@2x" is part of an V1 sprite atlas and it displays fine in a runtime UI when rendering the UXML via an UIDocument.

    I then try to assign a new icon to the VisualElement via the background property in C# like so:
    Code (csharp):
    1.  
    2. icon.style.backgroundImage = data.Thumbnail.texture;
    3.  
    where "icon" is a reference to the VisualElement shown above.
    This does not throw an error, but instead of the icon being displayed, the atlas texture is shown:
    upload_2021-10-14_17-59-39.png

    When I delete the atlas, the assignment of the new sprite works fine.

    Question: Is assigning a sprite which is part of an atlas via C# supported and if so how can i do it?
     
  18. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    In your code sample, is
    data.Thumbnail.texture
    a sprite object or the texture associated with that sprite? I would expect it to work properly if it's the former, and I would expect it to show the full texture atlas if it's the latter.
     
  19. orb_9

    orb_9

    Joined:
    Feb 10, 2010
    Posts:
    47
    data.Thumbnail
    is of type Sprite and .texture is in fact the texture property of the Sprite. It is declared like this:
    Code (csharp):
    1.  
    2. public Sprite Thumbnail {
    3.     get { return thumbnail; }
    4.     set { thumbnail = value;}
    5. }
    6.  
    When I try to assign the Sprite rather than the texture like so
    Code (csharp):
    1. icon.style.backgroundImage = data.Thumbnail;
    I get a compiler error
    Code (csharp):
    1. error CS0029: Cannot implicitly convert type 'UnityEngine.Sprite' to 'UnityEngine.UIElements.StyleBackground'
     
  20. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    I think there is no implicit conversion between Sprite and StyleBackground, doing

    Code (CSharp):
    1. icon.style.backgroundImage = new StyleBackground(data.Thumbnail);
    should work.
     
  21. orb_9

    orb_9

    Joined:
    Feb 10, 2010
    Posts:
    47
    Hi mcoted3d,
    Code (csharp):
    1. icon.style.backgroundImage = new StyleBackground(data.Thumbnail);
    works like a charm. Thanks for the hint.

    While it works it should be mentioned that the documentation of the StyleBackground constructor does not list a constructor accepting sprites.
    https://docs.unity3d.com/2021.1/Documentation/ScriptReference/UIElements.StyleBackground-ctor.html

    Now that I know, I found that VS Code intellisense indeed shows a StyleBackground constructor using a Sprite. So I guess documentation needs to be updated.
     
  22. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
  23. orb_9

    orb_9

    Joined:
    Feb 10, 2010
    Posts:
    47
    I use 2021.1, specifically
    • Unity 2021.1.24f1
    • UI Builder-1.0.0-preview18
    • UI Toolkit-1.0.0-preview18
    and it works despite the missing documentation.
     
  24. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Thanks for the info, we'll try to get that sorted.
     
  25. optimise

    optimise

    Joined:
    Jan 22, 2014
    Posts:
    2,129
    Hi @antoine-unity. Long time ago I asked about build sprite atlas at runtime feature. Is that feature still planned to implement?
     
  26. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    Hello @antoine-unity.
    Perhaps I'm doing something wrong, but the Pixels for Unit property in the sprite import settings are not affecting the sprites in the UI Toolkit.
    Also would there be any support in the future for an individual "Pixels Per Unit Multiplier" property for the 9 scale sprites?
     
  27. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    The pixels-per-unit value is used when using sprite in world space, so that the pixels units of the original texture can be converted to reasonable world-space units. This value is ignored in UI Toolkit. The sprites will act the same way as other backgrounds: they will stretch to fill the VisualElement content (following the specified scale-mode of course), so the pixels-per-unit is ignored in that context. This is a similar behavior than UGUI in that regard.

    Not sure about this one. Can you please share more details why you want to scale 9-slice values by the pixels-per-unit value?
     
  28. Grumpy-Dot

    Grumpy-Dot

    Joined:
    Feb 29, 2016
    Posts:
    93
    @mcoted3d Thank you for your reply, I will try to explain it better.

    I have a button in UGUI with a background a sprite set with borders to be 9-slice scalable. This is in a normal Canvas with Screen Space - Overlay.
    In the first image I am setting the Pixel Per Unit property to 100:
    BlueButtonExample_100PPU.png
    In this second image I am setting the Pixel Per Unit property to 200:
    BlueButtonExample_200PPU.png
    The difference between the 2 is the scale of the border. In some situations I would like to scale the border a bit down depending if the border is for a button or a panel.
    As you can see, the Pixel Per Unit value is also affecting the UGUI.

    This behaviour can be done in a different way, if we want to change only individual images, and not all which are using this sprite, by increasing the Pixels Per Unit Multiplayer property in the Image component. To look the same as above we would increase from 1 (default value) to 2.

    This result is somewhat also possible in UI Toolkit, but with a hack. We can change the scale down of the whole button to 0.5 by changing the transform values, and double the fontsize and paddings. Clearly this is not desirable.

    Ideally we would have the Pixel Per Unit property changing the scale of the sprite directly in the UI Toolkit as well OR have another property for the background similar to Pixels Per Unit Multiplayer.

    Please let me know if this is clear now. Thanks!
     
  29. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Yes, thank you! I didn't look very thoroughly, but I'd expect the 9-slice to behave the same as UGUI in this situation. We'll look into it.

    Thanks again!
     
    Grumpy-Dot likes this.
  30. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    EDIT: Found the solution!
    In order to use the packages (preview) version of UI Toolkit that contains the Sprite feature in 2020, you have to explicitly reference the UITK package in the asmdef files that use the code. If you don't do that, Unity will try to compile those asmdef's with the builtin (version 2) of UITK instead on startup.

    This is for sure a bug, but I'm not sure if there's any chance it'll get fixed since it's a bug with using a preview version that I'm pretty sure goes away if we update to 2021.

    Original Post:
    We're running Unity 2020, using UI Toolkit preview, and use this feature in some spots.

    It worked fine in 2020.3.11f1, using 1.0.0-preview.14. I now updated to 2020.3.23f1 (latest). We're running into a bug, both with 1.0.0-preview.14 and -preview.18.

    What's happening now is that when we start Unity, Unity tries to compile our code using what seems like the built in version of UI Toolkit. This means that we fail to compile on code like
    new StyleBackground(sprite)
    , and are prompted to enter safe mode. If we force a recompile by adding an arbitrary space somewhere, Unity compiles and works again, but this isn't viable to do every time we open the project, and I don't want to ask our artists to do that!

    I seem to remember that I ran into this bug a while ago, but I cannot remember what we did in order to fix it!

    Any advice? We don't want to update to 2021 quite yet, but I've got some crashes in 2020.3.11 that's supposed to be fixed in later 2020.3 versions. Dropping the code that uses the sprite feature is also not viable - we've got some important windows that need to draw sprites, and rewriting that is probably going to be more work than the 2021 upgrade :p
     
    Last edited: Nov 23, 2021
  31. viktorcode

    viktorcode

    Joined:
    Jun 30, 2020
    Posts:
    23
    Encountered issue in Unity 2021.2.4 that I cannot set sprite in UI Builder if the file is in Resources folder. In that case the builder allows setting it as sprite then changes the type to texture when I save or navigate away.

    Is it the expected behaviour?
     
  32. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
  33. Smolty

    Smolty

    Joined:
    Nov 8, 2016
    Posts:
    17
    Hi,

    I was wondering if someone from Unity could explain how the Dynamic Atlas works.
    I imagine it creates a dynamic atlas at runtime where it packs all the sprites that are currently used but I'm not sure if the Sprite Atlas Asset has any affect on it.

    Does UI Toolkit still create a Dynamic Atlas if all my Sprites are already in a Sprite Atlas Asset?

    Thank you.
     
  34. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Hi! Yes, it creates an atlas and will try to pack textures and sprites in it as they are added to your VisualElements hierarchy. Sprites that are already packed in a SpriteAtlas asset are ignored and won't be included in the dynamic atlas.

    Not all textures can be atlassed, as they have to pass some filters before being selected for inclusion. You have some control over this through the DynamicAtlasSettings, which you can set on your PanelSettings:
    https://docs.unity3d.com/2022.2/Documentation/ScriptReference/UIElements.DynamicAtlasSettings.html

    UI Toolkit will allocate the texture for the dynamic atlas only when it finds an atlassable texture in your VisualElement hierarchy.

    Hope this helps!
     
    Smolty likes this.
  35. Smolty

    Smolty

    Joined:
    Nov 8, 2016
    Posts:
    17
    Thanks for the explanation mcoted3d.

    One last question, is there any advantage in using the Dynamic Atlas over the Sprite Atlas Asset when it comes to performance?

    It seems that the Sprite Atlas Asset would be the preferred way when I know exactly when, where and what sprites/textures will be needed and used.

    Thank you.
     
  36. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Yes. Using a Sprite Atlas asset will guarantee that your sprites are packed in an atlas. The dynamic atlas may decide to not pack your sprite if the texture is too large, the filter mode doesn't match, or some other reason. Also, the dynamic atlas requires an additional blit to the atlas, which doesn't happen with a pre-baked Sprite Atlas.
     
    Smolty likes this.
  37. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    136
    @mcoted3d @antoine-unity : This features is broken in Unity 2022.2.0b13: all sprites are rendered solid white when they are part of an SpriteAtlas. Sprites are rendered again as expected once SpriteAtlas is deleted. Bug report:
    CASE IN-21747
     
  38. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    Thanks for reporting, we'll have a look.
     
  39. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    This will be fixed in b15, thanks for reporting.
     
    Fribur likes this.
  40. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    136
    It is indeed fixed, but not working as expected: I am getting a view into the packed SpriteAtlastexture, instead of the sprite. From left to right in the attached picture: (1) what I get (2) what it should be (3) relevant portion of AtlasTexture:
    upload_2022-11-17_20-2-18.png

    I imported individual png (texture importer settings: Sprite (2D and UI), packed them into an SpriteAtlasV2, and get the Sprite in the UI Manager like this:
    Code (CSharp):
    1. svg.style.backgroundImage = new StyleBackground(pointAtlas.GetSprite("BOYLAT14"));
    Outside of UIElements this way of acessing the sprites from the SpriteAtlas works as expected.
     
  41. lilacsky824

    lilacsky824

    Joined:
    May 19, 2018
    Posts:
    171
    Is your triangle sprite mesh type is Full Rect and you use tight packing with your sprite atlas?
    Change your sprite mesh type to tight or don't use tight packing with your sprite atlas, may fix this problem.
     
    Fribur likes this.
  42. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    136
    Your suggestions work, however I believe it's still a bug of 2022.2.0b15, as there is no such issue in 2021.3.12f1. The picture in the first post of this very thread here does not look like that in 2022.2.0b15. Will wait if @mcoted3d has an idea in this thread here, if not I can submit the very project from post number 1 as bug report.

    BTW here detailed setting that make the issue go away: (1) changing mesh type from tight to full rect. Or (2) removing "tight packing" option of atlas. Bot options I like to avoid as it blows up the texture size significantly for my >600 sprites.
     
    Last edited: Nov 18, 2022
  43. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    I'm surprised it's behaving differently in 2021.3. If you use a full-rect sprite with a tight-packed atlas, I'd expect to see the neighboring textures in the full-rect sprite.

    Note that UI Toolkit may ignore tight-mesh imported sprite and fallback on full-rect in situations where cropping is required (for example, if the background scale mode is ScaleAndCrop). In 2022.2+ we also introduced the background-repeat style which may force the use of a full-rect sprite as well. This could be the cause of the difference here. If that's the case, there's hope we can fix it.

    Short term, if tight-sprites works for you, this would be the way to go. Otherwise, you'll have to prevent overlaps in the atlas.
     
  44. Fribur

    Fribur

    Joined:
    Jan 5, 2019
    Posts:
    136
    Try to open the package from the first post of this very thread here in Unity 2022.2.0b15 and 2021.3 and you will see the difference: In 2022 some sprites (e.g. the AxeDouble) show fragments from other sprites, no such issues in 2021.3. See upper right corner:
    upload_2022-11-18_16-38-11.png
    No, misunderstanding: In that package (and in my project) sprites have Mesh Type "tight", the atlas is packed "tight", and the VisualElement loading the sprite as background has scale mode "stretch-to-fill".

    BTW: the minimal project I submitted under CASE IN-21747 is nothing else but the package from the first post, so you can use that for reproduction in case that is easier with your internal QA logistics.
     
    Last edited: Nov 18, 2022
  45. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    1,003
    In that case I suspect this is caused by our recent changes related to background-repeats. Thanks for reporting.
     
    Fribur likes this.
  46. TwoBitMachines

    TwoBitMachines

    Joined:
    Oct 5, 2016
    Posts:
    43
    Hello there, how do you install this in version 2020.3.37f1 ?
     
  47. JuliaP_Unity

    JuliaP_Unity

    Unity Technologies

    Joined:
    Mar 26, 2020
    Posts:
    698
    2020.3 is no longer supported so you can't download it anymore directly from the hub, but you can find it in the archives. Unless you have a very good reason to use that one though we highly recommend you use the latest LTS, which right now is 2022.3 (on the hub you'll see 2022.3.9f1 right now).

    Hope this helps!