Author Topic: Clipping panel animation problem  (Read 7106 times)

electrodruid

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 48
    • View Profile
Clipping panel animation problem
« on: April 27, 2013, 07:00:04 PM »
There is a problem when animating a UIPanel's clipping region which means that widgets on the panel which should be drawn end up not getting drawn at all.

I first encountered this in a fairly complex UI scene I was working on, although I've reproduced the problem in a very simple scene. I don't know if there's a way to send you the scene file (I can do so if you want me to), but it's probably simple enough for me to describe. It looks like this:

UIRoot
- Camera2D
-- UIPanel (with an Animation)
--- UISprite

The UIPanel is at (0,0,0) and has an Alpha Clip which is initially set up with centre (0,0) and size (100,200). The Animation is set to play automatically, has the culling type set to Always Animate, and the animation itself simply animates the Clip Range W from 1 to 200 over a second.

The UISprite is just a simple sprite which I've made 100*100, with the pivot point at the Top. This could be any widget though, I've seen the problem happen with UILabels as well. Now, when the sprite's transform starts out at (0,0,0) and you hit play, everything works as expected: The clip panel starts 1 pixel high, then expands and you see the sprite appear from the top down (like a fill sprite with an inverted vertical fill). However, if you set the sprite's transform to (0, -1, 0) or some other negative y value, then the panel expands but you never see the sprite. The Inspector view for the panel says that it contains 1 Widget but 0 Draw Calls. The only way to make the sprite appear is by editing its transform in some way, which forces a refresh and makes the sprite appear.

I've had some trouble following the ins and outs of the panel/widget visibility code, so I might be wrong here, but I think what happens is as follows:

- Scene gets created. Animation is started automatically, setting the initial clip region to (100,1)
- UIPanel.LateUpdate adds the widget(s) to the panel, but notices that the sprite is just outside the clip region (its top edge being -1), so sets it as not visible
- In subsequent frames during and after the animation, nothing changes in the sprite's material, depth or alpha, meaning it's never added to the panel's mChanged list, so is never passed to the Fill method to have its visiblity reconsidered. Only some external effect that changes the transform or material causes this to happen and the sprite to reappear.

How can I get around that? It seems to me that if a clip region is animating, the panel should consider all of its widgets to have changed, and so reprocess them every frame. Or if that's too inefficient, perhaps the panel needs to work out at which point it will be biggest, and base its calculations from that. Or should I write some custom thing than, on the first update, sets the panel to some sufficiently big size, marks all of the widgets dirty and then sets the size back to whatever the animation had set it to?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Clipping panel animation problem
« Reply #1 on: April 27, 2013, 09:37:08 PM »
When you say transform, what are you talking about here? Position? Rotation? Scale?

electrodruid

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 48
    • View Profile
Re: Clipping panel animation problem
« Reply #2 on: April 27, 2013, 09:43:48 PM »
My bad. In general, I was talking about the position. As in, the panel's position is (0,0,0), and rotation and scale are the defaults of (0,0,0) and (1,1,1) respectively. The sprite's position when there are problems is (0,-1,0), rotation is (0,0,0) and scale is (100,100,1). When I talk about making the sprite appear by editing the transform I'm talking about making changes to any aspect of the transform whilst in Play mode, after the animation has happened and the sprite has failed to appear. I was generally doing it by editing a position value, although I found that editing the rotation or scale also caused it to reappear. Just pick any number in the transform, change it to any other number, and the sprite appears. Change it back to the original value, it stays visible. Does that help?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Clipping panel animation problem
« Reply #3 on: April 27, 2013, 09:49:07 PM »
I generally advise simply adjusting the Alpha value on the panel. It's a lot easier. A lot easier.

electrodruid

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 48
    • View Profile
Re: Clipping panel animation problem
« Reply #4 on: April 27, 2013, 10:08:26 PM »
What do you mean? Have the panel fade in rather than open up? I'm not sure that's going to work for me. Or do you mean supplementing the clip bounds animation with a (possibly quite subtle) alpha fade just to force the panel to update?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Clipping panel animation problem
« Reply #5 on: April 27, 2013, 11:53:53 PM »
I mean replacing your clip bounds animation with a panel fade-in. You can also scale in the entire window instead of adjusting clip bounds. I'm not sure what the point is of scaling clip bounds. All it does is messes with positioning making your life a pain.

electrodruid

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 1
  • Posts: 48
    • View Profile
Re: Clipping panel animation problem
« Reply #6 on: April 28, 2013, 07:43:38 PM »
Everything in NGUI already messes with positioning - anchors, stretches, the lot. Adding clip regions into the bargain doesn't bother me, in fact I've already had to write custom UIStretch components to handle panel clip areas, grid spacings, colliders and label regions. And surely you can see that scaling clip bounds on a panel is not the same thing as scaling the UIPanel's actual transform? The first reveals the panel as if it's sliding out from somewhere, and the second sort of inflates it, making things look squashed until they've fully expanded.

Anyway, I wrote what I need. It's ugly and probably really slow, but it fixes the problem, in case anyone else is insane enough to want to animate panel sizes :)

  1. // To be applied to an object that contains a UIPanel component and an Animation component which changes the panel's clipping region
  2. public class UIPanelAnimFudge : MonoBehaviour {
  3.        
  4.         UIPanel         mPanel;
  5.         Animation       mAnimation;
  6.         UIWidget[]      mWidgets;
  7.  
  8.         void Start ()
  9.         {
  10.                 mPanel = GetComponent<UIPanel>();
  11.                 mWidgets = mPanel.transform.GetComponentsInChildren<UIWidget>() as UIWidget[];
  12.                 mAnimation = GetComponent<Animation>();
  13.         }
  14.  
  15.         void Update ()
  16.         {
  17.                 if(mAnimation.isPlaying)
  18.                 {
  19.                         foreach(UIWidget widget in mWidgets)
  20.                         {
  21.                                 widget.MarkAsChangedLite();
  22.                                 widget.visibleFlag = 1;
  23.                         }
  24.                 }
  25.         }
  26. }
  27.