Tasharen Entertainment Forum
Support => NGUI 3 Support => Topic started by: ENAY on August 10, 2012, 11:19:10 PM
-
Ok Arenmook (and everyone else who is reading) :)
Been using NGUI for a fair while now, I have some questions about NGUI/Unity that I have been mulling over for a while, just wondering if anyone else has had any experiences like me.
(1) Whether or not it is me I don't know, but I find draggable panels to be pretty slow on iPhone4. Everything else, iPad2, iPhone3, iPhone4s seems to be ok. But just having one draggable panel, and especially 2 on the iPhone4. If that is all I have in my scene, there is a significant performance hit. Just wondering if it something I am doing wrong. But from my experience it is slow. Maybe an issue with shaders? I heard the fillrate of the iPhone4 is particular poor.
(2) Each Menu you create starts off with the Object name, then a Camera, Panel, Anchor etc, and from inside there you can create your own menu system. My question is about cameras.
If I say had a title_Screen menu system all contained within one object, that uses one camera. Is there going to be a performance hit if I have say a separate asset for ingame_menu and then chatwindow_menu?
Having 3 or 4 cameras is surely going to be a performance hit? Then again I don't really know too well how Unity works, if I have multiple cameras, surely each is just going to be called separately and is not really much different to adding an extra draw call, especially if each camera is rendering a separate layer.
Or am I wrong? I just don't know.
(3) UIDraggablePanel
The DraggablePanel works by having all the items in the draggable panel present and as you drab the panel they pop in and out of view. By my thinking, if I have 10 or 1000, if only 10 are shown in the window at any one time then surely there is no performance by having 1000? Problem is, deleting objects and creating them on the fly is surely going to bad for garbage collection. My question is basically, if I create 100 objects as my max and even if I am only using about 10 or so at a time on screen, is there a performance hit for having so many in the panel. This is of course in relation to UIDraggablePanel seemingly being quite slow on the iPhone4.
Thanks for reading :)
-
I have similar experience..
NGUI become slow with any kind of "motion" because panel has to build geometry of all UI elements in every frame.
I think that's not that good architecture..
Making 1 draw call is needed for performance.. but, in my test, geometry building architecture actually drops performance in many case.
Even in idle state, panels and widgets have to check their state changes in every frame that cause overhead main thread.
-
J. Park, if possible you should use multiple panels to isolate whichever geometry changes frequently, so the other panels don't have to rebuild everything every frame. Individual panels can also be marked static, telling them that the geometry is not expected to change, so it shouldn't even take the time to check the widgets to see if they've changed. You can turn that flag on and off at runtime for panels that are static most of the time but change intermittently. Even with multiple panels, unity can batch the draw calls as long as they're using the same material, so you can still end up with a single draw call if you're careful.
ENAY, regarding your second question, in most cases you should be able to set up your UI under a single root, in one layer, with a single camera. You can add objects to that root as you need them and destroy them or mark them as inactive when you're done. You should only need multiple layers and cameras if you're doing something really complicated.
With UIDraggablePanels, my understanding is that performance shouldn't be hurt by having a large number of non-visible widgets, as long as their geometry isn't changing. (Dragging the panel around doesn't change the geometry, it just moves the whole panel.) Dynamically adding and removing the objects as needed probably would be worse for performance, but I would defer to ArenMook and PhilipC on that question.
-
Draggable panels can be extremely fast if you set them up correctly. Look in the provided example for that. If you drag something within the panel, it will be slow as it will cause the geometry to be rebuilt. If you are dragging the panel itself, or using UIDraggablePanel, then it will be fast because nothing is actually moving.
You can increase performance further by marking certain panels as static, indicating that widgets inside will not change their size/color/position changes. This will cut down on some checks, improving performance.
If you're clever, you can actually enable the "static" by default, but turn it off when you believe your panel will need to be changing. For example -- when you click on a button. You can then turn it on again in the next frame.
-
In regards to the original question... having multiple cameras is always going to be more expensive than having only one camera. In Windward I have one camera, and underneath it a bunch of anchors with all the windows I need (usually disabled until I need them).
-
Hi guys, thanks for all the tips :)
Ryan,
As I am aware, a UIPanel takes a separate geometry and Drawcall so having multiple inside a panel is going to make things slower.
My UIDraggablePanel, I am using basically the same setup as the NGUI example, just moving the panel and not the objects.
By the way, if you have a UIPanel inside a UIPanel and either one is marked static or static, what actually happens?
I am presuming the most parented UIPanel option cancels out everything else. The only thing that could explain my slowdown is that my draggablepanel is inside a UIPanel already, although only the second UIPanel is draggable.
-
All nested panels are treated as separate entities. Nothing is inherited.
-
That would make sense.
I just came across a very annoying problem, which I thought was a bug, but isn't.
If you have a UIPanel set to static, if you move things around in the editor even without compiling, nothing moves unless you click on Apply or hit CTRL+S. Has been driving me bonkers for the past few hours. I rebooted and nothing happens.
So anyway, yes, it is practically impossible to edit your menus when the UIPanel is set to static.
-
You can increase performance further by marking certain panels as static, indicating that widgets inside will not change their size/color/position changes. This will cut down on some checks, improving performance.
If you're clever, you can actually enable the "static" by default, but turn it off when you believe your panel will need to be changing. For example -- when you click on a button. You can then turn it on again in the next frame.
Checking "static" may not be applicable in most case. At least, we have to turn off "static" property to use button roll over effect.
Turning on/off "static" dynamically make codes more complex.
Why don't you just relying on dynamic batching?
By doing that, you can also make 1 drawcall without performance drop.
UIpanel's geometry building architecture has nothing better than dynamic batching.
I really like component based structure and functionality of NGUI.
I actually moved to NGUI from EZGUI.
But after some test, I can't understand why you chose this architecture...
-
Try a simple test with EZGUI. Create a 3D UI window with a bunch of widgets in it, then turn it by 30 degrees. What happens? The draw order gets all screwed up.
This is why I am doing my own batching. With NGUI, the draw order is controlled by the user. With EZGUI it isn't.
-
Try a simple test with EZGUI. Create a 3D UI window with a bunch of widgets in it, then turn it by 30 degrees. What happens? The draw order gets all screwed up.
This is why I am doing my own batching. With NGUI, the draw order is controlled by the user. With EZGUI it isn't.
In 3D UI, I can see draw order problem with dynamic batching as you mentioned.
But, I think much more people use 2D UI than 3D UI. Should 2D UI performance be sacrificed because of 3D UI?
How about giving option to use dynamic batching?
If I use EZGUI with SpriteManager2 combination(I wanna say I'm not a fan of EZGUI), I can use static batching property called sprite manager with draw order setting. In other words, it's kind of an option. We can choose dynamic or static batching.
"2D Tookit" works with dynamic batching in default, and also has a static batcher component. We can choose dynamic or static batching.
NGUI is forced to be used only with static batching technique...
-
> How about giving option to use dynamic batching?
Well, I suppose a nice feature is Arenmook has time but right now I think Static batching is much better when you get used to it, so I don't need it. For now dude, you just have to pull your finger out and cleverly design your GUI instead of moaning about it here.
-
Unfortunately NGUI was designed to be manually batched from the start, so making it use dynamic batching isn't feasible at this point.
-
(3) UIDraggablePanel
The DraggablePanel works by having all the items in the draggable panel present and as you drab the panel they pop in and out of view. By my thinking, if I have 10 or 1000, if only 10 are shown in the window at any one time then surely there is no performance by having 1000? Problem is, deleting objects and creating them on the fly is surely going to bad for garbage collection. My question is basically, if I create 100 objects as my max and even if I am only using about 10 or so at a time on screen, is there a performance hit for having so many in the panel. This is of course in relation to UIDraggablePanel seemingly being quite slow on the iPhone4.
I have a draggable panel with clipping and instantiate about 150 items on it, it's very slow.
I optimize my code with the idea of "object pool", only create 5 items, and shift/un-shift the item to bottom/top of the draggable panel when it's out of visible area.
No more instantiating and destroying at runtime.
-
Just to throw my 2ยข in. Dynamic batching comes at a cost. Batching isn't free not to mention the drawing order issue that ArenMook mentioned.
I agree with others here in that if you need a list of hundreds of elements, maybe the UI needs to be rethought in order to better fit the batching system that NGUI is using.
-
Simon129, can you explain to me that works?
So you only have enough items to fill the window and as you drag, you simply scroll all the contents of the viewable by 1?
The shift and unshift part, you move the outside of the drag area?
eg I have items scrolling in the X direction, so I should move all the items outside of the area each side by say about 500 (or a huge number) in the Y direction and then just put them to 0 in the Y direction when they are viewable inside the panel?
Not quite sure I understand your explanation. Sorry about that :(
By the way, instantiate is very slow isn't it. What I have been doing is creating 100 items, and then just deleting the objects I don't need. Deleting items is incredibly fast and it seems better doing that than instantiating at all.
-
Simon129, can you explain to me that works?
I upload a picture, and hope you can understand what I mean.
-
@simon
How do you get your objects to align properly when you reposition them? I've managed to get a menu slot that scrolls out of view move to the end of my list, but the positioning is never quite right. If the player drags slowly, the slot goes into the correct position, but if the player drags quickly, it appears far down the list. Maybe UIGrid refresh is what I need? Not sure.
-
You're using the same technique that is used in Android for ListView I think, really nice :)
Would love to see that by default in NGUI ^^
-
Hi,
I am also having performance issues with draggable panels. I have a scroll setup in the same way as in the example. It runs fine even with +1000 items. I use 2 different atlas, an so I get 2 drawcalls. However, things go really bad when I have a UITexture as part of the items. My drawcalls go from 12 to +200, and framerate gets really sluggish. Do you guys know if that's expected when using UITexture in a draggable panel? Do you have any solution?
UITexture is really importante in this case, cause I have those items coming from a database.
Thanks in advance.
-
UITexture draws a texture as a separate draw call. It won't be batched because it can't be batched. Only atlas-using widgets can be batched.
Solution is simple: don't use the UITexture. It's meant to be used only for things like large backgrounds that shouldn't be atlased.
-
So, just to clarify, the solution you suggested requires that I build the atlases on real time, just before populating the panel. Correct? Do you see any other possible solutions?
Thanks again.
-
If you do something similar to what Simon suggest above, you can use UITexture just fine.
Each UITexture adds one extra draw call, by keeping the number of UITedxtures down, you keep the number of draw calls down. You just have to be clever about it - it's totally doable.
-
We ran into the UIDragPanel slowdown issue in our game project with 30 or more items in the list.
Simon's solution sounds effective and easy to adopt into many lists at once by abstracting the "pooling" logic into a Monobehaviour. However, if you can't get it to work, we tried an alternative approach which might work well enough for your purposes.
We attached a box collider and a kinematic rigidbody to a game object which would essentially act as the "render window" of the drag panel, as well as to each of the list elements of the drag panel. This let us hook into the "OnTriggerEnter" and "OnTriggerExit" events in a script attached to the render window. We would use these events to toggle the active state of the drag panel children to true or false depending on whether or not they were visible. To prevent some "popping" from occurring as the objects move in and out of view, we made the collider on the render window larger than the area that was actually visible to the player.
The box collider and rigidbody for the child elements will need to be on parent objects to the actual contents of the elements, which are what you actually set to be inactive. If you set the parent object to be inactive or put the collider on the same object as the contents, the collider would also get disabled when the object is out of view, preventing the element from reappearing when it should be in view. Also, the children should be disabled by default, since otherwise they will only be set inactive when they leave the render window, making the list sluggish until the user drags to the bottom.
It seems to work smoothly in the Unity editor, although we're experiencing some lag with it on the iPad (admittedly in a scene filled with other crud that's slowing the game down a bit already), probably due to the overhead of having rigidbodies on so many objects. One option we're considering to work around this is to use a normal drag panel on smaller lists and then switch to the box collider method when the list becomes sufficiently large.
Sorry for the wall of text -- hopefully this is helpful to anyone running into this issue.
-
I upload a picture, and hope you can understand what I mean.
Could you tell , how do you check(algorithm) of visible/invisible obj in clip panel(draggable panel) ?
-
2.6.3 actually has performance improvements that also affect draggable panels. Only for Unity 4.1 or higher, however.
-
Thanks ArenMook for your answers, I have a little question though regarding how to set panel to static, should I use the widgetsAreStatic member or am I missing something? Also is a panel the smallest unit that can be set to static? Like for exemple something to do on UIDragPanelContent?
My second question concerns the same one as Pyro asked : you were suggesting the best way is to always use atlases, but in real-life situation we often get content which are not included in the original build and therefor not incorporated in atlas via the editor, do you suggest that we build atlas at runtime and then use it to create the panel content? If yes would you have any references to exemple of generating atlases at runtime, especialy used in conjunction with a draggable panel?
Thanks in advance for your help
-
1. If your widgets within the panel will never move, scale or rotate, yes set the widgetsAreStatic flag to true to improve performance.
2. Depends on whether you need to limit your draw calls. If you're on a mobile device, then yes, adding dynamically downloaded images to an atlas or a sprite sheet would help. The Atlas Maker class generates everything using code, you could just lift code from there. Just omit the part that saves the texture and prefab to disk.