Search Unity

Unity 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:
    475
    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:
    1
    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).
     
  3. mcoted3d

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    756
    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.
     
  4. leutnant_kane

    leutnant_kane

    Joined:
    Apr 29, 2015
    Posts:
    20
    Since Addressables we're just mentioned. Any plans/existing workflows how ui Toolkit will work with Addressables (addressable sprites/sprite atlasses in this example)?
     
  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:
    756
    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:
    756
    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:
    756
    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:
    756
    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:
    121
    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:
    121
    spiralogy likes this.
  15. dujimache

    dujimache

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

    mcoted3d

    Unity Technologies

    Joined:
    Feb 3, 2016
    Posts:
    756
  17. orb_9

    orb_9

    Joined:
    Feb 10, 2010
    Posts:
    43
    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:
    756
    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:
    43
    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:
    756
    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:
    43
    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:
    756
  23. orb_9

    orb_9

    Joined:
    Feb 10, 2010
    Posts:
    43
    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:
    756
    Thanks for the info, we'll try to get that sorted.
     
unityunity