Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

SpriteManager - draw lots of sprites in a single draw call!

Discussion in 'iOS and tvOS' started by Brady, Jan 15, 2009.

  1. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I'm not sure why it would make it crash, but you actually just want to use one SpriteManager component for each material you'll be using. So if you only have one sprite atlas, you just need one in the scene. And that should probably be added in the inspector rather than at runtime.

    To create a reference to the SpriteManager script, either create a public reference and then drag the GO that contains the SM script onto it in the inspector, or use FindObjectOfType() in Start().

    Then when you want to create a new Sprite, you can refer to the SpriteManager script in-code like so:
    sprite_manager.AddSrite(...);

    I recommend having a thorough look at the sample project that is attached to the first post of this thread. It should answer some questions for you.
     
  2. Dark-Table

    Dark-Table

    Joined:
    Nov 25, 2008
    Posts:
    315
    I believe this is because "allocBlockSize" defaults to zero. So if you are adding a SpriteManager component at runtime it will crash as soon as you try to create a sprite with that SpriteManager.
     
  3. JürgenBF

    JürgenBF

    Joined:
    Oct 22, 2009
    Posts:
    4
    Thanks a bunch. That's what made it work for me. Also thanks for adding th sample project (I figure you just added that along with your latest post, right?).

    Btw, silentchujo is probably correct on the blockSize thing. I was able to work around the error by setting the count parameter to 1 in the EnlargeArrays method in case a 0 was given as parameter. That lead to other problems however. Anyways, not adding the ScriptManager at runtime was the way to go, so thanks again.
     
  4. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Glad you got it working! Actually, the sample project has been there for a while, but with all that's in this thread, it's easy to miss. :)

    Good call, silentchujo. I think you're right.
     
  5. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I'd like to change the UV coordintates of the texture I am using for a sprite so as to change to a different image for the sprite. I'm a little confused as to how to do this. It looks like UpdateUV is the function that I should use, but from the description:

    it sounds like I only need to modify lowerLeftUV. So I have tried:

    Code (csharp):
    1.        s.lowerLeftUV    = Vector2(0, 128);
    with no luck and I have tried:

    Code (csharp):
    1.        s.lowerLeftUV    = Vector2(0, 128);
    2.        s.UpdateUV();
    with no luck, where "s" is a sprite that I have added to the LinkedSpriteManager as:

    Code (csharp):
    1.        s = LSP.AddSprite(instantGO,  // The game object to associate the sprite to
    2.                          70.0,        // The width  of the sprite
    3.                         130.0,        // The height of the sprite
    4.                         400,        // Left pixel
    5.                         256,        // Bottom pixel
    6.                          50,        // Width in pixels from Left pixel
    7.                         128,        // Height in pixels
    8.                         false);     // Billboarded?
    Is this the correct way to change the portion of the texture that is used to display the sprite?
     
  6. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    That is half correct and half incorrect. It looks as if you are feeding lowerLeftUV pixel coordinates, not UV coordinates. You need to use PixelCoordToUVCoord() to convert your pixel coordinate values before assigning them to lowerLeftUV. That should do it.
     
  7. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    Thanks Brady!

    Code (csharp):
    1.        s.lowerLeftUV    = LSP.PixelCoordToUVCoord(400, 256);

    did the trick!
     
  8. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    I am using Sprite Manager for my GameObjects and I don't know if SpriteManager is causing the problem I am seeing, but I thought I would ask. The problem is that some of the GameObjects are moving at normal speed and some are moving at double speed.

    I instantiate 5 GameObjects, one I leave on screen, and the other four I move offscreen.
    Code (csharp):
    1.  
    2. var instantGO : GameObject = (Instantiate(prefabGO, InitialPos, InitialRot));
    3. s = LSP.AddSprite(instantGO,  // The game object to associate the sprite to
    4.                          70.0,        // The width  of the sprite
    5.                         130.0,        // The height of the sprite
    6.                           0,        // Left pixel
    7.                         128,        // Bottom pixel
    8.                          50,        // Width in pixels from Left pixel
    9.                         128,        // Height in pixels
    10.                         false);     // Billboarded?
    11.  
    12.  

    When I move the four back on screen, the first and the fourth move at normal speeds and the second and the third move at twice normal speed. I've looked at the velocities of all GameObjects and they are all the same so I am wondering if it might have something to do with the timing used by SpriteManager to update the sprites on the screen?

    Another strange thing I noticed that might be related is that as I bring each GameObjects back on the screen, the number of DrawCalls increments. I thought that Sprite Manager grouped all of the sprites into one draw call. Maybe this is a clue?
     
  9. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I don't think there's any say SM could be causing your GOs to move strangely since SM doesn't touch the GOs themselves. It just attaches sprites that will follow the GOs wherever they go. Depending on how you are moving the GOs around, you may want to check their scale, as that could affect it.

    As for draw calls, in SM1, all sprites are part of a single mesh, so there can't be any additional draw calls from sprites that are part of the same SM object. The additional draw calls could only be coming from: 1) the sprites in question don't share the same SpriteManager - you will get a single draw call per SpriteManager object in the scene, so make sure all the sprites in question were created from the same one if you want only a single draw call for all sprites. 2) There is something else attached to the GO in question that is being rendered besides the sprite.

    I hope that helps.
     
  10. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    Brady:

    Thanks, that helps a lot. I have a few questions/comments:

    1. What do you mean by check the GOs scale?

    2. As far as draw calls and number of SpriteManagers;

    I have a GameObject named SpriteManagerGameObject which contains the script LinkedSpriteManager. Inside my mainCamera script attached to the camera where I instantiate the GOs and add them to the SpriteManager, I have:

    Code (csharp):
    1.  
    2. static var SMGO : GameObject;
    3. static var LSP : LinkedSpriteManager;
    4. static var s      : Sprite;
    5. SMGO = GameObject.Find("SpriteManagerGameObject");
    6. LSP = SMGO.GetComponent("LinkedSpriteManager");
    7.  
    8. for(m = 0; m < 5; m++){
    9.        s = LSP.AddSprite(instantGO,  // The game object to associate the sprite to
    10.                          70.0,        // The width  of the sprite
    11.                         130.0,        // The height of the sprite
    12.                           0,        // Left pixel
    13.                         128,        // Bottom pixel
    14.                          50,        // Width in pixels from Left pixel
    15.                         128,        // Height in pixels
    16.                         false);     // Billboarded?
    17.  
    18. |
    19.  
    So as far as I can tell there is only one SpriteManager, unless I am missing something.

    3. The problem GOs have particle systems attached to them, with a Particle Emitter, Particle Animator and Particle Renderer. I have non-problem GOs that don't have the particle emitters that don't have the speedup problem. But I replaced the problem GOs with the GOs that do not have particle emitters, and the problem GOs still have the speed up. Hmm.
     
  11. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    1) I'm referring to the GO's transform's x, y, and z scale.

    2) It looks like you only Hagar a single SM object so that must not be the drawcall culprit.

    3) The particle emitters are almost certainly the reason for the additional draw calls. As for movement speed, it has to be something other than SM, as SM only reads from the GO's transform, but never writes to it.
     
  12. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    Brady:

    1. The GOs all have the same scale, so that is not it.

    3. Yup, checked the draw calls and without the particle emitters, there are no additional draw calls as GOs are added.

    Since the SM never writes to the GO's transform, I will look elsewhere for the solution.

    Thanks again!
     
  13. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    1. What about any parent GOs? If some of the GO's parent object(s) have a different scale, then changing the GO's localPosition by, say 1 unit, whilst the parent's scale is 2, would result in the GO translating 2 units in world space.

    Just a thought.
     
  14. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    The GOs don't have any parent GOs. All the GOs are instantiated the same and then move around the scene independently. All the GOs have the same scale = (1, 1, 1);

    Thanks for the thought. It's a good tip!
     
  15. cloud369

    cloud369

    Joined:
    Jul 26, 2009
    Posts:
    5
    Hello all, I'm kinda new to making games with unity and I wanted to make a 2d shooter game. I'm going through and trying to figure out how to use the spriteManager created by Brady. Is there some type of tutorial around somewhere that could explain the spriteManager a little bit easier?
     
  16. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Are you asking about SM2 or the original SpriteManager that is on the wiki?
     
  17. cloud369

    cloud369

    Joined:
    Jul 26, 2009
    Posts:
    5
    the original.
     
  18. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    This is a thread for SpriteManager 2. For lots of details on the original, check this thread:
    http://forum.unity3d.com/viewtopic.php?t=17864

    In the first post, you'll find a demo project that shows how to use lots of SpriteManager's features. There isn't a "tutorial" per se, however, that I'm aware of at the moment. But a lot can be gleaned from the demo project. It's pretty straight-forward from there.

    SM2, however, is much easier to use because of the way it integrates into the Unity editor.
     
  19. cloud369

    cloud369

    Joined:
    Jul 26, 2009
    Posts:
    5
    I think I'm starting to understand it. Does the sprite sheet have to be one picture or can it be separate?
     
  20. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I'm not sure what you mean. There can be multiple sprites together on a single sprite sheet (or "atlas"), but in SM1 there is one atlas per SpriteManager (or LinkedSpriteManager). But in SM2, using the PackedSprite class, you hand it a bunch of separate individual sprites and it will build the sprite atlas for you.
     
  21. mudloop

    mudloop

    Joined:
    May 3, 2009
    Posts:
    1,107
    I think you're mistaking Brady :) That link is this same thread...
     
  22. cloud369

    cloud369

    Joined:
    Jul 26, 2009
    Posts:
    5
    So every single sprite used in the game is on one sprite sheet and the spritemanager holds it?

    Or...

    Multiple spritemanagers holding different sprite sheets.
     
  23. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Smag:
    LOL! You're right, somehow I got confused as to what thread I was posting to! :)

    cloud369:
    You can have multiple SpriteManager/LinkedSpriteManager objects in the game if needed (and you'll get a drawcall for each one you have), but what determines whether an additional one is needed is if you can't fit all of your sprites on a single atlas (1024x1024 max texture size). So if they will fit, then yes, every sprite in the game will use one sprite sheet (atlas) and the SpriteManager/LinkedSpriteManager uses that (points to that material).

    If they will not all fit, then you will need multiple SpriteManager/LinkedSpriteManager objects in the scene, each pointing to their own material with a different sprite sheet.
     
  24. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    I'm really confused about winding. Near the beginning of this thread, there was some mention of an issue with CCW polys facing the wrong direction, but that was a long time ago, and I'm assuming it has since been fixed.

    -----

    I have a Sprite Manager that creates a number of sprites.

    When I have the SpriteManager GameObject selected in the editor, and the "Scene" view is set to "Front", I see poly edges for each triangle used to make up the sprites.

    If I set the "Scene" view to "Back", the poly edges disappear.

    Assuming that the edges are visible because I'm looking at the "front" face of the polys, if I reversed the SpriteManager Winding, shouldn't it flip the edges around so they are visible in the "Back" view?

    I have tried both CW and CCW, and neither seemed to affect the behavior. In fact, I saw no difference between the two settings. When I set the Material Shader to something other than a particle shader, the material only shows up on one side of the sprites (the front side with the visible wire edges).

    Shouldn't swapping the Winding flip the faces around?

    I have been working in the "Back" view, because I prefer to use X and Y for horizontal and vertical coords, and in "Back", -X is to the left, and +X to the right. In "Front", that's flipped.

    Unfortunately, I have found no way to get the sprite wire edges to appear in the "Back" view. Is there an easy way to flip the normals on all sprites in the SpriteManager?
     
  25. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    That is very odd. Changing the winding order should, indeed, flip the way it faces, and viewing it from the back should actually work using the default winding.

    I'm trying to think of what could be affecting it and causing it to do otherwise, but I'm drawing a blank. If you change the winding and nothing else (don't change scale or anything), it should cause the opposite side of the polygon to become visible (assuming your shader performs backface culling).

    If I think of something to try, I'll let you know.
     
  26. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    A bit more information on my recent post regarding Winding ...

    Actually, CW and CCW winding is working, although in my test, I create a bunch of sprites (~170), and then remove them.

    Later, when I create new sprites, they are pulled from the 'availableBlocks' ArrayList, because it is populated with the old Sprite objects.

    I noticed that when I commented out the "availableBlocks.Add(sprite);" line in the SpriteManager.RemoveSprite() method, the new sprites after the initial 170 have the correct winding. Although when that line is kept in there, the new sprites are facing the wrong direction.

    This is very strange. I don't see any reason why the reused Sprite objects are ignoring CW, and defaulting to CCW.
     
  27. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    Okay. During the creation of initial batch of Sprites, some had their draw layer specified using 'Sprite.SetDrawLayer()'.

    In the second batch, where old Sprite objects are reused, I don't use SetDrawLayer.

    Anyhow, commenting out that line in the initial batch allows for the second batch to have the correct Winding.

    For the record, I was passing negative numbers to SetDrawLayer in a loop (-index) so that the sprites created first would always appear over later sprites.

    =====

    After looking at SortDrawingOrder(), I noticed that the winding for CW is wrong. In the first triangle, mv4 and mv2 were backwards, and in the second, mv3 and mv2 were.

    This is how they should appear.


    Code (csharp):
    1. // Clockwise winding
    2. triIndices[i * 6 + 0] = s.mv1;    //  0_ 1          1 __ 4
    3. triIndices[i * 6 + 1] = s.mv4;    //  | /    Verts:  | /|
    4. triIndices[i * 6 + 2] = s.mv2;    // 2|/            2|/_|3
    5.  
    6. triIndices[i * 6 + 3] = s.mv4;    //    3
    7. triIndices[i * 6 + 4] = s.mv3;    //   /|
    8. triIndices[i * 6 + 5] = s.mv2;    // 5/_|4
    9.  
     
  28. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Ahh yes, that seems to make sense. Thanks for pointing that out.
     
  29. mrAndrew

    mrAndrew

    Joined:
    Oct 25, 2008
    Posts:
    33
    Iv got some problem with UVAnimation()
    I have 128x128 test texture with digits 1,2,3,4 (Attached)


    So i created Sprite and added UvAnim :

    Code (csharp):
    1. public LinkedSpriteManager m_SpriteManager;
    2.  
    3. void Start (){
    4.       UVAnimation ani1= new UVAnimation();
    5.       ani1.BuildUVAnim(new Vector2(0,0.5f), new Vector2(0.5f,0.5f), 2, 2,4, 2);
    6.       ani1.name = animation1Name = "anim1";
    7.       ani1.loopCycles = -1;
    8.    testSprite = m_SpriteManager.AddSprite(gameObject, 1, 1, 0, 64, 64,64, false);
    9.      
    10.       testSprite.AddAnimation(ani1);
    11.  
    12. }
    13.  
    14.    void Update ()
    15.    {
    16.       if(Input.GetButtonDown("Jump"))
    17.         testSprite.PlayAnim(animation1Name);
    18.  
    19.    }
    Sprite image appears correctly with the picture of "digit 1 ".But when I press the "Jump" ,animation starts with the picture of "digit 2",and I see the following cycle: 2, 3, 4, 1, 2, 3, 4 ,1.. and on.How to make animation started with the "digit 1" ?
     

    Attached Files:

  30. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    It looks like you are doing everything correctly. Try replacing PlayAnim() with the version below and see if that addresses the problem:

    Code (csharp):
    1.  
    2.     public void PlayAnim(UVAnimation anim)
    3.     {
    4.         // First stop any currently playing animation:
    5.         m_manager.StopAnimation(this);
    6.  
    7.         curAnim = anim;
    8.         curAnim.Reset();
    9.         timeBetweenAnimFrames = 1f / anim.framerate;
    10.  
    11.         m_manager.AnimateSprite(this);
    12.     }
    13.  
    I suspect what may be happening in your case is that the first frame is getting set when you call PlayAnim(), but then before that has a chance to display, the animation pump calls StepAnim() again, stepping it to the next frame.
     
  31. mrAndrew

    mrAndrew

    Joined:
    Oct 25, 2008
    Posts:
    33
    Nothing changed :(.Im still get 2,3,4,1,2,3,4 cycle.If I put anim1.loopCycles = 0, then the cycle looks like this: 2,3,4(Sprite changed 3 times). StepAnim (-1); also does not help:)
     
  32. CMoss

    CMoss

    Joined:
    Apr 21, 2009
    Posts:
    75
    I'm trying to animate the size of a sprite based on its distance from the camera. What would be the best way to do it? I tried using:

    Code (csharp):
    1. Sprite.height = 100/screenPos.z;
    2. Sprite.width = 100/screenPos.z;
    This changes the height and width values in the inspector but doesn't change the actual size of sprite. Instead I decided to just scale the game object, but I saw in another thread that scaling meshes hurts performance.
     
  33. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    mrAndrew:
    Strange, that's the only thing that comes to mind that could produce that behavior. I'll try to think of something else that could cause that.

    Moss:
    Scaling the GameObject shouldn't hurt the performance, especially since you're not actually scaling the mesh with SM1 since SM1 "manually" transforms the vertices internally. But to use the height/width method, you'll need to use SetSizeXY() (or XZ or YZ, depending on your plane).
     
  34. mrAndrew

    mrAndrew

    Joined:
    Oct 25, 2008
    Posts:
    33
    Thanks Brady.
    One more question.If I plan to use 2 or more materials for the sprites, what is the best way to do that, except creating additional instances of "LinkedSpriteManager" for each material ?
     
  35. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    That's really the only way. You have to have one SpriteManager/LinkedSpriteManager object for each material you wish to use. You could possibly change materials at runtime by re-assigning the material of the GameObject that hosts the SpriteManager, but doing that you can still only use one material at a time. To use multiple materials at once, you'll need additional SpriteManagers.
     
  36. mrAndrew

    mrAndrew

    Joined:
    Oct 25, 2008
    Posts:
    33
    thanks a lot :)
     
  37. deadbug

    deadbug

    Joined:
    Sep 9, 2009
    Posts:
    165
    hey all.
    i like this sprite software but am having a problem building my atlases.

    when i resize the images to fit into something like 256 by 256 sheet with frame padding 0 i get a big L shape. Can someone tell me what i need to do for it to fillup the sheet and maximize the space?

    thanks lots,
    attached an image.

    chris
     

    Attached Files:

  38. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Is this using SM2? If so, this is probably due to the algorithm used by Unity's PackTextures feature. I believe it will always resize textures in increments of half their previous size in order to get them to fit on a texture. So in your case that would mean the textures are much smaller than they need to be to fit into the desired atlas size. For example, if you want an atlas that is 64x64 and contains 4 sprites that are 33x33 pixels each, that will result in an overage of 2 pixels in each dimension, so when they get sized down to fit into 64x64, they'll be resized to about 16x16, meaning now there will be a lot of unused space on the 64x64 atlas. I wish it would resize to 32x32 per-sprite to get it to fit perfectly, but unfortunately, Unity won't do that. Probably something to do with hardware optimizations or something.

    Unity's PackTextures also has its own algorithm for positioning the textures on the atlas, but that is less important since the positioning is only decided on after the size has been set, and it is the size that appears to be the issue here.

    I would recommend, instead of letting Unity resize the textures for you (halving them in the process), I'd recommend resizing the source textures to an optimal size that would allow all of them to fit into the desired 256x256, then let SM2 handle them and they should fill the 256x256 atlas nicely.
     
  39. playemgames

    playemgames

    Joined:
    Apr 30, 2009
    Posts:
    438
    Hi Brady, I am using a modified version of SM1 and getting the following error when I try to disable/enable the gameobject that is associated with the sprite. The gameobject position on enable turns to NaN and it spits out the error:

    Code (csharp):
    1. !local.IsValid()
    2. UnityEngine.Mesh:RecalculateBounds()
    3. UnityEngine.Mesh:RecalculateBounds()
    4. LinkedSpriteManager:LateUpdate() (at Assets\Plugins\LinkedSpriteManager.cs:157)
    5.  
    6. [..\..\Runtime\Filters\Renderer.cpp line 226]
    7.  
    8.  
    Code (csharp):
    1. !sh->m_AABB.IsValid()
    2. UnityEngine.Mesh:RecalculateBounds()
    3. UnityEngine.Mesh:RecalculateBounds()
    4. LinkedSpriteManager:LateUpdate() (at Assets\Plugins\LinkedSpriteManager.cs:157)
    5.  
    6. [..\..\Runtime\Camera\UnityScene.cpp line 91]
    Basically I am trying to change one sprite character into another by enabling the one gameobject and disabling the other, however I randomly get this error when I run my code to change the character. I am using 2 separate spritemanagers, one for each character.

    I am not sure if this is a Unity bug or if this is something in my code I am not doing right.

    Here is the code I am running (in Boo):

    Code (csharp):
    1. def changeModel (newModel as Entity, modelName as string):
    2.         newModel.gameObject.active = true
    3.         newModel.gameObject.SetActiveRecursively(true)
    4.         if newModel.sprite and newModel.gameObject.active:
    5.             newModel.sprite.manager.StopSpriteAnim(newModel.sprite)
    6.             newModel.sprite.hidden = false
    7.         if gameObject.active:
    8.            
    9.             # Change the model of the entity
    10.             newModel.model = modelName
    11.             # Change the name of the entity to the name of the Model
    12.             newModel.alias = name
    13.         if sprite:
    14.             sprite.manager.StopSpriteAnim(sprite)
    15.             sprite.hidden = true
    16.            
    17.         gameObject.active = false
    18.         gameObject.SetActiveRecursively(false)
    19.         return newModel
     
  40. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    I'm no longer able to support SM1 in terms of updating the code base as all my energies are focused on maintaining and updating the SM2 codebase, however I'm happy to try and help you figure out the issues anyone may run into using SM1. The reason I point that out is I think this may be a case where the SM1 source may need to be modified for your special case.

    The error you're receiving is usually produced when a mesh's bounding volume is 0, so if you only have one character and it gets disabled, then all the vertices that comprise that SpriteManager's mesh will get transformed in LinkedSpriteManager.TransformSprites() and will probably be undefined (NaN) since the transform by which they're being transformed is attached to a disabled GameObject. So when the bounds are recalculated, you'll get that error.

    This is just my hypothesis as to what may be happening, but here are a couple of things you can try:

    1) If the character is disabled, and the only thing in the SpriteManager in question is that character, there's no need to do a bounds recalculation, so you could turn off automatic bounds recalculation while the character is disabled, or you could even disable the LinkedSpriteManager GameObject itself altogether - saving performance in the process.

    2) Try putting a check at the top of Sprite.Transform() to see if the client GameObject is active or not like so:
    Code (csharp):
    1.  
    2. if( !m_client.active )
    3.    return;
    4.  
    This will cost you performance since this check will e done for each transformation, but if you only have one sprite in each manager, it should be no big deal.

    If neither of the above suggestions work, then my diagnosis is likely wrong and it could be a result of some of the modification to which you referred earlier.

    I hope that helps.
     
  41. playemgames

    playemgames

    Joined:
    Apr 30, 2009
    Posts:
    438
    Thanks Brady, I know you are busy with SM2 I was just wondering if you had encountered something like this before.

    Thanks for taking the time out to reply on this, I think you are right though it is probably running the calculation for the mesh when it is disabled hence the NaN. Otherwise it could be my code, everything else seems to run kosher though, I'll post my findings on it after some tests.

    EDIT:

    Yep, Brady you were right, it had to do with the null GameObject, I dropped that code into the Sprite.Transform() and it worked perfect after that. Thanks for the help!
     
  42. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    There is a minor bug in SpriteManager1 regarding PixelCoordToUVCoord(). The Y will be off by one unless you increment it before passing the vector to PixelSpaceToUVSpace().

    Code (csharp):
    1. public Vector2 PixelCoordToUVCoord(Vector2 xy)
    2. {
    3.     // Must increment xy.y by 1, otherwise the conversion will be wrong.
    4.     // For a 512-pixel tall material, the typical pixel range is 0-511.
    5.     // In PixelSpaceToUVSpace(), it would use 511 / 512, which isn't the
    6.     // bottom-most pixel.
    7.     xy.y++;
    8.  
    9.     Vector2 p = PixelSpaceToUVSpace(xy);
    10.     p.y = 1.0f - p.y;
    11.     return p;
    12. }
    13.  
    14. public Vector2 PixelCoordToUVCoord(int x, int y)
    15. {
    16.     // Increment Y before passing the variable
    17.     return PixelCoordToUVCoord(new Vector2((float)x, (float)++y));
    18. }
    If you wanted to reference just the first row of pixels in the material, you would use PixelCoordToUVCoord(0, 0) and PixelSpaceToUVSpace(512, 1).

    Without the adjustment to Y, you'd end up with a Coord vector that pointed to the upper-left corner of the pixel in the row you want to copy, but the Space vector would actually grab the last row of pixels in the material.
     
  43. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Ahh yes, thanks for pointing this out!
     
  44. CaptainKiyaku

    CaptainKiyaku

    Joined:
    Feb 8, 2009
    Posts:
    324
    I have a question.
    I used your SpriteManager a lot of times but i always only used one big Atlas Map.

    So when i want to use a second atlas map i have to create a new object with a second LinkedSpriteManager and the new material?

    The thing is, when i use a sprite animation tileset for my character, and have different spritesets for different animations, do i have to create a new Spritemanager for every animation i want to use? (one animation image is 512x512 as they have many frames).

    Or another example, i have 2 big background images (512x512 and they contain 2 backgrounds, each 256x512).
    So when i have like 4 images of this (each 512x512) i would create 4 SpriteManagers if i want to display them at the same time?

    Or can you somehow use several materials in one SpriteManager?

    Thanks
     
  45. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    You must use only one material per manager - that's just the way Unity (and for that matter, graphics hardware) works. This is because the performance gains were a result of it using a single mesh (and even with batching now, batching only works when meshes share the same material).

    However, on iPhone, the max texture size is 1024x1024, so if you can fit multiple animations on a single texture, you can use multiple animations, no problem. But if you need a second atlas to be used concurrently, you'll need a second manager, etc.

    If, however, you're only going to use one atlas at a time anyway, you could switch out the textures in the same manager, but that's not likely to be your situation.
     
  46. moocher

    moocher

    Joined:
    Nov 23, 2009
    Posts:
    17
    Hi.

    When using multiple SpriteManagers, or LinkedSpriteManagers, how do you control the order in which they are drawn? The documentation specifes that each SM must be created at position (0, 0, 0). If that is the case, how is the draw order determined?
     
  47. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
  48. moocher

    moocher

    Joined:
    Nov 23, 2009
    Posts:
    17
    Yes, I understand that drawLayer may be used to organise sprites within each SpriteManager. However, if I have multiple SpriteManagers, how do I force SpriteManager 1's sprites to appear in front of SpriteManager 2's sprites, or vice versa?
     
  49. Brady

    Brady

    Joined:
    Sep 25, 2008
    Posts:
    2,474
    Ahh, I see what you're asking.

    Unity depth sorts, I believe, according to the center point of a mesh's bounding volume. So I believe to get manager 1 to draw in front of manager 2, make sure its sprites are all nearer, on average, to the camera. This causes the center point (the average of all sprite locations) of the bounding volume to be nearer than the other.

    If, for some reason, you don't want to have to do it this way, and your camera doesn't move too much, you could actually create some dummy sprites at startup such that the manager you want to be drawn on top gets sprites created nearer to the camera, and the other farther away, then manually invoke a bounds calculation, and leave automatic bounds recalculation turned off. Then remove those sprites and proceed with your game. That will setup the initial bounding volumes where you want them and leave them there, and from that point forward, you don't have to worry about how you position your actual game sprites during gameplay.

    Just be sure your camera doesn't move too much since failing to recalculate the bounding volume could mean that if the volume moves out of the camera's frustum, all the sprites attached to that manager will stop being drawn.
     
  50. Michael-Ryan

    Michael-Ryan

    Joined:
    Apr 10, 2009
    Posts:
    184
    I modified Unity's "Particle/Alpha Blended" shader to fix this issue. You can create your own shader with the following shader code, or you can download the attached shader and use it instead. If you do not see a file attached to this post, you must sign in to the forum first.

    I just enabled the Zwrite function that was disabled in the original particle shader. I'm not too familiar with shader language, so a more optimized shader might work just as well with SpriteManger.

    The first line of the shader specifies where it will be located in your Unity project. In this case, it will be located under "GUI/Alpha Blended".

    Code (csharp):
    1. Shader "GUI/Alpha Blended" {
    2.     Properties {
    3.         _TintColor ("Tint Color", Color) = (0.5,0.5,0.5,0.5)
    4.         _MainTex ("Base (RGBA)", 2D) = "white" {}
    5.     }
    6.  
    7.     Category {
    8.         Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent" }
    9.         Blend SrcAlpha OneMinusSrcAlpha
    10.         AlphaTest Greater .01
    11.         ColorMask RGB
    12.         Cull Off Lighting Off Fog { Color (0,0,0,0) }
    13. //      Cull Off Lighting Off ZWrite Off Fog { Color (0,0,0,0) }
    14.         BindChannels {
    15.             Bind "Color", color
    16.             Bind "Vertex", vertex
    17.             Bind "TexCoord", texcoord
    18.         }
    19.  
    20.         // ---- Dual texture cards
    21.         SubShader {
    22.             Pass {
    23.                 SetTexture [_MainTex] {
    24.                     constantColor [_TintColor]
    25.                     combine constant * primary
    26.                 }
    27.                 SetTexture [_MainTex] {
    28.                     combine texture * previous DOUBLE
    29.                 }
    30.             }
    31.         }
    32.  
    33.         // ---- Single texture cards (does not do color tint)
    34.         SubShader {
    35.             Pass {
    36.                 SetTexture [_MainTex] {
    37.                     combine texture * primary
    38.                 }
    39.             }
    40.         }
    41.     }
    42. }
     

    Attached Files: