Tasharen Entertainment Forum

Support => NGUI 3 Support => Topic started by: briangibson on April 28, 2014, 10:39:40 AM

Title: clipping a panel with a non-square rect
Post by: briangibson on April 28, 2014, 10:39:40 AM
Hey there- I would like to clip a scrollview panel contents via rounded clipping corners or another sort of clipping mask around the edges. How would you recommend going about this?

I was thinking maybe my grid contents could use a particular material that clips with a 2nd texture input or something... but I'm not entirely sure about the rendering pipeline involved in a scrollview contents + the ngui-generated meshes.

Would be a killer feature to add- being able to use a Sliced uisprite as a clipping mask for a UIPanel.

I saw this: but it isn't quite what I'm looking for. I need to sort of sample the texcoords in world space to use as a mask, more or less.
http://nickithansen.dk/masking-and-clipping-textures-using-shaders-in-ngui/
Title: Re: clipping a panel with a non-square rect
Post by: ArenMook on April 29, 2014, 02:39:21 PM
NGUI's clipping is done via a shader -- if the texture position lies outside the rectangle, it's faded out. Involving texture sampling is doable, but not using sliced sprites. Sliced sprites are drawn using 9-slicing -- by drawing 9 triangles, each scaled differently than its UVs. TLDR version: this would not be a simple feature. Masking is easy. Sliced masking? Not so much. It wouldn't be worth the effort as it would complicate everything dramatically.
Title: Re: clipping a panel with a non-square rect
Post by: briangibson on April 29, 2014, 02:54:12 PM
I understand that 9 sliced masking would be a complicated feature. Let's say for simplicity's sake, I just want to clip a panel via a 'mask' sprite placed somewhere in the scene. In theory, I could make a solid image with an alpha background...and use the solid color as a mask for the scrollview contents (or for other content)

Is that out of the realm of possibility? "Involving texture sampling is doable" gives me hope... I poked at the shader that does the clipping, but I'm not sure how I'd go about this with NGUI. Perhaps writing to the stencil buffer? *ponder*
Title: Re: clipping a panel with a non-square rect
Post by: ArenMook on April 30, 2014, 05:09:43 PM
You can currently already do this using a stencil buffer. Write a shader that will write to a stencil buffer, then create a shader that will only write where stencil is set.
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 16, 2014, 03:23:34 PM
Hi guys, I'm bumping this thread.
I think there is a way in the next Unity UI system to make clipping using texture as mask.
Is there any way to have this as well on NGUI?

Thanks !
Title: Re: clipping a panel with a non-square rect
Post by: ArenMook on September 17, 2014, 12:00:43 PM
Yes, as I mentioned above you just need to write two shaders. One shader to write to stencil, another to draw only where the stencil was written. The first shader will go on the mask, the second shader will go on the atlas material.
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 17, 2014, 12:16:35 PM
One of our developer made it without using stencil buffer or even writing shaders.
He modified UIPanel and few other scripts, and it works well.
Would you be interested on adding this feature into the actual version of NGUI? It would be cool to share it with all users.
Title: Re: clipping a panel with a non-square rect
Post by: ArenMook on September 17, 2014, 01:23:07 PM
Without writing shaders? I see no way this can be done without writing at least one shader. You are welcome to share the solution here if you like. Just don't post all of NGUI's source code. A few files is fine.
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 17, 2014, 02:26:56 PM
My bad, he made a new variation of shaders you created for NGUI (AlphaClip, SoftClip, etc...). I'll post only those new scripts, but we are using a quite old version on NGUI, so the code might no be up-to-date (3.5.3).
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 17, 2014, 02:40:56 PM
I attached an archive with UIPanelInspector, UIPanel and UIDrawCall scripts.
It also includes all new variation shaders (TextureClip).

The lines added/modified on scripts:

UIPanel ->

Line 130: 
  1.  
  2. [HideInInspector][SerializeField] Texture2D mClipTexture = null;
  3.  

Line 433:
  1.    
  2. public Texture2D clipTexture
  3.     {
  4.         get
  5.         {
  6.             return mClipTexture;
  7.         }
  8.         set
  9.         {
  10.             if (mClipTexture != value)
  11.             {
  12.                 mClipTexture = value;
  13. #if UNITY_EDITOR
  14.                 if (!Application.isPlaying) UpdateDrawCalls();
  15. #endif
  16.             }
  17.         }
  18.     }
  19.  

Line 1222:
  1.            
  2. dc.clipTexture = mClipTexture;
  3.  

UIDrawcall ->

Line 43:
  1.         TextureClip = 5,
  2.  

Line 72:
  1.     Texture2D       mClipTexture;
  2.  

Line 261:
  1.     public Texture2D clipTexture { get { return mClipTexture; } set { mClipTexture = value; } }
  2.  

Line 271:
  1.         const string textureClip = " (TextureClip)";
  2.  

Line 279:
  1.         shaderName = shaderName.Replace(textureClip, "");
  2.  

Line 292:
  1.         else if (mClipping == Clipping.TextureClip)
  2.         {
  3.             shader = Shader.Find(shaderName + textureClip);
  4.         }
  5.  

Line 569:
  1.             mDynamicMat.SetTexture("_ClipTex", mClipTexture);
  2.  

And finally on UIPanelInspector ->

