Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Texture2D.PackTextures - currently decreases quality without alternative

Discussion in 'Editor & General Support' started by diablo, Jul 26, 2011.

  1. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    From what I read in this thread as well as the reference page for the function, Texture2D.PackTextures will, upon failure, halve the size of each texture until they all fit into the atlas. What if I don't want them halved (which decreases quality)? What if I wanted to split the textures among multiple atlases? Is there any supporting method(s) which, given an array of textures and a max texture size, create multiple atlases? Or methods that will provide me with useful information that will allow me to split the textures optimally across several atlases? Or at the very minimum, a method that will tell me the first n number of textures in my array that will fit into an atlas of maxtexture size? Currently, there's no way I can create multiple atlases since they're no support functions that will give me any information whatsoever; not only does PackTextures not give me an option *not* to halve the textures, but when it's done doing its magic I don't even know if it was halved or not.

    Anyone have any ideas?
     
  2. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
  3. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    http://unity3d.com/support/documentation/ScriptReference/Texture2D.PackTextures.html

    read the docs. It tests my patience how much people aren't willing to read the docs. You control which textures go into the packer, so obviously you have control over how many is packed. Simply don't pack too many in one texture. Use a few atlases.

    Unless you roll your own method you're not going to be able to predict it so you'll need to use trial and error or sensible limits on what batch you're packing.
     
  4. diablo

    diablo

    Joined:
    Jan 3, 2011
    Posts:
    736
    Thank you for replying hippocoder, but I think you need to read my full post because it also tests my patience when people don't do so. I know how to use PackTextures, I've been using it over and over in my project, I know it backwards and forwards, it's not rocket science and I'm not asking how to use it. Now sure I have control over my textures, but how do I know how many will go into a, let's say, 1024x1024 atlas, given their packing algorithm? Am i to guess? Should I say, hmmm... I have 1000 textures I need to pack, so I think I'll put 250 in each atlas? Where does this magical number 250 come from? Of course there are ways I can reach some sort of "guesstimate" by accumulating the total sum of texture widths and heights and once I reach a certain point I stop, pack those textures, and start over on the next batch, but even that's not guaranteed. What if I guess wrong and woops! it goes and halves each of my textures in order to make them fit? Now I have another problem; I have no idea that this halving process happened at all, so I continue on my merry way in complete ignorance! Now I can take the stupid approach, which is to simply use half of the number of textures in a reasonable guesstimate, that way it's sure to be packed, but that's a lot of waste don't you think? I taught myself how to program in machine language when I was 10 years old, worked professionally since I was 13, and I am 38 now and still programming professionally, so I think I have a decent sense of when a particular method is found lacking. Now I'm hoping that there's a function out there that, given an array of textures and a max texture size, returns an integer that tells me how many of the first N textures in my array will fit. For example :

    Code (csharp):
    1. Texture2D[] textures = ...;
    2. int maxTextureSize = 1024;
    3. int n = GetPackTextureCount(textures, maxTextureSize); // <-- this would be great to have! it will compute, based on current packing algorithm, how many textures will fit into an atlas of size maxTextureSize
    4. Texture2D packedTexture= new Texture2D(0,0);
    5. Rect[] uvs = packedTexture.PackTextures(textures.Take(n).ToArray(),0,1024);
    6. ...
    7. // loop back and continue creating atlases until no more textures left to pack
    If anyone knows of any way to do this please let me know. An alternative (but worse) is a way to get it to throw an exception if it doesn't fit, that way I can keep going smaller until it works. Or at least let me know that it had to halve my textures, that way I can redo the operation with less textures. Something... ANYTHING... is better than being forced to do something you don't want, and worse yet, you have no idea that it happened.
     
    Last edited: Jul 29, 2011
  5. codebeans

    codebeans

    Joined:
    Apr 7, 2014
    Posts:
    79
  6. codebeans

    codebeans

    Joined:
    Apr 7, 2014
    Posts:
    79
    Ok, so I spend the day working on this issue and solved it.
    Unfortunately the code I came up with is now proprietary software of the company I work for.

    But a good start, if not all you need can be found here
    https://github.com/mfascia/TexturePacker

    and basic Texture2D operations such as SetPixels32 and GetPixels32()

    big hint: turn off mipmap generation when creating a new Texture2D or you will get some weird grey overlaps/graphic bugs.
     
  7. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    8,967
    There are a couple of other routes. What is the reason you are atlasting? Are you packing at runtime or can it be done before build? Are they for ui/sprites?
     
  8. codebeans

    codebeans

    Joined:
    Apr 7, 2014
    Posts:
    79
    I am packing at runtime. I have a set of ~1GB sprites on amazon s3
    However the set I need at a particular level is about 50mb/500 unique sprites max. (most of them are cached on the mobile device after the first download)

    In order to reduce drawcalls to a minimum I have to pack them at runtime without losing quality once a level is fully loaded
    therefore the need of multipacking sprites.

    The optimum would be to have ui-sprites shipped with the build of the app, and the other stuff is lazy loaded.
    Levels are user generated content retrieved from the backend upon socket connection in json format
     
  9. CyRaid

    CyRaid

    Joined:
    Mar 31, 2015
    Posts:
    134
    Y'know, you didn't have to say "it tests my patience", already starts off by being standoff-ish and preventing proper discourse, especially since you possibly misunderstood the post. It's very a valid point and instead of shrinking, the command could've returned (at option) what it fit on the atlas; The OP was asking what could we use if we didn't want the textures halved? A possible argument to disable shrinking and return the rects that fit, and we can create more by doing it again with the remaining, etc. Not all of us want the textures shrunken.
     
    hippocoder likes this.
  10. hippocoder

    hippocoder

    Digital Ape Moderator

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    You know, 2011 is quite a while ago. I'm sure many of us have mellowed in that time.
     
    CyRaid and Kurt-Dekker like this.
  11. CyRaid

    CyRaid

    Joined:
    Mar 31, 2015
    Posts:
    134
    Nice. :)
     
    hippocoder likes this.
  12. CyRaid

    CyRaid

    Joined:
    Mar 31, 2015
    Posts:
    134
    Btw whoever is coming across this now may have some luck with Texture2D.GenerateAtlas() until it returns true, and then run a Texture2D.PackTextures().