Tasharen Entertainment Forum

Support => Misc Archive => Topic started by: bac9 on October 14, 2014, 03:23:26 AM

Title: Building Material Design UI with NGUI
Post by: bac9 on October 14, 2014, 03:23:26 AM
(http://i.imgur.com/VFXmTWY.jpg)

Thought I should post about that work outside of support threads. Exhibit A:


Long story short, I got a bit tired of implementing controls from scratch in every project and overall from using unstructured UI workflows. Seriously, why am I still using awkward half-assed window managers that are created anew every time, why do I have to deal with setting up tweens and sprite references when adding a spinner and why do I need custom switches, buttons and show-hide sequences every time? I shouldn't be doing that.

So I started working on a coherent MVC based foundation that will allow me to create interfaces that are quick to set up, easy to maintain and easy to expand.

While at it, I thought to myself - wouldn't it be wonderful if I had not just nice code providing reusable elements, but also those beautifully implemented controls from Material Design (http://www.google.com/design/spec/material-design/introduction.html) by Google that native Android developers enjoy? Wouldn't it be nice to have Unity applications that can fool a user into believing they are native? Anyway, how hard would implementing controls from Material Design guidelines would be?

________________

Turns out they are quite a bit complex, but every single one of them can be implemented without atrocious hacks or performance-hungry workarounds like frame-based animations. For example, those radio buttons are just three overlayed dots that require no custom masking - just proper order of color and scale tweens.

(http://i.imgur.com/hTLzgYo.gif)

The most complex things here are touch effects and shadows. Those were a complete mystery to me - for all I knew, Google implemented them with magic. Check these animations:


Only idea I had at first was using NGUI panel clipping in every element, but that was unacceptable from performance standpoint and would have cluttered the hierarchy - and that would only allow those radial ripples, without addressing even more mysterious second part of the animation - inverse erasing of the expanding ripple sprite, which can't be achieved through traditional rect-based clipping at all. But as it turns out, it can be implemented, at almost no performance cost, and with that double clipping from within.

You set up a separate UIPanel set to hard edge clipping, with a component that can set it's dimensions and position, with a singleton to access it, and a child ripple sprite that can tween through the touch animation. Any touchable widget can call the singleton and invoke a method (using itself as an argument) on touch, which will reposition the UIPanel clip area to dimensions of a widget arriving in the argument and start the ripple animation in the clicked point of the screen.

(http://i.imgur.com/Hku7CYC.gif)

Now only thing that is left is the second clipping - erasing the ripple sprite from within. That one is achieved by creating clipping-compatible depth cutout shader (no need to modify the example, just give NGUI a properly named duplicate) and applying it to a UITexture with the circle texture, then moving the object with it outside of the UI plane to allow depth testing to kill pixels within the panel. All you need to do when that is set up is to tween the ripple sprite first and the eraser sprite second, and you get yourself that sexy impossible ring that is required for every clickable element in Material Design.

(http://i.imgur.com/NzQJseD.gif)

________________

Another area where Material Design presents a huge challenge is dynamic shadows. They are not in any way similar to the standard static drop shadows that people bake into sprites.


They are dynamic, with every rectangular element capable of lifting back and forth through multiple depth levels, casting very smooth shadow of variable feathering radius. That's extremely problematic. But as it turns out, it can be implemented too, with some clever trickery. Take a look:


To do this, I prepare a sliced sprite with rectangular shadow and assign it to the sprite anchored without any offsets to my card. There is no need to do it manually - I just add a "sprite shadow" component to a UISprite object and everything is set up automatically (and cleaned up when that component is removed).

The desired look, with variable feathering radius, is impossible to achieve with standard sliced sprite behaviour and anchoring in NGUI. Using that custom component, I subscribe to the fill event of the sliced shadow and directly modify the positions of 36 vertices, pushing the central quad instead of all quads to be controlled by the sprite dimensions and anchoring, and pushing the other quads outward depending on offset calculated from the depth, then finally sampling a certain curve to get proper shadow intensity. Ah, and the sprite is offset downward a bit, depending on the depth.

________________

Not sure if that webm hosting has limits on the traffic (sites accepting 15s+ files are hard to come by), so just in case, here is a mirror (379kb):


________________

P.S.: To inevitable question of "why not uGUI", well, I really prefer NGUI for a number of reasons.

Title: Re: Building Material Design UI with NGUI
Post by: hexaust on October 14, 2014, 08:25:51 AM
Wow! Holy **** dude, this is impressive! Big thank you for sharing. Great work!
Title: Re: Building Material Design UI with NGUI
Post by: ArenMook on October 14, 2014, 03:35:33 PM
You sir, are a wizard.
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 17, 2014, 07:43:14 AM
Input fields in two varieties (yet to make a multiline one):

(http://i.imgur.com/v0kB65d.gif)

Works with any content text size, automatically adapts the control widget size to make guidelines-compliant spacing easy, can work on any background.
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 17, 2014, 05:13:15 PM
Spinner: controlled through a method with 0-1 float as an argument, value that can be fed with the progress on some operation or alternatively just produced from delta time in update.
The method constructs the color by sliding through HSB, while rotation and fill completion are evaluated from two relatively simple custom AnimationCurves that intersect to provide the catch-up impression.

(http://i.imgur.com/qPHKva6.gif)

Multiline input:

(http://i.imgur.com/qDH1eCs.gif)
Title: Re: Building Material Design UI with NGUI
Post by: ArenMook on October 18, 2014, 07:21:15 AM
Very, very sexy. Are you going to put this up on the Asset Store at any point?
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 18, 2014, 07:55:00 AM
After actually making a reasonably complex project with it, yeah, probably.

I just need that to ensure I'm not making some impractical monstrosity with awful architecture that drives you insane right after a minute of attempting to make a UI with it. So far I'm starting with simple stuff (like, let's say, codex app with simple screen hierarchy, articles, settings etc), checking what drives me insane in the process and solving the issues that do that.

Dislike to redo the work to create every dialog box? Abstract that object into a component that sets everything up for you, exposing just the size, actions and text to configure. Dislike how much you have to hardcode while setting up buttons for that dialog? Create a better abstracted button class that can set up what you need with just one line. Dislike how you have to set up icon buttons, FAB buttons, rect buttons and sidebar buttons separately with different objects? Come up with a way to combine them all into one button class that can switch between every type. Dislike how that makes the button object bloated with children that are frequently disabled and unused? Improve your code so that only objects necessary for the current type are maintained. Dislike how you have to recheck the referenced objects and recreate them with proper configuration using kilometer long code? Write a utility class that can check your references and replace them if they are missing, creating the sprites, labels, control widgets, textures, tables and so on with one line for you, enabling you to drop boiler plate code from all abstract components. Dislike setting up guideline-compliant colors through Color for every single object? Create a library that can be referenced instead. Dislike having to open a calculator to recheck how DP size values from the guidelines are scaled into pixels in XXHDPI space? Create in-editor tool that can give you the values directly and provides grid info. And so on.

So far it's going nicely but there is still a lot of work to do. No blocking issues though, like in the beginning when I had no idea if it's even possible to replicate the required effects.

P.S.: By the way, it would be nice to add onSelect and onDeselect event delegate lists to UIInput in addition to existing two. All methods already exist, it's a matter of declaring them and adding .Execute in two new places, nothing else required. Having them enables a lot of interesting stuff, including that hint behavior on the gifs above, so it would be nice to have them by default - so far it's the only change I had to make in NGUI code. I would obviously prefer to stay away from making changes like that where possible, to enable easy support.
Title: Re: Building Material Design UI with NGUI
Post by: ArenMook on October 18, 2014, 09:03:12 AM
Regarding your PS: just attach UIEventTrigger. It has the OnSelect/OnDeselect. No need to code.

I'm sure if you release this on the Asset Store, it will sell like hotcakes because of how awesome it all looks.

P.S. of my own: I recommend turning each type of a control into a prefab, and setting up their previews properly so that they show up in the Prefab Toolbar.
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 18, 2014, 10:40:05 AM
Oh, that's a nice solution.

As about the prefabs, to be honest I'm not much of a fan of them in UI. They are extremely useful for things like:


But I'm skeptical about using them for reusable components because usually you want a lot more than an object properly instantiated from a blueprint: you want an object that self-updates itself to stay compliant with the latest reference design, the object that repairs itself if something is missing. You want every single button and checkbox in your project to update themselves (talking about editor environment, not runtime, ofc) the instance you update their design. And importantly, you want to have all that for objects that are combined into an intricate nested hierarchy where some instances control others but must be updated independently. Unity prefabs can't offer that. So I construct stuff without them, and doing so directly allows me to have buttons, fields, etc. that are harder to break, that use the very latest configuration and look no matter how and when you create them, do not require you to hand-check every scene wondering if your changes to the reference were properly distributed to the copies, etc.

It's a bit more rigid approach, one that won't allow the users to slap ten effects to a button and distribute that with one click on "Apply" on top of the inspector, but when the appeal of the system is replication of a rigid design framework in the first place, I guess it's not exactly a problem :) And if they really want to, it's simple to do so through code.

P.S.: Did some work on screen control.

(http://i.imgur.com/NGvGWbo.gif)

At the moment it works like this:


So, the most simple UI design goes like this:


Of course, no one is stopping you from setting up whatever internal layout you want in every area by using labels, buttons, switches and separators (all of those are parent entities wrapping and constructing certain NGUI design, of course - you don't have to deal with setting up tweens in a switch animation or shadows in a button).

Creating any entity type is a matter of adding a component to an empty GameObject. The component checks what objects are required for it, and if they are not present, creates them following in-built presets (for a flat rectangular button that would be creating one sprite, one label, a control widget and a collider for it). Presets can be very varied and can be switched on the fly - a switch can transform itself into radio, checkbox or a toggle slider with just one enum selection in it's inspector. The component also provides a method (and a context menu option) to destroy it along with all connected objects and components, which is handy when you don't want to clean up that stuff yourself.
Title: Re: Building Material Design UI with NGUI
Post by: badawe on October 22, 2014, 01:20:58 PM
Amazing WORK!

Any chance of you share this "clipping-compatible depth cutout shader"
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 22, 2014, 05:52:33 PM
It can be a simple duplicate of an existing shader with a space and "1" added in the end of the name - as it's a subtractive shader that can only operate against the content of a panel anyway, there is no need to actually clip what it does. Just make sure NGUI finds the separate version of a shader, which is why you need that new file.
Title: Re: Building Material Design UI with NGUI
Post by: Nicki on October 23, 2014, 06:29:12 AM
It's looking damn sexy. I'll pick this up when you go live.
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 25, 2014, 09:17:30 AM
Had some progress. I'm navigating with a mouse in the following gifs, but GifCam is not capturing the pointer for some reason.

(http://i.imgur.com/lZWRvYe.gif)

This time, I tried to create a simple note-keeping application with few options (list, editor, tagging, removal, etc.). Can easily be expanded into a quest log or, say, Mass Effect style codex.
Along the way, as usual, I spent time working on workflow problems that drove me insane, and added stuff which could speed up the workflow. The results are pretty neat.

(http://i.imgur.com/LgJBKum.gif)

The scene hierarchy goes like this:

  1. VPScreenManager
  2. └   VPScreen
  3.     └   VPArea
  4.         └   Various content
  5.  

There are following basic entities:


None of those three create anything visual. They do not control a single sprite. Now though, after those are set up, under any area, you can drop a wide variety of view presenters, including your own, to actually create a visible layout and allow interaction. Few examples:


It's also extremely easy to create your own view presenter entities if your application has some unusual elements not covered by existing types. I added two:

The whole application depicted on the gifs takes few hours to set up at most: the controller and data models are pretty short and UI work is mostly dragging ready-made entities in the scene view. It's not a static demo, it's data-driven UI that loads documents from files and saves them back. Pretty neat.

Next time I'll try something more complex, maybe an inventory with tabs, dropdowns and previews.
Title: Re: Building Material Design UI with NGUI
Post by: ArenMook on October 25, 2014, 01:53:57 PM
Wizard, I say.
Title: Re: Building Material Design UI with NGUI
Post by: bac9 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:

(http://i.imgur.com/NbKc2st.jpg)

Ugh. What are your existing options?


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:

(http://i.imgur.com/iAKGxgo.jpg)

Well, that problem is already solved in native UIs. Android has a very nice approach to solving that very issue:
https://developer.android.com/guide/practices/screens_support.html

There are few important ideas:


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:

(http://i.imgur.com/FLiLhnC.jpg)

Replacing atlases aside, it does this:


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.
Title: Re: Building Material Design UI with NGUI
Post by: Nicki on October 28, 2014, 04:19:31 AM
Your ideas are intriguing to me and I would like to subscribe to your newsletter. Pls gief asset store, bac pls. :]
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on October 28, 2014, 06:11:11 PM
Hell yeah, everything seems to work right now!

(http://i.imgur.com/kCPyaDI.gif)

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).
Title: Re: Building Material Design UI with NGUI
Post by: bac9 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.

(http://i.imgur.com/NzQJseD.gif)

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

(http://i.imgur.com/RjEPHoC.jpg)

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:

(https://i.imgur.com/SPIz1hd.gif)

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.
Title: Re: Building Material Design UI with NGUI
Post by: bac9 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: http://www.google.com/design/spec/resources/color-palettes.html

Now you can load one straight into Unity:

(http://i.imgur.com/Y56Tg5J.jpg)

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.

(http://i.imgur.com/sbQT97q.jpg)
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on November 03, 2014, 07:53:37 PM
After wrestling it for few days, finally got it working. Fancy clipped screen transitions straight out of apps like Google Inbox!

(http://i.imgur.com/wXNDKnx.gif)
Title: Re: Building Material Design UI with NGUI
Post by: ArenMook on November 04, 2014, 08:27:15 AM
Keeps getting better and better!
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on November 05, 2014, 02:27:41 PM
One particularly inconvenient issue with designing UIs for multiple screen resolutions and densities is how you need radically different proportions and layouts to cover all cases nicely. You don't want lines to span a 4k display horizontally and you don't want your sidebar to eat precious horizontal space on a narrow smartphone screen. So you need to make design responsive.

Uh, well, I solved that, more or less.

(http://i.imgur.com/0NFbTBX.gif)

I thought about the issue a bit and found a somewhat elegant solution.


Current implementation looks like this in inspector:

(http://i.imgur.com/ZHsdouN.jpg)

A bit ominous (I can probably get neat color coded interval visualization going for every group), but very easy to use.
Title: Re: Building Material Design UI with NGUI
Post by: Limyc on November 07, 2014, 05:26:23 PM
This is absolutely incredible. I'll definitely be watching this thread for updates on a release. Maybe a Christmas present?

I almost confused you with /u/Saxy_Man on reddit until I saw him comment on one of your submissions.
Title: Re: Building Material Design UI with NGUI
Post by: r.pedra on November 24, 2014, 12:09:40 PM
Simply amazing  :o
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on December 10, 2014, 03:09:01 PM
Great news everyone! Responsive layout system progressed very nicely and is pretty different now from object-based draft I showcased above. First, to remind you what responsive layouts are, simple illustration:

(http://i.imgur.com/FQABXmv.jpg)

There were two biggest issues with the previous implementation:
Both of those issues are out and workflow is much more straightforward now. First, you set up desired resolution brackets. For example, maybe you want to have one layout for screens of below 480dp width, another layout for screens between 480dp and 640dp width, and another layout for screens wider than 640dp. Easy! Just set up your intervals with this neat array in the screen manager (featuring auto-configured clamping to nearest neighbors with fancy sliders and warnings):

(https://i.imgur.com/iabbeHr.gif)

Second, add a new component to any UI widget you want to be density dependent. Depending on amount of resolution intervals set up in your screen manager, that component will store appropriate amount of anchoring configurations. The component is not attempting to replace the perfect anchoring editor from NGUI - you still use the familiar controls, except you can save your configuration to one of the resolution brackets. Set up your anchoring for a narrow screen, click the copy button on narrow configuration, set up your anchoring for a wide screen, click the copy button on widescreen configuration. Done.

(http://i.imgur.com/gZt2OEC.gif)

The screen manager maintains a list of resolution-based anchor components and swaps anchoring configuration to appropriate one depending on detected resolution, giving you results like this (http://'https://i.imgur.com/0NFbTBX.gif') while keeping your data-driven UI free from pesky duplicates or other inconveniences. There is no need to set up dozens of resolution-based anchoring configurations either - in some applications, the whole design can be hierarchically anchored to just one widget, necessitating just one collection of configurations on that topmost widget.

Aside from this goodness, I worked on some other stuff like refactoring and new view presenters. One of the new object types is the dropdown menu. While still work in progress, it's already looking quite good:

(http://i.imgur.com/kEhuqai.gif)

Title: Re: Building Material Design UI with NGUI
Post by: ArenMook on December 11, 2014, 08:15:21 AM
Nice, I was just wondering last night what you ended up doing with the project. Good to see it moving forward!
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on December 11, 2014, 10:37:53 AM
I'm just frequently borrowed to do other work, so this project is moving forward slower than I would like. :)
Title: Re: Building Material Design UI with NGUI
Post by: callski on December 15, 2014, 04:18:49 PM
How close are you to putting something up on the asset store or releasing source? This looks amazing!
Title: Re: Building Material Design UI with NGUI
Post by: bac9 on December 19, 2014, 07:26:43 AM
Not earlier than the middle of January I'm afraid, too much is still missing or unfinished.
Title: Re: Building Material Design UI with NGUI
Post by: GHVNlab on December 22, 2014, 11:38:02 PM
Hi there, your work is amazing. Will u release a pre beta version of this on asset store, a paid beta version. I'm just a MD crazy fan

PS: u should check this out sir http://alexk111.github.io/SVG-Morpheus/
Title: Re: Building Material Design UI with NGUI
Post by: Maxii on April 11, 2015, 10:53:22 AM
What ever happened with this amazing work? Did is get to the asset store?
Title: Re: Building Material Design UI with NGUI
Post by: r.pedra on October 13, 2015, 05:51:54 AM
Would love to see this in Asset Store or whatever. This is so amazing
Title: Re: Building Material Design UI with NGUI
Post by: mm76 on December 28, 2016, 06:56:29 AM
do you share your plugin, or is there a asset store link ?

all regards

mike