Author Topic: Nicki's Depth Management Tool  (Read 16982 times)

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Nicki's Depth Management Tool
« on: October 06, 2013, 07:54:34 AM »
So, I've gotten to a point where my tool is basically finished, but there's bound to be small tweaks to do here and there.

You open it by going into NGUI->Open->Nicki's Draw Call Toolbox.

This is how it looks:


You can set the depth on Panels and groups of widgets that have the same depth.  If you need to seperate an individual widget, you should expand the widget thingie and click the individual widget to go to it in the inspector, and change that there. I ran into som small issues with doing that directly in the tool easily, so that's not in yet.

The colors are set by Panel. That means that all that have the same colors are drawn by the same panel - so if you see something with the same color and same material in multiple places, that could probably be collapsed by moving the depths closer together.

When the numbers are changed, two buttons appear "Apply depth, Reset depth". Doing it instantly while typing caused too many problems with depths with more than 1 digit.

You install it by just putting the attached script into a Editor folder (doesn't matter where). I've decoupled it as much as possible from the rest of the NGUI core, so I don't stumble on side effects (DrawHeader set the GUI.backgroundColor to white, for instance), but I do still use the NGUIEditorTools.BeginContents/EndContents and NGUITools.GetHierarchy.

When you fold a draw call together it works as it does in the individual panels, and it does overlap with those - so if you fold it in the panel, or in my tool the others fold as well.

In this tool, when a draw call is folded, it turns bright red, to indicate that this should only be a temporary state and you should fold it back out again - they will stay folded together until you unfold them, so if you think you have missing references, that might be it.

Anyways, hope you can use it.

Updated link 15th jun 2014 http://nickithansen.dk/stuff/drawcalltoolbox.unitypackage (Unity 4.5+, NGUI 3.6.4+, no guarantees below that)
« Last Edit: June 15, 2014, 02:58:50 PM by Nicki »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #1 on: October 06, 2013, 10:29:07 PM »
The folding of draw calls no longer hides the draw call in 3.0.2 -- I assume you noticed the newly added explicit checkbox on the matter, and the fact that it doesn't save the state from edit mode to play mode anymore in order to avoid confusion.

Aside from that, might be a handy tool if it's cleaned up a bit visually.

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #2 on: October 07, 2013, 01:23:34 AM »
I did not! :) I made it with 3.0.1 and only added the panel interaction and 3.0.2 this weekend, so I completely missed that part.

I think it is handy. My main reason for making it, is to be able to jump back and forth to panels and widgets without leaving the window, like it necessarily does on the individual UIPanels. The modifying of depths is actually just extra that I built on top.

It's in a bit of a rough shape, buttons placed a little weirdly here and there, which I intend to clean up, but otherwise, feel free to take it a modify, if you want to put something like it into NGUI.

That goes for the rest of y'all too - feel free to take it and modify for your own needs.

yuewah

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 180
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #3 on: October 07, 2013, 08:31:32 AM »
Is it possible to not using UIPanel to group widgets ( UIButton A ) that is on top of another group of widgets  ( UIButton B ) in 3.0.2 ?
e.g.
UIButton A
|-Background Sprite ( depth = -1 )
|-Icon Sprite ( depth = 0 )
|-Label ( depth = 1 )

UIButton B
|-Background Sprite ( depth = -1 )
|-Icon Sprite ( depth = 0 )
|-Label ( depth = 1 )

In 2.x, I can change z of UIButton to easily move back and front, however, in 3.x, using UIPanel seems too much overhead.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #4 on: October 08, 2013, 02:17:13 AM »
Moving Z has no effect in relation to depth in 2.X. It only works if you have a UIPanel attached to your "UIButton" objects. Not sure why you would want to have a UIPanel there... but in any case, in 3.0.2 you can just specify a depth on your panels, exactly the same way you can specify it on widgets. Panel depth is more important than widget depth. All widgets are sorted by panel depth first, and only then by widget depth.

yuewah

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 180
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #5 on: October 08, 2013, 10:08:27 AM »
In my experience, UIPanel is slow. In 3.0, z won't work, only UIPanel and UIWidget contains depth. And UIWidgetContainer is used to hold more than one widget inside, can it also have depth like UIPanel. Therefore, Button A and Button B can change the draw order using UIWidgetContainer depth.

Button A ( UIWidgetContainer, depth = 0 )
|-Background (UISprite, depth = -1)
|-Icon ( UISprite, depth = 0 )
|-Label ( UILabel, depth = 1 )

Button B ( UIWidgetContainer, depth = 1 )
|-Background (UISprite, depth = -1)
|-Icon ( UISprite, depth = 0 )
|-Label ( UILabel, depth = 1 )

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,154
  • Toronto, Canada
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #6 on: October 08, 2013, 12:49:17 PM »
Widget container doesn't have depth. It's a helper script that's used to make it possible to move a group of widgets at once. Depth is specified either on widgets, or on panels.

Z has no effect in 3.0.

Tiktaalik

  • Newbie
  • *
  • Thank You
  • -Given: 7
  • -Receive: 0
  • Posts: 39
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #7 on: October 09, 2013, 03:39:12 PM »
Does the new depth scheme change anything with regard to the interaction between UIPanels and 3D Objects in the world?

If you wanted to have some 3D object infront of a UIPanel would you simply make the 3D Object have a more negative z in its transform?

Tiktaalik

  • Newbie
  • *
  • Thank You
  • -Given: 7
  • -Receive: 0
  • Posts: 39
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #8 on: October 09, 2013, 04:17:44 PM »
Does the new depth scheme change anything with regard to the interaction between UIPanels and 3D Objects in the world?

If you wanted to have some 3D object infront of a UIPanel would you simply make the 3D Object have a more negative z in its transform?

Answer is right here:
Quote
- NEW: UICamera now has "world" and "UI" event types that affect how raycasts are processed.

Looking at the UICamera.cs, it looks like I just have to switch my camera type to world to get my world stuff to work again.

7realm

  • Guest
Re: Nicki's Depth Management Tool
« Reply #9 on: October 09, 2013, 10:33:53 PM »
I added this tool to my project, and I got a lot of exceptions when I try expand widgets at one of drawcalls.

ArgumentOutOfRangeException: startIndex + count > this.length
Parameter name: count
System.String.Remove (Int32 startIndex, Int32 count) (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System/String.cs:1747)
UIDrawCallOverview.OnGUI () (at Assets/_Scripts/Editor/UIDrawCallOverview.cs:240)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) (at /Applications/buildAgent/work/b59ae78cff80e584/mcs/class/corlib/System.Reflection/MonoMethod.cs:222)

The problem can occur, because I have UIPanel and UISprite on one object. Is that bad practice in NGUI 3.x?

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #10 on: October 10, 2013, 12:53:37 AM »
7realm, I haven't seen that bug in mine. Be sure to use the newest Unity and the newest NGUI as well.

I have an updated version of the tool, where it's more in line with how the UIPanel does the things and with some code cleanup, bit I can only post that once I get home later today.

Sprites directly on the same panel should be just fine, afaik.

ChrisPruett

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 24
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #11 on: October 10, 2013, 10:11:15 AM »
This is an exceedingly useful thread.

We are experimenting with NGUI 3 for a new project we're working on.  Like some other folks in this thread, the new depth workflow is completely intractable for existing projects because we have a very large number of panels that contain a very large number of widgets and are instantiated in unpredictable order (think pop-up dialogs that may themselves spawn other pop-up dialogs that are based on the same prefab, etc).  But, on those projects we also had a lot of problems with depth sorting, so I'm happy to give the new stuff a shot for new projects.

Two questions related to the new sorting approach:

- The panel depth parameter doesn't do what I expected it to do.  I expected this value to serve as something of a depth offset of all children widgets, either by changing their depth values on the fly or by simply sorting the display list by panel depth first and widget depth second.  I expected to be able to sort panels as a single unit in front or behind of other panels by changing this value.  That doesn't seem to be how it works, though.  If I have two overlapping panels with widgets set to the same depth parameter, I get the same results (i.e. sorting of widgets at global scope rather than panel scope) regardless of the depth of the panels.  I can't pull a panel forward by increasing its depth value.  What am I missing?  What is the indented use pattern for this value?