Line 511:
  1.             if (mPanel.clipping == UIDrawCall.Clipping.TextureClip)
  2.             {
  3.                 GUILayout.BeginHorizontal();
  4.                 GUILayout.Space(80f);
  5.                 Texture2D tex = (Texture2D)EditorGUILayout.ObjectField("Clip Texture", mPanel.clipTexture, typeof(Texture2D), false, GUILayout.Width(200));
  6.                 GUILayout.EndHorizontal();
  7.  
  8.                 if (mPanel.clipTexture != tex)
  9.                 {
  10.                     NGUIEditorTools.RegisterUndo("Clipping Change", mPanel);
  11.                     mPanel.clipTexture = tex;
  12.                     EditorUtility.SetDirty(mPanel);
  13.                 }
  14.             }
  15.  
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 17, 2014, 04:01:15 PM
One thing:
Maybe it's not logic right now that the sprites or textures will be faded out when the alpha of the texture mask is 0.
So in my version I changed in all shaders the line where the alpha of the texture is multiplied by the alpha of the mask to 1 - alpha to inverse it.
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 17, 2014, 04:09:28 PM
Here's an example of the result: it's pretty damn AMAZING.

(http://i.imgur.com/7JyTg6y.png)
Title: Re: clipping a panel with a non-square rect
Post by: badawe on September 17, 2014, 07:50:05 PM
This is TO DAMN AWESOME!

This mask feature of the new Unity almost made me switch a entire project to it!
But I'll give a try in this test, and try to update this to the new NGUI! :D

Thanks for sharing this!
Title: Re: clipping a panel with a non-square rect
Post by: afrokick on September 18, 2014, 05:44:51 AM
Thank you very much! But it doesn't work in 3.7.0.

Fixes:


UIPanel:
clipCount
  1. if (p.mClipping == UIDrawCall.Clipping.SoftClip || p.mClipping == UIDrawCall.Clipping.TextureClip) ++count;
  2.  

hasClipping
  1. public bool hasClipping { get { return mClipping == UIDrawCall.Clipping.SoftClip || mClipping == UIDrawCall.Clipping.TextureClip; } }
  2.  

UIDrawCall:
void CreateMaterial ()
  1. // Legacy functionality
  2. if (shader == null && mClipCount == 1){
  3.     mLegacyShader = true;
  4.     shader = Shader.Find(shaderName + soft);
  5. }
  6.  
  7. //added
  8. if(panel.clipping == Clipping.TextureClip){
  9.     mLegacyShader = true;
  10.     shader = Shader.Find(shaderName + textureClip);
  11. }
  12. //end
  13. ...
  14.  
  15. mDynamicMat.SetVector("_ClipSharpness", sharpness);
  16. mDynamicMat.SetTexture("_ClipTex", mClipTexture);//<---- added
  17.  
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 18, 2014, 08:21:49 AM
I think the best way to do it is to wait for ArenMook to integrate it in the latest version of NGUI.
Or you will have to figure out where to integrate changes on those 3 files in the new version (maybe script like UIPanel is completely different) and add new shaders into your project (from the archive I attached in my previous post).
I don't think that's not going to work on the last version, we didn't change a lot of things into the project, we just add pretty much the support for a new clipping mode, and the shader is very similar to the original one. Basically it's just multiplying the alpha of the sprite/texture/label with the alpha of the mask texture.

Title: Re: clipping a panel with a non-square rect
Post by: ArenMook on September 18, 2014, 04:19:42 PM
This part in the vertex shader:
  1. o.worldPos = TRANSFORM_TEX(v.vertex.xy, _MainTex);
...and this in the fragment shader:
  1. half alpha = tex2D(_ClipTex, IN.worldPos * 0.5 + float2(0.5, 0.5)).a;
...doesn't work. You're transforming the vertex coordinate by the texture matrix, but the texture matrix isn't used in NGUI, and it's never set. I have a vague recollection of writing this a while back... for Unity perhaps? Where did you get this from?
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 18, 2014, 04:36:26 PM
We're getting this from the 3.5.6 version (the version we are using right now).
My college told me that this line:

  1. o.worldPos = TRANSFORM_TEX(v.vertex.xy, _MainTex);
  2.  
was already into the original AlphaClip shader (the original file we modified). It allows to get the coordinate on the UIPanel (if I'm right, I'm not a shader guy...).

Then the other line is used to be able to scale the alpha with the size of the Panel.

If you still can't figure out how's working with the latest version of NGUI, we will tomorrow try into an empty project with the latest version of NGUI those changes. If we manage to do it I'll post here the solution.
Title: Re: clipping a panel with a non-square rect
Post by: ArenMook on September 18, 2014, 04:49:44 PM
3.5.6 is way out of date.

Anyway I've fixed the shader on my end, so you'll find this feature in the next update. Thanks!
Title: Re: clipping a panel with a non-square rect
Post by: badawe on September 18, 2014, 04:54:50 PM
Awesome news! Thank you guys :D
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 19, 2014, 08:23:58 AM
3.5.6 is way out of date.

Anyway I've fixed the shader on my end, so you'll find this feature in the next update. Thanks!

Good news, glad to help !

And the only reason to keep this version for our project is that updating it is most of the time not necessary (for the new features, most of the time) and it might causes bug/compilation errors.

PS: The 3.5.6 version is working pretty well with the Unity5 beta 4 version ;)
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 19, 2014, 08:33:06 AM
One note, I don't know if you have chosen to set the alpha to the sprite on the panel to 0 when the texture mask alpha is 0 or when it's set to 1.
IMO I would say that when the alpha mask is set to 1 it should set the alpha of the sprite behind to 0.
Maybe letting the user choosing this might be great as well.
Title: Re: clipping a panel with a non-square rect
Post by: Nicki on September 22, 2014, 07:25:44 AM
You know, I wonder if it would be entirely crazy to modify this to use a sliced sprite and generate an "invisible" sliced sprites to sample for alpha. Would be terribly sweet.
Title: Re: clipping a panel with a non-square rect
Post by: cayou on September 22, 2014, 08:14:57 AM
Like an alpha cutout classic shader?