Search Unity

Masking or cropping of sprite?

Discussion in '2D' started by JimMakesGames, Dec 19, 2013.

  1. JimMakesGames

    JimMakesGames

    Joined:
    Nov 13, 2013
    Posts:
    21
    I've been trying to figure out a way to do some kind of masking or cropping of sprites in Unity 4.3. The intent is to have a sprite move up into another sprite and appear to be disappearing into it. I was hoping that with some kind of mask or cropping I could just move the sprite up and have it disappear when it moves above the other sprite.

    This gif should illustrate what I mean: $scrollup.gif

    Is there any way to make the paper above the rolled up part of the scroll disappear? There will be a background eventually so having a black rectangle over the top won't work. I thought there would be some kind of sprite mask or ability to crop the sprite, but I haven't been able to find anything. I've seen some stuff about shaders but I have not used shaders before and I was wondering if there was a better solution. Any help you could offer would be much appreciated. Thanks. :)
     
  2. wccrawford

    wccrawford

    Joined:
    Sep 30, 2011
    Posts:
    2,039
    I'm surprised not to be able to find an easy way, either.

    2 options come to mind:

    1) Use a shader on an invisible block that simply hides everything inside the block. Make sure nothing else enters that block by having it on a different Z layer. (Might not work with 2D stuff, never tried it.) I've found this shader by searching for it, but don't remember where it is right now.

    2) Use multiple pieces to create that long paper piece. As they are moved behind the scroll at the top, hide them. (Or show them, for rolling the paper out.) Obviously, the pieces have to be as small or smaller than the scroll at the top.
     
  3. JimMakesGames

    JimMakesGames

    Joined:
    Nov 13, 2013
    Posts:
    21
    Thanks for your suggestions wccrawford. From what I've seen of the shader stuff it looks like it's tailored for the 3D, which makes sense. It looks like a whole new language and seems very arcane and bewildering. Making multiple pieces is a good idea, but it seems like it shouldn't be necessary. Fortunately I found a workable solution in having multiple cameras.

    I'll only have these at the top and bottom of the screen, with a bit of space above and below them respectively. So I was able to set up a second camera for the GUI which has a smaller viewport rect than the main camera, so the top and bottom are cut off, like letterboxing, with the cutoff right at the edge of the rolled up part of the scrolls. It's a weird way to achieve the desired result, but it works. I hope they will implement some sprite cropping or masking functionality at some point though. It would be very useful.
     
  4. Kurius

    Kurius

    Joined:
    Sep 29, 2013
    Posts:
    412
    2Dtoolkit has a UI component that does this.
     
  5. Digital Hermit

    Digital Hermit

    Joined:
    Dec 22, 2013
    Posts:
    2
    Can you please explain on how to do #1? I've been searching for hours now for a way to crop sprites. If this is the only solution, I'll take it.. but I have no idea how to make such "invisible blocks" that can hide its contents. Please help!
     
    Last edited: Dec 22, 2013
  6. wccrawford

    wccrawford

    Joined:
    Sep 30, 2011
    Posts:
    2,039
    http://forum.unity3d.com/threads/215465-More-than-backface-culling

    See my comment there for the solution I found for him. There are others, too, but this is the simplest one that will do the job, I believe. (I haven't used it.)
     
  7. Digital Hermit

    Digital Hermit

    Joined:
    Dec 22, 2013
    Posts:
    2
    Thanks wccrawford. I'll be sure to check those out.

    Btw, I've found a way to crop.. but offset is a bit weird due to pivot. You basically need to create a new Sprite object from the old one's textures and edit the rect. It's extra messy when dealing with a muti-image texture.

    Sprite cropped = new Sprite();
    cropped = Sprite.Create(oldSprite.texture, oldSprite.rect ,new Vector2(0.5f,0.5f),100.0f);

    In the sample code above you basically replace the "oldSprite.rect" with the cropped rectangle. Kinna works.. I stopped fully developing it out since I came across other workarounds. Just wanted to post this here for anyone still investigating.
     
  8. DKWings

    DKWings

    Joined:
    Jun 18, 2014
    Posts:
    1
    This might be it.

    http://wiki.unity3d.com/index.php/TextureMask
     
  9. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Sorry for kicking open this old thread, but I just ran into exactly the same need, and didn't find a good ready-to-go solution. But, based on comments here and elsewhere, I took the Sprites/Default shader and modified it slightly to only render within a rectangular area of the screen. It seems to work great in my testing so far.

    Here it is, in case anybody else finds it useful... (Just save this to a file called Sprites-Cropped.shader, create a material out of it, and set the properties on that material to reflect the area of the screen where it should draw.)

    Code (ShaderLab):
    1. Shader "Custom/Sprites/Cropped"
    2. {
    3.     Properties
    4.     {
    5.         [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
    6.         _Color ("Tint", Color) = (1,1,1,1)
    7.         [MaterialToggle] PixelSnap ("Pixel snap", Float) = 0
    8.         _MinX ("Min X", Float) = 0
    9.         _MaxX ("Max X", Float) = 1
    10.         _MinY ("Min Y", Float) = 0
    11.         _MaxY ("Max Y", Float) = 1
    12.     }
    13.  
    14.     SubShader
    15.     {
    16.         Tags
    17.         {
    18.             "Queue"="Transparent"
    19.             "IgnoreProjector"="True"
    20.             "RenderType"="Transparent"
    21.             "PreviewType"="Plane"
    22.             "CanUseSpriteAtlas"="True"
    23.         }
    24.  
    25.         Cull Off
    26.         Lighting Off
    27.         ZWrite Off
    28.         Blend One OneMinusSrcAlpha
    29.  
    30.         Pass
    31.         {
    32.         CGPROGRAM
    33.             #pragma vertex vert
    34.             #pragma fragment frag
    35.             #pragma multi_compile _ PIXELSNAP_ON
    36.             #include "UnityCG.cginc"
    37.            
    38.             struct appdata_t
    39.             {
    40.                 float4 vertex   : POSITION;
    41.                 float4 color    : COLOR;
    42.                 float2 texcoord : TEXCOORD0;
    43.             };
    44.  
    45.             struct v2f
    46.             {
    47.                 float4 vertex   : SV_POSITION;
    48.                 fixed4 color    : COLOR;
    49.                 half2 texcoord  : TEXCOORD0;
    50.                 float2 screenPos: TEXCOORD2;
    51.             };
    52.            
    53.             fixed4 _Color;
    54.             float _MinX;
    55.             float _MaxX;
    56.             float _MinY;
    57.             float _MaxY;
    58.  
    59.             v2f vert(appdata_t IN)
    60.             {
    61.                 v2f OUT;
    62.                 OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
    63.                 OUT.texcoord = IN.texcoord;
    64.                 OUT.color = IN.color * _Color;
    65.                 OUT.screenPos = (float2)ComputeScreenPos(OUT.vertex);              
    66.                 #ifdef PIXELSNAP_ON
    67.                 OUT.vertex = UnityPixelSnap (OUT.vertex);
    68.                 #endif
    69.  
    70.                 return OUT;
    71.             }
    72.  
    73.             sampler2D _MainTex;
    74.  
    75.             fixed4 frag(v2f IN) : SV_Target
    76.             {
    77.                 fixed4 c = tex2D(_MainTex, IN.texcoord) * IN.color;
    78.                 c.a *= (IN.screenPos.x >= _MinX);
    79.                 c.a *= (IN.screenPos.x <= _MaxX);
    80.                 c.a *= (IN.screenPos.y >= _MinY);
    81.                 c.a *= (IN.screenPos.y <= _MaxY);
    82.                
    83.                 c.rgb *= c.a;
    84.                 return c;
    85.             }
    86.         ENDCG
    87.         }
    88.     }
    89. }
     
    fruitsK and Bivisss like this.
  10. BenP_Leda

    BenP_Leda

    Joined:
    Aug 17, 2015
    Posts:
    4
    Not sure what's gone wrong (I have zero understanding of shaders), but this isn't working for me. I copy-pasted the code, created the material and assigned it to a sprite... altering the min and max values shows me the required segment of my texture in the Unity scene editor, but when I run, it looks like moving the camera position around messes this up!

    Any way this could be modified so that the cropping is constant, no matter what the camera's position?
     
  11. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Hmm, I don't know... I haven't observed any problem like that. The ComputeScreenPos position is supposed to calculate the actual screen pos, for the camera in use. Maybe it has something to do with the camera settings? I'm at a bit of a loss here.
     
  12. sandboxed

    sandboxed

    Unity Technologies

    Joined:
    Apr 6, 2015
    Posts:
    95
  13. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    That's a good point — though UI stuff and sprite stuff often have an uncomfortable relationship (completely different coordinate systems, awkward layering, etc.). But yeah, for something like the OP's need, using a canvas would probably be an easier solution.
     
  14. sandboxed

    sandboxed

    Unity Technologies

    Joined:
    Apr 6, 2015
    Posts:
    95
    Last edited: Aug 18, 2015
    smetzzz and JoeStrout like this.