Author Topic: Having a difficult time with porting my immediate mode GUI to NGUI  (Read 11139 times)

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
I purchased NGUI as a replacement for the immediate mode GUI that I had been creating for a game that I am developing. The primary reason being performance (fewer draw calls than the greedy immediate mode). It's a pretty great system for the most part. However, I am having an extremely difficult time porting what I think is a fairly simple GUI to NGUI's system.

Perhaps the best way to describe this pre-existing GUI is that we have different scales based on the device (2.0, 1.0, 0.5, 0.25, etc), but the GUI tries to be pixel perfect when possible. We do *not* want to simply scale the entire UI as a whole, because then UI elements are too tiny on small devices or too big on large devices. Instead, the scale is used to modify the size of the individual GUI elements (e.g. button is 256x256 on ipad-retina, but 128x128 on iphone). So the layout can look radically different depending on the scale.

NGUI does not seem to like this approach at all. The biggest issue is that I keep needing to define fixed dimensions and fixed anchor offsets of sprites via the inspector and it's not practical at all for my scaling system. Instead, I'd like them to be defined via the size of the source texture (so the SD/HD atlas can drive the layout). It's not the same approach I used with my immediate mode GUI, but might work even better. There's a few other small issues but I think I can figure those out...

It seems like I'm going to need to add a TON of custom scripts to NGUI GameObjects to supplement the missing functionality. I'm really hoping that maybe I'm just missing something. I've had little luck with searching for existing solutions.
« Last Edit: April 25, 2014, 07:13:36 PM by Wisteso »

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #1 on: April 25, 2014, 10:06:03 PM »
I think I've figured out a good solution for my problem.

I was mistakenly thinking that I had to rely on "PixelPerfect" mode to achieve pixel perfect rendering. What I am now doing is using "fixed size", and setting the UIRoot's height to  (screen.height / zoomfactor) where zoomfactor is 1, 2, 4, 8, etc. I also had to set texture filtering to point filtering to get rid of transparency pixels creeping in at 2x zoom.

I then set the "pixel size" of my atlas to 0.5 and let NGUI take care of the rest. When zoomlevel = 2, everything will be zoomed in, however it will still look crisp due to the 0.5 pixel size atlas. Though for 4x zoom to look crisp, I would need to create another atlas with a pixel size of 0.25, but I dont think that will be needed.

If I wanted to save texture memory on the SD devices, I could use a separate SD atlas (and maybe I will), but during development time it will be better to just have one atlas to maintain.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #2 on: April 26, 2014, 02:58:14 PM »
Yup, that's a good solution.

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #3 on: April 30, 2014, 05:03:03 AM »
Thanks for the response, ArenMook. Though I'm having a secondary issue cropping up that your feedback would be much appreciated on... 

The issue is that no matter how I modify UIRoot.manualHeight via code, my static sprites that use OnEnable anchoring (for performance reasons) are still acting upon the default/serialized value instead of the value I set. For example: if I set 480 in the inspector, and then set 720 via code, the UI will still be at 480 scale. One solution is obviously to use OnUpdate anchoring, but I'd really like to avoid that since I will have possibly over 100 static UI elements, and that could be pretty costly on the CPU for the older devices.

The only way I've been able to have OnEnable anchoring work for my UI elements so far has been...

1) Set the height via the inspector (serialization) but this does not allow the dynamic size I need, so it's not really a solution here
2) Change line 41 of UIRoot.cs to be something like "private int manualHeight = SomeClass.getDynamicSize();"

I've tried extending UIRoot.cs and then overriding the value of manualHeight in the constructor, but it does not work either. I think due to serialization overriding my override? I also cant stop that process since I cant leave manualheight blank in the inspector. I've also tried adding my custom script to the Script Execution Order registry, right after UIRoot but that didn't help either.

Is there a better way than option 2? Ultimately, I would rather have that ugly one line hack than have 100+ objects needlessly calling Update() constantly when they will never change their anchor values.

