Search Unity

Mask and GUI's is it possible?

Discussion in 'Immediate Mode GUI (IMGUI)' started by madwilson, Jul 1, 2008.

  1. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    I am in the process of making a circular compass but I do not want to show the hole thing inside the GUI. It would be nice if there is a way to add a mask layer that only renders the compass image inside the white are of a second image that is used as the mask. Is there any way to make this work?
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    There's one way here.

    --Eric
     
  3. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    that isn't what I wanted... I would like to have an image inside a gui (compass) that is masked and only shows about 1/3 top of the image showing direction moving (rotation of image).

    So i should take that as a NO it isn't possible. Or is there a halk out there that works.

    Thanks for the reply..
     
  4. MatthewW

    MatthewW

    Joined:
    Nov 30, 2006
    Posts:
    1,356
    Your best bet for any kind of complicated, moving GUI element is to use a second camera and do it all in 3D.
     
  5. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    It's almost certainly possible, but I don't get what you're after.

    --Eric
     
  6. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    Have you tried GUI.RotateAroundPivot() ?
    For cropping the the bottom of the control, put it inside a Begin/EndGroup() and make sure that it's set to clip, then position your control outside of the group to clip what you don't want.
    Don't use the GUI matrix calls within a Window, I think thats still broken.
     
  7. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    does this image help explane?


    I am not worried about the rotation right now I am trying to get the Mask effect.
     
  8. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    That does help.
    To make this, you'd be better off to write your own customer shader, and use GUI.DrawTexture which can take a material.
     
  9. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    It can take a material?? How?

    Cheers,
    -Jon
     
  10. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    Sorry, too much GUI - it's Graphics.DrawTexture(Rect, Texture, Material)
     
  11. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    Ah, yeah, dang. Maybe some day.
     
  12. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    You can also do this on the GUI system if you care to create the texture that comes from combining.

    This function replaces the alpha of the diffuse image with the mask alpha. (didn't test it.)

    Code (csharp):
    1.  
    2. Texture2D CreateUsingMaskAlpha(Texture2D diffuse, Texture2D mask)
    3. {
    4.    Texture2D result = new Texture2D(diffuse.width, diffuse.height, TextureFormat.ARGB32, false);
    5.    
    6.    Color[] diffuseColors = diffuse.GetPixels();
    7.    Color[] maskColors = mask.GetPixels();
    8.  
    9.    for(int i = 0; i < diffuseColors.Lenght; i++)
    10.    {
    11.       diffuseColors[i].a = maskColors[i].a;
    12.    }
    13.        
    14.    result.SetPixels(diffuseValues);
    15.    result.Apply();
    16.  
    17.    return result;
    18. }
    19.  
    20.  
    Note: Remember to call Destroy on the the textures when not using them anymore or you get a memory leak. (wish the garbage collecter would handle this)
     
    cppjames likes this.
  13. Jonathan Czeck

    Jonathan Czeck

    Joined:
    Mar 17, 2005
    Posts:
    1,713
    Yeah, but the rotation of the mask is separate from the rotation of the diffuse, so that won't work.

    Cheers,
    -Jon
     
  14. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Yeah you will have to do the rotation math your self there. Which might be tricky, but is doable.
     
  15. shaun

    shaun

    Joined:
    Mar 23, 2007
    Posts:
    728
    Marc, I'm not sure how friendly this one would be on the CPU, as you're iterating the Color array and calling Apply() every frame, which is why I suggested doing it in a Shader.
     
  16. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Ofc will be faster on the GFX card in hardware no doubt.
     
  17. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Oh if you have it rotate in intervals you could render each texture image for the interval and cache them then you will only run the for loops on initalization, will speed it up, but still wont come close to the fluent movement of a custom shader rendering it.

    Edit: heh or create them by hand.
     
  18. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    Thanks for the help. Funny how a simple visualization can become a big project.

    Don't know how to write a shader.
     
  19. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Just because something is conceptually simple doesn't mean the implementation is. ;) Although in this case it actually is pretty much, as long as you have Pro and can use rendertextures. Here's a basic shader that combines the rgb from one texture and the alpha from another. Then you make the rgb texture be a rendertexture, and you can do whatever to it (rotate the camera, etc.).

    Code (csharp):
    1. Shader "Transparent/Mask" {
    2. Properties {
    3.     _Color ("Main Color", Color) = (1,1,1,1)
    4.     _MainTex ("Base (RGB)", 2D) = "white" {}
    5.     _Mask ("Mixing Mask (A)", 2D) = "gray" {}
    6. }
    7.  
    8. Category {
    9.     ZWrite Off
    10.     Alphatest Greater 0
    11.     Tags {Queue=Transparent}
    12.     Blend SrcAlpha OneMinusSrcAlpha
    13.     ColorMask RGB
    14.     Lighting Off
    15.     SubShader {
    16.         Pass {
    17. CGPROGRAM
    18. #pragma fragment frag
    19.  
    20. float4 _Color;
    21. sampler2D _MainTex;
    22. sampler2D _Mask;
    23.  
    24. struct v2f {
    25.     float4 uv;
    26. };
    27.  
    28. half4 frag( v2f i ) : COLOR
    29. {
    30.     half4 color = tex2D( _MainTex, i.uv.xy );
    31.     half4 mask = tex2D( _Mask, i.uv.xy );
    32.     return half4(color.r, color.g, color.b, mask.a) * _Color;
    33. }
    34. ENDCG
    35.         }
    36.     }
    37. }
    38. }
    Attached is a simple demo package. The only flaw is the compass seems to "bounce" slightly when rotated, I expect because the texture isn't perfectly circular, but that could be tweaked no doubt.

    If you don't have Pro, and can live without the gradient in the mask, the technique I first linked to would still work; you'd just have to model the mask instead of using a texture for it. Or find some other way of rotating the texture instead of using a rendertexture, since the shader itself doesn't need Pro.

    --Eric
     

    Attached Files:

  20. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    Thanks!!.. give update as soon as i get it working.
     
  21. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    Thanks--
    I see what you did there with adding that image to a mesh plane. is there a way to apply the rendered results to a GUI instead of a plane and still get the alpha?

    Dealing with multiple cameras and the compass needs to reside infront of a gui (background).
    Have to say it again Thanks for the Help..
     
  22. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    Don't think so, but you can use another camera that only renders the compass and put that on top of everything. Although that's still not going to appear on top of OnGUI stuff. If that's what you're using, you could use GUIElements instead (GUITexture and GUIText), which can be layered with cameras.

    --Eric
     
  23. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    Thanks again for taking the time to answer my questions.
     
  24. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    You can't apply render textures to gui using GUI.DrawTexture?
     
  25. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    You can, but take another look at the shader I posted...the rendertexture is only going into the _MainTex slot. You need the whole material for the effect to happen, not just the rendertexture. Since you can't apply materials to anything in OnGUI, it won't work.

    --Eric
     
  26. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Maybe you can take a screenshot of the effect and save that to a texture that can be shown in the GUI? or i dunno maybe someform of OnPostRender hacking?

    Edit: Would be nice though if the GUI would be able to have image effects and the likes applied. Maybe an item for a wish list.
     
  27. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    If you mean render the compass to a second rendertexture and use that in the GUI, that was what I did first. Unfortunately, in order for it to work properly, you need to change the background opacity of the rendercamera to 0, but since the opacity is applied to the entire texture, this makes the whole thing invisible in the GUI. It does work with non-GUI stuff like a non-transparent diffuse shader, but even then, the whole "rendertexture of a rendertexture" thing would make me a bit nervous--is the camera render order even defined in this case?

    --Eric
     
  28. ProtonOne

    ProtonOne

    Joined:
    Mar 8, 2008
    Posts:
    406
    I know you already got an answer, but I was curious how this could be done without a render texture. I ended up with this:

    Web Player
    http://protonfoundry.com/MaskTest/

    It is just one custom shader that takes the diffuse texture, mask texture, and the rotation as a parameter (in radians).

    Code (csharp):
    1. Shader "Transparent/Mask" {
    2.     Properties {
    3.         _MainTex ("Base (RGB)", 2D) = "white" {}
    4.         _MaskTex ("Mask (RGB)", 2D) = "white" {}
    5.         _Rotation ("Rotation (-2Pie, 2Pie)", Range (-6.3, 6.3)) = 0.0
    6.     }
    7.     SubShader {
    8.        
    9.         Tags {Queue=Transparent}
    10.         Lighting Off
    11.         ColorMask RGB
    12.        
    13.        
    14.         Pass {
    15.             blend Zero OneMinusSrcColor
    16.             SetTexture [_MaskTex] {
    17.                 Combine texture
    18.             }
    19.         }
    20.        
    21.        
    22.         Pass {
    23.             blend One OneMinusSrcColor
    24.            
    25.                
    26. CGPROGRAM
    27. #pragma vertex vert
    28. #pragma fragment frag
    29. #include "UnityCG.cginc"
    30.  
    31. struct v2f {
    32.     V2F_POS_FOG;
    33.     float2  uv : TEXCOORD0;
    34.     float2  uv2 : TEXCOORD1;
    35. };
    36.  
    37. uniform float4 _MainTex_ST;
    38. uniform float4 _MaskTex_ST;
    39. uniform float _Rotation;
    40.  
    41. v2f vert (appdata_base v)
    42. {
    43.     v2f o;
    44.     PositionFog( v.vertex, o.pos, o.fog );
    45.     float2 uv1 = TRANSFORM_TEX(v.texcoord, _MainTex);
    46.     o.uv2 = TRANSFORM_TEX(v.texcoord, _MaskTex);
    47.  
    48.     uv1 -= float2( 0.5, 0.5 );
    49.     o.uv.x =  cos( _Rotation )*uv1.x + sin(_Rotation)*uv1.y;
    50.     o.uv.y = -sin( _Rotation )*uv1.x + cos(_Rotation)*uv1.y;
    51.     o.uv += float2( 0.5, 0.5 );
    52.  
    53.     return o;
    54. }
    55.  
    56. uniform sampler2D _MainTex;
    57. uniform sampler2D _MaskTex;
    58.  
    59. half4 frag (v2f i) : COLOR
    60. {
    61.     half4 mainCol = tex2D( _MainTex, i.uv );
    62.     half4 maskCol = tex2D( _MaskTex, i.uv2 );
    63.    
    64.     return mainCol * maskCol;
    65. }
    66. ENDCG
    67.  
    68.         }
    69.  
    70.        
    71.     }
    72. }
    73.  
     
  29. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    Hehe nice work.
     
  30. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    Thanks Again for all the help..
     
  31. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    is there any way to take the final result and apply that as a Texture2D so I can use it in a GUI?

    I am wishing for the answer to be YES figures crossed
     
  32. Marc

    Marc

    Joined:
    Oct 4, 2007
    Posts:
    499
    I think eric covered the answer, but you can try doing something like this:


    Store the result in a Texture2D and put it on GUI. It will most likely be slow as you will be making a screenshot of parts of the screen each frame which is an expensive operation.
     

    Attached Files:

  33. madwilson

    madwilson

    Joined:
    Jun 4, 2008
    Posts:
    106
    ok.. I have been trying to get it into a texture2D for some time now but I cant seam to assine it to a GUI.Box(Rec(),texture2D); any help at this point in something that sounds very trivial would be most appreciated.

    I can apply it to a GUItexture but they don't play nice with my GUI script? second it seams that I have an alpha problem. witch I think I could get around if I could just get it into my GUI.Box instead of a GUItexture..

    Thanks again for the help
     
  34. SavaB

    SavaB

    Joined:
    Feb 11, 2010
    Posts:
    39
    you can allways split the pixelarray to a 2-dimensional array (using the image width and height). Then you'll have just a big-ass matrix, on which you can apply an rotation matrix.
     
  35. aerende

    aerende

    Joined:
    Apr 27, 2009
    Posts:
    316
    Is it possible to get the MaskTest unity package in this thread to work on Unity iPhone? I'm getting the following errors:

    Assets/Pro Standard Assets/Image Based/BlurEffect.cs(77,17): error CS0117: `UnityEngine.Graphics' does not contain a definition for `BlitMultiTap'
    Assets/Standard Assets/Scripts/DragRigidbody.js(31,22): BCE0019: 'isKinematic' is not a member of 'UnityEngine.Component'.

    "Shader Transparent/Mask: no subshaders can run on this garphics card.