Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - bac9

Pages: 1 2 [3] 4 5 ... 8
Misc Archive / Re: Seeking a 3D Artist
« on: November 01, 2014, 06:24:06 PM »

I'm having a bit of trouble with root rescaling and anchors. In short, when I change the root resolution (both in edit mode and in play mode), positions of anchored widgets are not updated correctly.

Here is a simple setup:

  • Anchor a sprite to a panel (say, a background snapped to edges)
  • Anchor another sprite to that first sprite (say, a window covering half of that background)
  • Anchor another sprite to that second sprite (say, a shadow of that window)

When you change UIRoot resolution, widgets are properly updated, but anchor-based positions are not propagated because their positions are based on other positions that were not updated yet.

The only way I can get my UI in order right now is to manually enable and disable UI root object three times, with every update making anchors one level deeper right. I'd love to know if there is a way to instantly invalidate all anchors AND force their update in hierarchical order so that UI will snap itself together in one update instead of taking unpredictable amount of takes. Ah, and few things:

  • Performance is not a concern, I only ever need that operation to run in the edit mode (when I change screen density or rescale the window) and in the very beginning of a play session (when root gets scaled appropriately for a detected device)
  • Every single anchor in the project is set to OnEnable as I don't need any runtime anchor-based updates - but as far as I remember from NGUI code, that has zero effect on edit mode where anchors are using always-on updates
  • I have tried panel.SetDirty (), panel.RebuildDrawCalls (), broadcasting CreatePanel message and all other stuff I found in the documentation, but nothing provides the desired effect - lower hierarchy elements only get their positions updated after manual game object toggling.


Edit: Ah nope, disregard that, forgot about panel.Refresh () which seems to work great there :)

Misc Archive / Re: Building Material Design UI with NGUI
« on: October 30, 2014, 11:39:36 AM »
Worked on some refactoring today, so not much to show. But I added one new fancy visual tool: .aco importer! Those files are Photoshop format containing color palettes (swatches) and are widely used to distribute palettes accompanying various design documents. You can download one here, for example:

Now you can load one straight into Unity:

You can use it with the standard screen-space color picker from Unity to color your NGUI widgets in a consistent manner. You can also assign those colors to screens, allowing entities controlled by them to automatically use consistent coloration. Pretty neat time saver.

Misc Archive / Re: Building Material Design UI with NGUI
« on: October 29, 2014, 09:11:50 AM »
Had a look at shadows again. I was never fully satisfied with how my dynamic shadows, while fancy, only shifted outward from the widgets and had quite a boring linear gradient, giving them impression of a cheap photoshop effect.

For all the nice look, they weren't really similar to the shadows detailed in guidelines:

So I charted those values into curves, fixed some obviously erroneous values from above that broke those curves, and had a go at rewriting the shadow implementation. Some would say it does not matter, some would say shadows looked alright as they were - sure, maybe. I might leave the old and simple implementation as a low-quality optional mode. But I'm adding a new one, and doubt anyone will want to go back. For a minor performance cost, you get this beauty that completely replicates offline quality you get from layered Photoshop/Illustrator effects. In realtime:

It's driven by three curves (blur, offset, alpha) and an altered post fill method that takes a lot of stuff into account (visibility of the shadow at low radius, separate inward/outward offsets, etc.) and damn it's satisfying to see it work. As always, it's completely automatic: you just add a component to a sliced sprite object and get a slider driving the shadow, and when you remove that component, child sprite it was employing is cleaned up.

NGUI 3 Support / Re: How to use Tweening Bounce animation?
« on: October 29, 2014, 05:47:02 AM »
To add to that, here is a cheat sheet showing how most popular curve types are supposed to look.

Misc Archive / Re: Building Material Design UI with NGUI
« on: October 28, 2014, 06:11:11 PM »
Hell yeah, everything seems to work right now!

You can now work with any screen density right in the editor, which is especially nice when you have properly prepared all atlases (for 160dpi, 240dpi, 320dpi, 480dpi and 640dpi). I did prepare them, of course - all five atlases, 440 core images each, with proper slicing, resolution, color, atlas scaling, etc. Murdered whole day converting and preparing them from SVG sources by Google. Will probably bundle those resources with the release if it's not prohibited by the license. They are suprisingly lightweight, never topping 1024x1024 atlas size even with insane 640dpi resolution very few devices on the market have. Few things left:

I'd like to add in-editor preview without density clamping - haven't looked into that yet, it's mostly relevant for people with small screens who want to preview ultra-high density layouts that can't fit into Unity window at true scale. Right now, like on targeted devices, density bucket is dropped until you reach minimum allowed screen resolution for a given bucket. I should add an option to allow you to sacrifice in-editor pixel perfect previews to fit high-DPI layouts into your small display (for example, it's impossible to fit 1:1 XXHDPI or XXXHDPI layout onto a 1080p desktop).

NGUI 3 Support / Re: color gradient sprites
« on: October 28, 2014, 11:05:44 AM »
You can simply add a semi-transparent overlay sprite to create a gradient of any shape over your widget. Far more flexible than attempting to influence vertex colors directly (which won't even work properly with a sliced sprite without end-to-end edges).

NGUI 3 Support / Re: NGUI and Unity 5.0 Upgradable APIs
« on: October 28, 2014, 11:01:35 AM »

"“transform” is now cached on the C# side, no more need to cache it yourself."

That's exactly his point, performance for everyone but 5.0 users will degrade if that change will be done right now.

NGUI 3 Support / Re: Phone status bar difference between iOS and Android
« on: October 27, 2014, 12:44:52 PM »
It simply tells the OS which status bar style to show, I'm not sure it was ever supposed to influence anything in your own screen.

NGUI 3 Support / Re: Phone status bar difference between iOS and Android
« on: October 27, 2014, 12:07:00 PM »
I think, as iOS status bars can be transparent, they have absolutely no influence on the resolution rendered by Unity - so your widgets have no reason to shift anywhere. You will most likely have to correct that manually (using, for example, a small script that will shift widgets down depending on the platform).

NGUI 3 Documentation / Re: UILabel
« on: October 27, 2014, 10:10:16 AM »
I think I almost got it, just need to fix alignment issues now. I changed:

Line 235 in NGUIText.GetGlyph
if (dynamicFont.GetCharacterInfo ((char) ch, out mTempChar, Mathf.RoundToInt (finalSize * screenMultiplier), fontStyle))

Line 258 in NGUIText.GetGlyph
float pd = fontScale * pixelDensity / screenMultiplier;

I think I need to alter Update in the beginning, but adding multiplier into baseline variable is not entirely fixing it, so I might be missing someplace else.


Edit: Still a bit wrong, but it's very close. Am I altering the right place in this baseline calculation?

float y0 = mTempChar.vert.yMax;
float y1 = mTempChar.vert.yMin;
baseline = Mathf.Round (y0 + (finalSize - y0 + y1) * 0.5f * screenMultiplier);

Both y0 and y1 are not changed when GetGlyph encounters non-1 screenMultiplier, so it's unlikely I need to multiply those by anything. Multiplying finalSize doesn't look right either, as well as multiplying the whole thing before rounding. I'm probably overlooking something.


Edit 2: Or maybe baseline is alright all along and I should only alter something else in the GetGlyph method. For example, adding this comes extremely close to the desired result:

Line 246 in NGUIText.GetGlyph
glyph.v0.y = (mTempChar.vert.yMax - baseline) * screenMultiplier;

Except the result seems to deviate undesirably between glyphs, breaking proper vertical alignment. Ugh. :)


Edit 3: Ugh, so close yet wrong again!

Line 246 in NGUIText.GetGlyph
glyph.v0.y = (mTempChar.vert.yMax - baseline) * screenMultiplier;
glyph.v1.y = (glyph.v0.y - mTempChar.vert.height) / screenMultiplier;

Letter U no longer sinks, but now O fails to raise above other quads like it does in properly aligned x1 scaling. What the hell am I missing?


Edit 4: Okay, I'm starting to have a suspicion I have missed an already present pixel density correction that's right under my nose. Never saw the existing pixel density parameter in NGUIText be anything other than 1, but figuring out where it's assigned might be the right way to approach the issue instead of tinkering with delicate stuff in NGUIText.


Edit 5: Christ, that's completely right!

I forgot that I bypassed the way standard UIRoot DPI adjustment works, which is why labels never received any notice about changed density, - as the property of UIRoot they were reading was not changed by screen density logic anymore. Very simple fix.

Line 1792 in UILabel
if (rt != null) NGUIText.pixelDensity = (rt != null) ? 1f / screenMultiplier : 1f;

NGUI 3 Documentation / Re: UILabel
« on: October 27, 2014, 09:34:07 AM »
What would be a proper way to force UILabels to render dynamic fonts at a different resolution? Use of Flexible + Adjust by DPI UIRoot can lead the labels to believe they have to be rasterized at, say, 14px height, when in reality they occupy 28px on a physical screen (in case of 2x DPI adjustment). I take it I have to alter the arguments in RequestCharactersInTexture calls in NGUIText to do that? For example, by multiplying them by reliable static multiplier that will correct the rasterized resolution to proper one if UIRoot is scaled by DPI adjustment.

There is quite a lot of these calls, through, and I'm not seeing immediate changes to resolution after altering finalSize arguments, so I might be wrong.

P.S.: I know it would've been easier with bitmaps, but I'm afraid I don't have an option of using them (full Unicode support multiplied by reasonably big set of sizes and thicknesses requested by guidelines multiplied by six screen densities would produce quite a mess with bitmaps, so I think dynamic font labels win in convenience in my case).

Misc Archive / Re: Building Material Design UI with NGUI
« on: October 27, 2014, 04:38:49 AM »
No fancy gifs this time, but nevertheless, nice progress. The one thing I was extremely worried about is screen density handling.

Usually, you think about your UI design in pixels. That button is 48 pixels tall, that anchor offsets a widget by 16 pixels, and so on. That's a great way of doing it on traditional desktop games where resolutions and screen densities are pretty predictable and no one bats an eye about size of the elements unless they get a small 4K screen. Mobile platforms, on the other hand...

You usually want your buttons, or text fields, or other stuff to be around 0.7-1cm high for good balance between usability and amount of content on the mobile screen. Tiny problem is, there are smartphones with 480px 4' screens, and there are smartphones with 2160px 5' screens, and there are tablets, and there is insane wealth of other size+density combinations. So using pixel-driven control size, you will easily get this:

Ugh. What are your existing options?

  • Use Constrained UIRoot: Nice, but you say goodbye to pixel perfect elements. Do you really want to have your UI scaled to x2.1723454 on some device? Not really, you'd probably prefer it to be x2.
  • Use Adjust by DPI on Flexible UIRoot: Very nice option, retains pixel perfect UI on 96dpi screens and fools UIRoot into thinking it has a different resolution on a different DPI, allowing you, for example, to use absolutely identical values for non-Retina and Retina iPads while getting pixel perfect UI on both. Except many devices do not properly report their DPI so you'll be stuck with one size fits all platform-dependent assumption like 160dpi. Except most devices do not have the DPI multiple of 96, so say goodbye to nice proportional scaling. Except some devices combine relatively high DPI with relatively low resolution so you might want to use a lower DPI layout there instead of unbiased scaling to allow your layout to fit at all.

Okay, that's not a very attractive situation. You want this on every single device, no matter how nice it's resolution is and how weird it's screen size is:

Well, that problem is already solved in native UIs. Android has a very nice approach to solving that very issue:

There are few important ideas:

  • Do not use pixels, set up everything using virtual units (Android calls them DP, density independent pixels)
  • Translate virtual units into physical pixels depending on the DPI of the screen
  • Do not actually use true DPI of the device, because calculated scaling multiplier will most likely be absolutely awful - instead, sort all devices into broad groups by their DPI and force those groups to use unified, preferably integer scaling multipliers like 3x

Nice, but how can we do that in NGUI? Turns out it's pretty simple. I have mentioned the experimental Adjust by DPI mode above, and it actually does a very similar thing, except it's reliant on true DPI, creating multipliers by dividing 96 by that DPI. So, I just replaced NGUIMath.AdjustByDPI call in UIRoot with my own and created this simple component:

Replacing atlases aside, it does this:

  • You can assign screen density bucket (like HDPI) in the editor to directly preview how your UI will look on a device belonging to that density
  • When you change that option, the component checks the screen resolution and, if necessary, drops the DPI bucket selection down until it fits the guidelines: it's important to remember that, for example, even if a device belongs to XXHDPI (480DPI) density, unless it has a screen bigger than 960 pixels, it absolutely can not fit enough content on the screen and should be forced to use a lower bucket
  • After the check is passed, the component updates the multiplier (1x for MDPI, 3x for XXHDPI, 2x for XHDPI and so on) in the static class that returns adjusted height for UIRoot

With this slight change, Adjust by DPI UIRoot mode is perfectly usable! Well, ahem, for Editor work, that is. I still need to ensure that builds will automatically force a proper density depending on device. NGUIMath.AdjustByDPI fetches the DPI, but I wonder if any improvements are possible there - for example, maybe it's possible to ask an Android device it's real density bucket directly, in a way native apps do that.

P.S.: Looks like there is one issue: There is no way to tell the true type labels to rasterize at true resolution instead of virtual resolution, so they stay blurred no matter how high you are going. Not sure how to counteract this yet.

NGUI 3 Support / Re: Interaction of UI root resolution vs game resolution
« on: October 25, 2014, 03:40:12 PM »
Great to hear that!

As about the mode, I'm not really sure what benefit will Constrained mode give. I'm not actually planning to run 4k resolution in a 1280x720 viewport, just researching the options.

Ideally, I want to replicate what native UIs are doing: they are absolutely pixel perfect on the whole range of pixel densities and resolutions. They do that by never using true pixels as a scale of anything: instead, they have floating units (like DP) that are incremented depending on screen density of a device, and for raster elements, they swap the atlases to ones rasterized at the resolution of the currently selected multiplier. This allows you to have pixel perfect UI both on a 640x1136 iPhone screen, on a gigantic ultra-dense Samsung phablet and on an old low-res Android phone - just by virtue of values like "8dp" translating into different (nicely proportional) pixel values on different devices - 3x on one, 1x on another. If I were to do that, it makes sense to use pixel perfect NGUI mode with trickery of atlas switching and widget rescaling stacked on top. Will require some work, but I think it's feasible and would really improve how UI situation in Unity in comparison to native apps. Not sure if experimental DPI scaling option does what I need for that, but will check that out too.

The whole situation of UI resolution ending up bigger than rendering resolution mostly happens in the editor where you are forced to work with limiting viewports.

NGUI 3 Support / Re: Interaction of UI root resolution vs game resolution
« on: October 25, 2014, 03:06:45 PM »
Ignoring pixel perfect snapping and the difference in widget sizes - let's assume that everything is done through anchors with no pixel-based offsets, that makes it identical no matter the resolution. Still, is there any performance influence hit I might be overlooking?

Pages: 1 2 [3] 4 5 ... 8