- The new system seems to be splitting the widgets into draw calls much less efficiently than it should.  If my understanding is correct, the idea is a draw call per depth bucket per material in order to guarantee correct overdraw behavior.  But I am seeing widgets that do not overlap anything, that all have the same depth, that are all within the same panel and share the same material being split into multiple draw calls.  This is a panel that contains multiple materials (a sprite atlas and a font), but even when there is no obvious overlap, single widgets are split out from the draw call for their depth group and drawn later for reasons I don't understand.  What's the best way to debug this sort of thing?  My UI has gone from 2 - 4 draw calls under NGUI 2 to around 20 under NGUI 3, even after I've gone through and sorted all widgets into three depth buckets and corrected for widgets of different materials overlapping.

Thanks.

ChrisPruett

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 24
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #12 on: October 10, 2013, 11:06:41 AM »
OK, so, to answer my own question (the second one):

Superfluous draw calls are generated in panels that have multiple materials because UIWidgets are sorted only by panel and then by depth, but never by material.  UIPanel.Fill() walks through all of the widgets (NOT the panels) and maintains a record of the last draw call used as it goes.  If it reaches a widget that can't be placed in the last draw call (different material, different panel, etc), it will split off a new draw call for that widget. 

The problem with this is that the order in which UIWidgets exist in the UIWidget.list is dependent on the order that they are instantiated (well, actually, enabled).  They are sorted by panel and then by depth, but within those buckets the order they appear in is undefined.  So if you have widget A, B, and C, all of the same panel and of the same depth, you'll get three draw calls if A and C share a material but B is something different.  Since they are all at the same depth it would be better to draw A and C in one pass and B in a different pass.

I modded UIWidget.CompareFunc as follows to sub-sort widgets of the same depth and panel by material.  I am now down to 8 draw calls, sorted by depth bucket and material as I would expect, from 22 previously. 

  1. static public int CompareFunc (UIWidget left, UIWidget right)
  2. {
  3.         int val = UIPanel.CompareFunc(left.mPanel, right.mPanel);
  4.  
  5.         if (val == 0)
  6.         {
  7.                 if (left.mDepth < right.mDepth) val = -1;
  8.                 if (left.mDepth > right.mDepth) val = 1;
  9.                 if (val == 0)
  10.                 {
  11.                         Material leftMat = left.material;
  12.                         Material rightMat = right.material;
  13.                        
  14.                         if (leftMat != rightMat)
  15.                         {
  16.                                 if (leftMat != null && rightMat != null)
  17.                                 {
  18.                                         val = leftMat.GetInstanceID() < rightMat.GetInstanceID() ? -1 : 1;
  19.                                 }
  20.                                 else
  21.                                 {
  22.                                         val = leftMat == null ? -1 : 1;
  23.                                 }
  24.                         }
  25.                 }
  26.         }
  27.         return val;
  28. }

This hasn't been throughly tested but does what I expected it to do (fewer draw calls with more verts each) and didn't break my scene. 

Anything wrong with this approach?

Also, I now see what the panel depth value does (sorts groups of widgets by panel depth first), but it doesn't actually correct the problem of widgets in overlapping panels being occluded by panels of higher depth.  Still working on why that is.

ChrisPruett

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 24
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #13 on: October 10, 2013, 12:45:11 PM »
Hello again,

Looks like the core problem I am seeing with sorting is related to UITexture's shared material renderQueue.  Sprites and labels appear to use 30000 as the base render queue (to which the index of the draw call is added to find the actual render queue), but my UITextures have a base render queue of 20000.  So the order of the panels and widgets are correct, but the actual order that Unity draws them is not because the base draw queue is off.

The queue is off because we're using Unity's built-in Unlit/Texture shader for this material, which selects its render queue as Geometry.

So, problem solved: we should be using shaders that select the Transparent queue, as most of the NGUI shaders do. 

It might be worth throwing a warning when a shader that doesn't comply to this policy (i.e. has a material with a renderQueue lower than 30000) since sorting is now entirely dependent on the assumption that all materials are operating with the same base queue.

Cheers,
Chris

ChrisPruett

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 24
    • View Profile
Re: Nicki's Depth Management Tool
« Reply #14 on: October 10, 2013, 12:58:07 PM »
Oh, I see.  UITexture actually selects Unlit/Texture if there's no other material assigned.  In light of the new sorting mechanism, that seems like a bug (or the final renderQueue calculation needs to be based on something other than the shader).

4X POST POWERUP