Make a Cutout Mask in Unity! (Inverted Mask)
Вставка
- Опубліковано 25 сер 2020
- ✅ Get the Project files and Utilities at unitycodemonkey.com/video.php...
Let's learn how to make a Inverse Cutout Mask in the UI!
👇
🌍 Get Code Monkey on Steam!
👍 Interactive Tutorials, Complete Games and More!
✅ store.steampowered.com/app/12...
If you have any questions post them in the comments and I'll do my best to answer them.
🔔 Subscribe for more Unity Tutorials / @codemonkeyunity
See you next time!
📍 Support on Patreon / unitycodemonkey
🤖 Join the Community Discord / discord
📦 Grab the Game Bundle at unitycodemonkey.com/gameBundl...
📝 Get the Code Monkey Utilities at unitycodemonkey.com/utils.php
#unitytutorial #unity3d #unity2d
--------------------------------------------------------------------
Hello and welcome, I am your Code Monkey and here you will learn everything about Game Development in Unity 2D using C#.
I've been developing games for several years with 7 published games on Steam and now I'm sharing my knowledge to help you on your own game development journey.
You can see my games at www.endlessloopstudios.com
--------------------------------------------------------------------
- Website: unitycodemonkey.com/
- Twitter: / unitycodemonkey
- Facebook: / unitycodemonkey
🌐 Have you found the videos Helpful and Valuable?
❤️ Support on Patreon www.patreon.com/unitycodemonkey or get the Game Bundle unitycodemonkey.com/gamebundle.php
Here's something that took me a while to figure out, I'm hoping other people looking for the solution come across this video!
And also many of us will not have to struggle to find solutions as long as we have you. 🌸
@Maxwell Harris It will definitely come in handy )
Your tutorials are amazing and are a huge help I can't say thank you enough
Nice one! Pretty old, but still works - with a little update: I'm on unity 2020.3, and had to change "int" to "float" in material, like this:
SetFloat("_StencilComp", (float)CompareFunction.NotEqual)
Thanks so much I thought I was going crazy!
Thank you a lot! You saved me a lot of time, because I was searching on how to do this kind of transition and I thought maybe it was something to do with mask. And you helped me BIG time!
Thanks a lot, a nice and clean solution! I'll try this out for a tutorial mode to highlight certain parts of the screen.
You're a legend CM you made all these tutorials on different topics just in 2 years AMAZING also you reached 185K Subs In 2 years that's achievement bc I know some channels start way before you did and they don't have that much of subscribers great job
Thanks!
@@CodeMonkeyUnity no problem keep up the great work
Thx man all the vids you make are soo helpful and keep it up!
This is perfect, simple and elegant, thank you!
For those that don't work! You need to Disable the Show Mask Graphic box! It's very easy to miss in the video and got me for half an hour...
Thank you so much, couldn't understand why it didn't work
This was a huge help, thank you.
This is exactly what i needed keep up the good work!!!
Thanks so much for this tutorial!!!! I spent a lot of time trying to figure out workarounds for this, then I was saved by your video!
I'm glad the video helped! Thanks!
I spent weeks earlier this year looking for "inverse mask" and cutouts and only found shoddy tools etc. You make it look so obvious. I'll be implementing this technique for an in-game tutorial where I need to grayout everything but the button the player should focus on. Thanks!
How can you invert the raycast logic as well? I've used your technique to do the in-game tutorial, however only clicks in the blacked out area register, clicks inside the mask do not.
Yeah making it click through the mask is tricky, maybe try adding an invisible object on top with the same shape as the cutout and capture clicks in that object then pass them along to whatever object is under the mask
Thank you this is exactly what i was looking for
Worked perfectly, keep it up :)
That's amazing
oh... my... god... this was something I just could not figure out myself. Thank you thank you!
Thank you very much! This is what I was looking for)
yay just what i needed
this is a life saver, thank you!
short, precise, helpful. Thank you very much
Thank you for your work.
Thank you! Your videos inspired me to make a game.
I'm glad to hear it! Best of luck!
Hey bro! Never stop making videos. Never ever. Please. I want to see this channel grow and expand. This is in my opinion, the best Unity coding channel on the entirety of UA-cam, and i would not be able to code as well if i didn`t have your videos. Thank you man!
Thanks! I'm glad you like the videos!
Thanks, very helpful.
Heya! Thank you for revealing how to to do this! The thing I don't like about this approach though is that this seems to force a parent child relationship in order to work. Also, I don't want to worry about generating too much garbage making new materials😅
My approach was to create two materials as assets. I use the "UI/Default" shader for both. Then I change the properties of those materials like so:
Material 1 (This will define the "mask" that will subtract from Material 2):
- Stencil Comparison: 8 (Always)
- Stencil ID: 1
- Stencil Operation: 2 (Replace)
- Stencil Write Mask: 255 (This mask allows all values)
- Stencil Read Mask: 255
- Color Mask: 0 (Zero makes the mask invisible)
- Use Alpha Clip: true (Allows you to utilize the texture's alpha in the mask but can't control the "cutoff" value unfortunately)
Material 2:
- Stencil Comparison: 6 (Not Equal.)
- Stencil ID: 1
- Stencil Operation: 0 (Keep)
- Stencil Write Mask: 255
- Stencil Read Mask: 255
- Color Mask: 15
- Use Alpha Clip: false
Then I create two "Images" and assign the materials to them. I get the same effect but now they're siblings and I can rotate and scale them individually! The effect still works when they're parent and child too! The only restriction is that the image with Material 1 must be placed higher than the image with Material 2 in the hierarchy. I did encounter a glitch when I overlapped two sets of images. My solution was to add a third material that set the stencil buffer area covered by Material 2 to zero.
Material 3:
- Stencil Comparison: 8
- Stencil ID: 0
- Stencil Operation: 1 (Write Zero)
- Stencil Write Mask: 255
- Stencil Read Mask: 255
- Color Mask: 0
- Use Alpha Clip: false
Thank you So much friend.
You really did deserve that award
Thanks!
How to make the black more smooth?
Like transparent to black. I don't want hard circular shape.
Thank you very much!
Is there a way to do it while keeping the bigger image(the masked one) as the parent so that the masking image can move without effecting the masked image? I've done via hacky way and i didn't like it.
Image with rendering by CutOutImage component is not rendering after loading the scene async. Disabling and re enabling the object solves the problem but why its not able to work correctly after loading a scene?
nice video, thanks
Did not watch it yet. Anyways liked it. I know i will need this soon enough and it will help me a lot.
Nice tutorial big fan from INDIA!! 👌😍
Is it possible to keep the cutout part stationary when moving the parent image?
It is what I need.
Hi really thanks for the solution, But I did run into one issue, When using this as prefab and instantiating at runtime the mask stays for couple of seconds before disappearing. When checked in inspector there was no Shader component, but if I disable and enable the component is back, Am I missing anything here?
Thank you
This is very nice tutorial, but for some reason my mask is blocking the raycast whereas the cutoff isn't. Perhaps it might be just like the original mask intended, but how do you invert the function as well so that the holed one can be clicked instead of the rest?
I have the same issue.. were you able to fix it?
any way the code can be modified to only calculate one specific mask. I tried this method and it works but for my case I eventually don't want the inverted mask to get out of a certain area(mask it normally for it but still have the inverse mask inside it).
Whats about the raycast target? If the parent is a raycast target and we cut into it with the circle, can you click through the underlying parent image, or you always hit the parent object?
It doesn't click through by default, one approach might be to try adding an invisible object on top with the same shape as the cutout and capture clicks in that object then pass them along to whatever object is under the mask
Thanks
@CodeMonkeyUnity im using this guide to build a limited pov where the mask follows the player around and the rest of the screen is black around the player, i was wondering if there is a way to also punch out a second hole in the same mask? So bassically i have the hole that follows the player then another static hole somewhere else in the world?
I dont know why no one else make tutorials on this .
This is excellent and served exactly my purpose but I do have a question. How would one achieve extending this to multiple inverted masks? By this I mean, for example, having two transparent circles on the blue square at 6:12?
It wouldn't work for me because in 2021 version of Unity
SetInt has since been deprecated and _StencilComp property - made into a float. Use SetFloat and cast as float if You want this to work
Is it possible to make something like this and be only clickable only inside the inverted mask?
Hello, great video it helped lot, but I have one more question. Is there possibility to do it with TMP? What method should i override in some TMP script and how? Thanks for answer.
Could we somehow inverse masking click events? I'm thinking about a dimming view that highlights some spots in the screen, and only these masked areas are intractable? Thanks!
Hi there ik this comment is 2 Years old but I have the same issue right now and can't figure out how to do it. Did you manage to do this??
You used only rectangle shape on mask but i wanna use circle or any shape. When I try to use any sprite, i see strange pixels around the image. Why can this?
Yes Im finally ready to manually blink!
Will it cause memory leak (or great GC overhead)? Since each time you get that material you create a new one.
In my case it is called only once. I still cache the new material anyway.
Please make a video about the stencil buffer. Also, how to incorporate it in Shader Graph
Hi, the masking method worked great, but I ran into an issue when using this simultaneously with LoadSceneAsync. When the new scene with the mask is loaded, the mask doesn't get rendered until the color of the background is manually changed via the inspector. Adjusting the color via script doesn't seem to work. Any ideas why that is?
I'm having the exact same issue and couldn't find a solution yet did you? It doesn't start working properly when loaded async.
Hi , thank you for this amazing tutorial , can you tell me how to inverse the raycast target also .
I figured it out here is the code if anyone interested
public override bool Raycast (Vector2 sp , Camera eventCamer )
{
return !base.Raycast(sp,eventCamer);
}
This works, but is there a more permanent solution that modifies the mask component instead? I have UI elements other than Image
If you are having issues with selectables not being raycasted it's due to the Masking component, instead create a new material and assign it to your masking image. Copy the Default Masking Components Stencil properties: Stencil Comparison 8, Stencil ID 1, Stencil Operation 2, Stencil Write & Read Mask 255, Color Mask 0. This will act as a mask but not apply the raycast blocking.
Can you please create a sample project ?
is there any way to make a cutout mask from multiple objects?
Hey CodeMonkey! I love this however in unity 2022 I had to set the transparentcy of the mask to 1 to actually have it properly cause that (tansparent dot) effect, now I'm struggling to find a way to move the mask without moving the Image acting as the inverse mask. I'm trying to achieve an effect where everything on screen is blocked off except a dot which follows the player on screen. I'd also just like to know if I can make the "mask" animated.
Thank you kindly.
Whenever you move the parent, you need to move the child object in the opposite way. If you move the parent X+1 then move the child X-1
I could never guess you could change render pipeline like that! Now this is setting integers but what if I just wanted to add some antialiasing to the mask?
I’m trying to use these for see through bullet holes how can I do this?
Hey @CodeMonkey can I have the code check for transparency on the mask? That way I can create a sudo spotlight, sort of like in Zelda a link to the past.
Do you mean a fade? Not with this method, it's either fully opaque or fully transparent
This approach may cause some issues. For example: when changing scenes (when it's DontDestroyOnLoad) if the object (Image) is not focused - it disappears. Therefore it doesn't work properly for scene changing (all platforms). Tested on Unity 2020.2.1f1
Has anyone found a better solution than my quick and dirty hack for this?
cutoutMask.enabled = false;
cutoutMask.enabled = true;
@@ollieblanks2751 yeah but it's different from the basic concept. But hey if it works just leave as it is, it's not that bad with a comment in code
@@ollieblanks2751 I would imagine calling RecalculateMasking() would be a bit more efficient but not by much.
@@ollieblanks2751 should I put this in Awake or Start? Disabling and enabling the script doesn't seem to work for me.
@@AppsolusZero
Enabling and disabling the script, as well as RecalculateMasking() also failed for me when I put this in the Start function.
BUT, I noticed this worked if I put this code inside the Update function and I'm not sure why.
To optimise performance, I will try a coroutine that runs this, instead of on all frames in Update.
Do you mind me asking how you figured this out? As someone who also tried to solve this problem before, I'll be interested in your research process. I attempted a custom shader, but it was very inconsistent on mobile devices. Did you basically studied the Image component to try and find a way? Or found a resource pointing you in the right direction? Past experience with something like this? Thank you, love the channel!
I went on google and found like 5 separate posts on the Unity forums talking about how it could be done and how the UI uses the stencil buffer, so I looked some more to figure out exactly how the UI was using it and what the mask and normal image components were writing to the stencil buffer. One of those posts mentioned that you can extend the Image class and override the material so then it was just a case of figuring out how to invert the comparison that the normal mask was doing and that was it.
The information is all out there but for more obscure things its usually separated into lots of different places so its all about putting it together and testing it out.
Now in the future if someone has the exact same question I had hopefully they will come across this video which shows the whole effect working.
I had a similar process when figuring out how to do Cinemachine camera shake, there was no direct answer but there was mention of the noise component and from there its easy. ua-cam.com/video/ACf1I27I6Tk/v-deo.html
Nice, thanks for the answer! I probably didn't think to extend the Image class because I had a negative experience extending from Button (the Unity inspector basically broke) . In the future I will consider the option of learning the internals of Unity classes, so I can extend and adapt their behavior. My misconception was that it was not worth it, but as you shown, sometimes it can be even simpler than the alternatives. Good stuff, thanks!
Does this technic work for 3D objects? I'm trying to show only the parts of the 3D objects that are inside the curout
This is a UI effect so if you make it black all around and transparent in the middle it will show whatever the base camera is showing which could be some 3D objects
Hi. I'm making top down 2D game and using sprite mask of a circle sprite to reveal what's inside (sort of like fog of war with flashlight). But i wish to have some areas of the map on which this sprite mask should not have effect (DONT reveal this part in ANY cases), and this parts will dynamically change in game. is there a way to achieve that? Mb if its easier (which will give same result) to some how only show object where two different Sprite Mask's intersect?
your code doesnt cache the new created material and create a new one each time you access the property
@Code Monkey Btw. I bet you did some video on Octopath's kind of blurred screen FX (through shader graph?), that we see now.. where is that video? I kind of missed that out..
I did cover a Blur but that effect is more just playing around with Depth of Field Post Processing
This is great, but doesn't work if you need cutout part inside another normal mask. I am trying to figure it out with stencils but I have no idea how to make work cutout mask in conjunction with normal mask.
Same problem. Thinking of the way to be able to use Cutout effect only for some of the masks, but not all of them. Only Rect Mask 2D able to cut off the new Cutout Mask for some reason.
@CodeMonkey Thank you for the great tutorial. Do you have any thoughts on how to make Cutout Mask be able used with a standard Mask (crop images)?
Great video! One question though: Works great in Unity editor but not on iOS for some reason (image does not show at all...)?
Should this work with URP? doesn't for me :(( (or I'm doing something wrong)
Cant ant one help where masked circle blocks the buttons and the circle part we can interact
Hi Code Monkey,
Do you have any tutorial on how to do energy/live system like the one in candy crush? If you don't, can I suggest you do that please :)
I want to mask UI , but don't want the parent to contain the mask component ,
that is , I want a mask component on a free object not on parent coz I will be changing the size of parent and this is causing me to change in masking area ,
What can I do , Please help.
Sprite mask is perfect , in that I am not forced to attach it to only parent , can't this type of thing done for UI ?
This doesn't appear to work for me.
The override has changed the Stencil Comparison to 6 in the inspector but the mask is not inverting; just behaving as normal.
Weird eh?
Edit - One word - Android.
omg been ripping my hair out for days with a complex issue and this saved me. WHY does Unity not support RenderTexture stencil in shader graph?! I used this solution in order to create an inverted (cutout) mask to create black borders for my HD area map and other UI stuff. I'm using an older aspect ratio, so I wanted black borders on HD full screen elements to keep consistent with the low res game view RenderTexture. Many thanks.
This method doesn't seem to work when changing scenes unfortunately
Wow, very simple but effective!
Thank you very much for this great tutorial :)
Btw, is there any way to achieve smooth edges with this?
Currently, the half transparent pixels of my mask image completely block resulting hard and dirty edges.
Yes, using this method the pixels are either fully transparent or fully opaque.
For smooth edges it depends what you're trying to do, for example if its a circle cutout then you can make a Texture that smoothly becomes more transparent inside a circle and fit that exactly on top of the cutout shape, just like in the video thumbnail.
@@CodeMonkeyUnity Thanks!
@@CodeMonkeyUnity Sadly this doesn't seem to work! At least not with the basic Sprite Mask object that has an Alpha Cutoff slider where everything above the cutoff is shown fully opaque or transparent, and everything below it fully the opposite (based on mask interaction setting).
It doesnt work on Android for me, someone managed to do it on mobile ?
Same here, doesn't work on mobile.
How do I extend this to Universal Render Pipeline?
Hi CodeMonkey,Do you have any video on 2D platformar Games?I want make Gun and add Particle Effect?Where Should i start?
I made some Jump videos ua-cam.com/video/DEGEEZmfTT0/v-deo.html
And some weapon videos ua-cam.com/video/fuGQFdhSPg4/v-deo.html
I would have never come up with this idea,
I would have probably just used the vignette from post proccesing effects. (no idea if this would work)
awesome tutorial on it,
I guess you really need to know how this stencil thing works to be able to change it in the way you need
Is there any way on using this with multiple cameras?
where one camera only shows whats inside the object, the other only whats outside
could be used for quick transitions.
I also heard the terms mask and stensil from people talking about how to achiev a non-euclidean world in unity,
where you can walk into a room thats bigger on the inside than on the outside for example,
it's usually done by teleporting the player when entering the room without him noticing,
but you have to show the inside of the room while standing outside and vice versa.
so you have to show a distant location in the doorway
Any idea on how to do this?
this video might help to understand what I tried to explain
ua-cam.com/video/U3sTSWJF_qA/v-deo.html
@@bluegru Maybe this Video from Sebastian Lague could help you ua-cam.com/video/cWpFZbjtSQg/v-deo.html
Vignette would definitely be a valid approach if your goal was to make exactly this effect, but the cutout mask has more uses.
Making portals is a very tricky subject, that video from Sebastian Lague is awesome and will definitely guide you in the right direction
Just wow, great video
Don't know how I missed it in my search.
I found a similar one from brackeys, but he didn't go as much in depth and just provides the script.
Also he doesn't take care of the objects between camera and portal, or objects moving though portals, or portals visible from inside a portal.
Nonetheless, both videos are awesome and will be a help in trying to creat something like that,
but they both use multiple cameras, where as the video I linked used just one.
still on the hunt for that method
Upadte:
I'm one step closer
ua-cam.com/video/qjm1OSBaCfo/v-deo.html
Helpful video. There are very less good videos on UI and visuals. If you get time consider doing a tutorial on those topics it'd be much appreciated.
Hey Mr. Monkey! Really awesome solution. I ran into a problem though. Is it possible that there could be a problem with masking filled images? Using an Image as mask, there is no problem. Using this script instead, the masked image disappears on Scene change and only reappears when I disable and enable the image or change the fill amount (or changing any parameters in the inspector for that matter). It's super strange. Any ideas what this could be about? Thanks!
Hmm that's interesting, I'm not sure how the fillAmount is handled in the back-end, it's possible that it's also using a shader with the stencil and might conflict with this one.
If that happens then another approach you can take is handle the fill yourself. Instead of using the automated method just write some simple logic and modify the object sizeDelta. That way the object is just a normal image being sized so it should work without issues.
@@CodeMonkeyUnity Thank you so much for the fast reply! I need it for a radial fill and I think that might be a tad more complicated. I guess I will just draw a ring in everyone's favorite graphics application and use the standard mask in this case, but for other cases, your code is gold and let me thank you for all the hard work you put into your awesome tutorials! :)
Huge problem, it flipped all of the mask comparisons in the canvas and now none of my images show up. Is there a way to fix this?
Did you forget to do new Material(); ? If so then either restart unity or modify the base material again.
@@CodeMonkeyUnity Ah, I think I did do that
Sorry for wasting your time and thanks for the quick answer!
Uh this like completely broke all of my images in my scene. It works, but none of the other images appear visible for some reason. How do I fix this?
Did you forget to clone the material? If you don't then you're modifying the default material that is used by all objects
@@CodeMonkeyUnity Ah, yep my mistake. I forgot to add "new Material(...)" in the script when duplicating the material. Thanks!
Also, for anyone who makes the same mistake I did that messes up all the other UI images in the project, just go to Assets > Reimport All and wait a little bit. This fixed all of them for me.
I need to implement multiple masks on just one background. any clue?
Like multiple holes on a background
I'm currently on Unity 2017.4.4 (sigh) and it's not working. Anyone running into similar problems?
It’s not the version. Mine works fine, it must be something else.
WARNING! This has a side effect - GraphicsRaycaster is no longer blocked by the inverted graphic or, rather, blocked in the cutout area only!
What's the solution to it @tomassvedas2066
Hi! Can we click through the hole? It would be very useful for a tutorial...
Not just like this, the circle and the black background are normal images which block raycasts.
Maybe you could make the circle into an invisible button and test that
@@CodeMonkeyUnity i see i'm trying to achieve something like the black image will block raycast but the circle will let raycast through.. thanks!
But how does the "Image" child object not get altered by it's parent? 7:12
I would personally prefer that the black quad would be the parent object, and the circle would be the child. So that you can animate the circle and not have it affect the black quad, as that should just span the entire screen.
The child image does not have any anchor relative to the parent, it only has a pivot in the middle, so modifying the parent size does not change it
@@CodeMonkeyUnity That is true. Though, if you wanted a spotlight effect that could move around, this would cause issues and you'd have to make a script to "bypass" the parenting behavior. Unless I am mistaken with what is possible with rect transforms.
I did find another video with a different (but similar) approach, but doesn't require any new scripts. So if you ever wanted to revisit this topic in a new video, the channel who made the video is "jean-gobert de coster", and you can find it by searching "invert mask". I can't link the video unfortunately...
But it's same concept of changing material parameters.
@@Andrew90046zero Great tip! Thanks a lot!
This approach does work but when you reload a scene the mask stops working. I found a different approach creating the same masking technique with just materials: ua-cam.com/video/ZoiNP5IfBBo/v-deo.html
can u make a thermal vision for the player
loved the video btw
The implementation will depend on your specific game but for applying the post processing effect I covered it here ua-cam.com/video/77Lc43yTREo/v-deo.html
How did he manage to move the parent object without moving the child object?
Where are you seeing that? Moving a parent does move the child
@@CodeMonkeyUnity My apologies, after through rewatching i found that the rect you were moving around was the child HAHA
Is it possible to do this for see through bullet holes
This is a UI element so not really, although you could use a similar technique with a custom shader.
@@CodeMonkeyUnity ok thanks
@@CodeMonkeyUnity could you give me any tips how to make it
Your site doesn’t work
Thank you for the awesome Tut. I think there is a bug here when I extend the image and override the material I can't use regular Unity Images without adding a mask component to them.
That's been bugging me when I tried it on my own and I also tried a similar method before and faced this bug. Can you please check on your project and let me know if the same thing happening to you as well? Also if you can guys have a solution I'm all ears
Dark theme! Please
Sorry, dark theme burns my eyes