Thanks for the help so far, and thanks for reading this!
« Last Edit: April 30, 2014, 05:18:22 AM by Wisteso »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #4 on: April 30, 2014, 05:18:27 PM »
Just UIRoot.Broadcast("UpdateAnchors");

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #5 on: May 01, 2014, 03:59:24 AM »
Aren, I very much appreciate all the help so far. I'm definitely making tons of progress. I hate to keep coming back with issues, and like to figure things out on my own but i've spent several hours on this new problem without much luck....    I'm not sure if this issue has been going on all along, or just now noticeable, but somehow my UI keeps losing it's pixel perfect state based on seemingly random reasons.

If you look at the screenshot, it's showing an example of my UI is being distorted by about 1% which is causing little fractures all over the place. I'm using sliced sprites now per your suggestion, and all dimensions are divisible by 4 (no more odd dimensions). I have workarounds for the fracturing, but they make no sense at all.

(Keep in mind that the atlas is 0.5 pixel size for both modes.)

1) If I'm in my "HD screen" mode (with manualHeight set to half the screen height), the issue only happens for even resolutions. I can subtract 1 (one) from manualHeight and everything looks great again. So for 720, i'd use manualHeight of 359 and it looks good. For 719 and any other odd height, it will naturally look fine.
2) If I'm in my "SD screen" mode, with manualHeight set to the full screen height, all bets are off. With Unity's built-in player the problem occurs for any screen height if Unity is maximized, but never occurs if Unity is unmaximized (i realize that sounds insane). It does *not* occur in a standalone build at all.

I've checked everything for errors. I'm not doing anything fancy except the halving of the manualHeight. Every objects' scale, position, and rotation look good (integer values, aside from minor float rounding errors here and there). UIRoot being the exception, since it's doing it's scale conversion magic.
« Last Edit: May 01, 2014, 04:08:55 AM by Wisteso »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #6 on: May 02, 2014, 07:41:38 AM »
Quote
the problem occurs for any screen height if Unity is maximized
Open the Stats window. You will most likely notice that the width or height is not dividable by two. Odd dimension = stuff like this happens when point filtering is used, or blurriness when other types of texture filtering are used.

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #7 on: May 02, 2014, 09:07:06 PM »
Hmm I didn't think to check the width being divisible by two, but I have been checking the height. Though this issue was occurring with a proper standalone build too (running in 720p and 1080p) which is definitely a safe resolution.

Another new data point btw: it will happen to some widgets, but not other parts of the GUI which are near-duplicates (not prefabs though)...

I'm guessing it must be an odd sized resolution (like you said), or somehow there's a bad scale value sneaking in somewhere. I'll keep hunting and post back if I still have no luck after a few days.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #8 on: May 04, 2014, 10:33:30 AM »
Is any part of your UI not pixel-perfect? When you duplicate objects, the scale is not (1, 1, 1), but rather something like (1.008, 1.008, 1.008) due to Unity being odd. Select the UIRoot and hit ALT+SHIFT+P to force everything to be pixel-perfect.

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #9 on: May 04, 2014, 10:59:13 AM »
The ALT-SHIFT-P seems to have fixed it. I was seeing the 1.0008 thing showing up before as well, so yeah it was probably exactly what you said (some weird scale glitch with Unity). I'll keep an eye on the issue, but my usual way of reproducing the issue is no longer showing the bug! Hooray!! Thank you!

Edit: Spoke too soon. The issue is occurring still. I'll mess with it more later to see if I have better luck.
« Last Edit: May 04, 2014, 11:51:02 AM by Wisteso »

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #10 on: May 06, 2014, 05:46:36 PM »
This issue is still going on, however I'm starting to notice some very unusual trends.

  • Strangest of all is that I dont see the problem on any of my devices (iPad Mini, iPad Mini Retina, and Android 4.3). The iPad Mini uses SD, while iPad Mini Retina uses HD. I *only* see it happening with builds that run on my PC (happens with both SD and HD, but in different ways).
  • Sliced sprites show the symptoms more obviously than other elements. I imagine this is because tiled sprites use far more polygons and thusly have more vertices which can be out of alignment
  • With simple sprites, pixels bleeding in from neighboring sprites, which should not be happening since I am using point filtering rather than linear


Aren, if we still cant figure this out, would you be open to looking at a simple project that I can confirm reproduces the issue (on my end at least)?
« Last Edit: May 06, 2014, 08:48:29 PM by Wisteso »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #11 on: May 06, 2014, 10:05:35 PM »
Well first of all, don't use point filtering. Use trilinear filtering, and make sure to add some padding to the sprites you're displaying that you notice an issue with. By default NGUI adds 1 pixel of padding around sprites (chosen in the Atlas Maker). You can further modify each sprite, adding transparent, tiling, or clamped borders.

Next, what's the size of your window? If the size of the window is not even (ie: dimensions are not dividable by two), pixels won't align properly.

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #12 on: May 07, 2014, 01:50:14 PM »
Simple stuff first, the window (panel) size is 360 width and 100% of the "UI Root" height. The screen resolutions that I'm concerned with are all the standard iOS ones (iPhone 4 and newer). I've made sure all images are divisible by 4, but the border offsets of sliced sprites might sometimes only be divisible by 2. (e.g. a sprite that's 64x64 but has top/bottom/left/right offsets of 22 rather than 24). Is that okay?

As far as filtering, I'd really really like to avoid using linear filtering if at all possible, since I think it will just hide the underlying issue and also cause blur with the textures when there isn't an exact 1-to-1 mapping of texels to pixels. We're also only using integer zoom levels (1x and 2x), which should be totally compatible with point filtering. (for cases where linear filtering is a must, I dont think trilinear has any benefit over bilinear when using ortho perspective and fixed Z values, but it will still lower FPS).

I'm wondering if half pixel coordinates are used by NGUI/Unity3d? When doing OpenGL/D3D programming, I remember similar issues occurring without it being used.

(Sorry in advance about my reluctance, but our game has a need for extremely precise graphics that aren't blurred/smoothed)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #13 on: May 08, 2014, 01:55:41 AM »
Honestly, I would be very surprised if you notice any is any noticeable performance difference between point filtering and linear filtering considering how well it's optimized on the hardware. As for blurring... well, yes. If you upscale you get blur with linear filtering and blockiness with point filtering. Depends on which one you see as the lesser of two evils I suppose.

NGUI automatically adds the half-pixel offset on DX9 devices (so only the windows platform). It's not used on mobiles. Line 837 of UIPanel.cs, or just search for "half-pixel".

Wisteso

  • Full Member
  • ***
  • Thank You
  • -Given: 21
  • -Receive: 3
  • Posts: 103
    • View Profile
Re: Having a difficult time with porting my immediate mode GUI to NGUI
« Reply #14 on: May 11, 2014, 10:33:56 PM »
We definitely want the blocky "nearest neighbor" look as opposed to the blurry "bi/trilinear" look.

So since bi-linear won't solve the issue for us, there's a few more thoughts I had with the symptoms we're seeing...

1) I'm pretty sure that using "nearest" mode for texture filtering means you do not need borders to prevent bleeding, but we've been seeing single pixel bleeding (from neighboring sprites in the atlas) as well. The only way you should see bleeding with "nearest" mode is with incorrect texture-coordinate values.

2) Perhaps I should have mentioned this sooner, but there's been an "off by one" error that I've been seeing with almost all my sprites since day 1 of using NGUI, which you can see in my attached screenshot (look at the scene view). I'm wondering if perhaps the same root issue is causing all of the above mentioned texel-to-pixel problems.

I have some experience as an OpenGL graphics programmer and I've worked with getting native android apps to be pixel perfect before. If you'd like to work together on figuring this out, I'd be happy to provide examples and do whatever I can.

« Last Edit: May 11, 2014, 10:40:46 PM by Wisteso »