Blend Modes & Silhouettes | Game Maker Studio 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey the guys so today we're going to learn about blend modes and then use them to make object silhouettes and by silhouette I mean this effect here that some games have when characters move behind objects so while sometimes games will just have the character going out of view when they move behind an object others will actually draw the characters silhouette through the including objects that we can still see where it is and usually that's how it is just the sprite of the object shaded all one color now good news and bad news here so the good news is that the code for this is actually pretty simple it should only take about 20 lines of code but the bad news is if you haven't really messed around with blend modes or color channels and you have no idea what any of that is a lot of the functions that we use today are gonna seem pretty incomprehensible at first so that's why I'm actually going to take quite a bit of time to go through some conceptual stuff about blend modes before we actually jump into the code of course if you don't really care about the Y and just want to stick objects silhouettes in your game then you can jump to the end of the video but you probably won't learn much that way all right now before we actually get started there's a couple of prerequisites for this video firstly I'm not going to be going through setting up a project importing assets or setting up play movement or anything I'm going to assume that you've already done all that and secondly since we want the silhouettes to only be appearing when we're behind an object we're going to need a depth system in place so by that I mean objects that are higher up on our screen we want to make it so that they are behind the objects that are below them since they're kind of further away in the game world and this is going to give us the appearance of a depth in our game so this doesn't happen automatically in game maker you have to set this up yourself if you don't have a depth system yet then I'm going to direct you to one of my other videos that will step you through it and just to note that video will cover two ways of making the depth system and for this silhouettes tutorial I'm just going to be using the depth equals minus y method which is the first one I show in that video so if you're new just use that one there if you have set up something like the second one which is kind of just using a data structure that collects the IDs and positions of all of your objects and then sorts them based on their Y and draws them all I'll still be pointing out how you can make the silhouettes using a method like that all right otherwise I'm going to assume that you have all of your assets and your depth system set up and we can so let's have a think about what we actually want to do here so consider what game maker is drawing to the screen in one frame so we start off with just a blank canvas and then we draw all of our tiles which is just the grass and then we draw all of our objects starting with the ones at the top and going down to give us that appearance about depth and now if you just take the player and the tree is an example and say that I want to draw the plays silhouette when we go behind the tree here wherever they overlap at the points of intersection I want my player silhouette to appear so I need some kind of way of getting where where overlapping so you might think that to do this we just have to set up some kind of filter that just lets certain values of the player spark through the tree but actually we're gonna do it a bit differently so everything is going to get drawn as normal so we're going to get the player then the tree but then on top of that we're just also going to draw the silhouette but only add those overlap points and to do this we have to understand what game maker is doing when it crawls each pixel to the screen so remember how I said we start off with a blank canvas and then we just keep drawing all of the sprites on top of each other kind of like sticking a bunch of stickers onto a board well this is a bit simplistic and we're going to take a little bit deeper so our image here is composed of a certain number of pixels right and in game maker when we're telling our GPU what to render for each pixel we have to give it some information for what to draw and that information comes in the form of four channels that we write 2/3 of those are the color channels the RGB channels which you probably heard of so those are the red green and blue channels and you've probably seen these before when you're playing around in the sprite editor or any drawing program really when you're selecting what color you want to paint the sprite so we have our RGB values going from 0 to 255 and combining those we can make all of our colors from that so every single pixel has its own unique RGB value and that's what's gonna give it its unique color and what happens is every frame of our game once we've decided what we're drawing we have to send this information of the color channels for every single one about pixels off to the GPU for it to render that pixel at that appropriate color so before we actually send it off though is a bunch of processing to figure out what that pixel is going to look like so every time we draw something to the screen you can think of that as changing the value of these RGB channels for that pixel and once we've finished changing it whatever it's left as at the end that's what will determine the final appearance of that pixel so let's jump to the start of the stage where we're changing the values in these channels and we'll just take one pixel as an example so at the very start of the frame there's nothing on the screen so it's completely blank canvas accepts everything isn't going to be white like you might think it's actually going to be black because the RGB value for no color 0 0 0 right for each our RGB values is black which makes sense this is no color on their light nothing and this is what you'll get by the way if you're just drawing nothing at all in your game so if your room is completely empty it has no background they're no sprites at all you'll just get a black screen ok so we start off black and then we draw out the tiles in our room so say we just had a green tile where our pixel is so that pixel is changing from its black RGB values which was just 0 0 0 and now it's gonna be green and then actually let's say that the player object is actually on top of that green tile so we need to change those values again from green to red all right that's easy enough but what happens if say we don't have the player object there we actually have this kind of blue ghost character and this ghost right instead of being completely opaque which means it has no transparency because it's kind of ghostly let's say that it has an alpha value of 0.5 so anything drawn behind it is going to kind of appear through that sprite so it's 50% transparent so if we come back to our green pixel we actually don't want that green pixel to change into something that's completely blue because Algar sprite is transparent so we actually want this pixel to show some of that green so these colors are actually going to get landed together where the amounts of each color are going to be determined by the alpha value of that end color of the girl's character so that 0.5 alpha of the blue from a ghostly King and since its point 5 we're gonna have an equal value of the green from the grass and the blue from the sprite so this blending of the colors when we draw something new to the screen is actually happening every time not just when things are transparent it's just that when the sprite is fully opaque the alpha value of this end pixel is 1 so the blended result is just gonna get none of the old color none of the grass and all of the new color so every time we draw something new to the screen what's actually happening is we're blending the colors that are already there with the new ones that we want to draw and we refer to these two colors when we're blending as the destination color which is the one that's already there the grass and the source color which is the new one and if we have a look at kind of how the math works for this there's this basic blending formula which I've just pulled from a blog post by Mike Daley called alphas and surfaces which you should definitely check out if you're interested in this stuff so as I was saying so every time we blend something new the final color the final result of the blend is going to be a sum of the source color and the destination color so the new color and the old color but actually it's not going to be just the colors just added straight together we're actually going to change each of those by some kind of factor so the sauce blend factor and the destination blend factor and as I said before by default this has got to do with the alpha value of the new pixel of the sauce color right so the transparency value of the new sprite being drawn so each of these kind of corresponds to the amount of the sauce color and the amount of the destination color that we get in the end so how much of the new color are we getting and how much of the old one so how much of the new one is just going to be the Alpha value of the new one so the source color times its own alpha and in the destination color so the old color is just going to be so the inverse of that alpha right so that's how much of the old one that we're keeping so generally if our new source color is completely opaque like from our player right then it's alpha is gonna be one so the source color is gonna just get multiplied by one because that's the source alpha but the destination pixel is going to get 1 minus 1 so 0 so it's completely gone whereas if the sprite has say an alpha of 0.3 so it's quite transparent then our sauce color is going to get multiplied by that alpha by 0.3 and our destination color our old color is going to get multiplied by 1 minus 0.3 which is 0.7 so we're actually going to get mostly the old color in this case now this was actually a little bit simplified because this blending is actually happening for every single channel so our sauce color our red value is going to get multiplied by the source alpha and the same for the green and the blue and actually remember how I said there's four channels so I've gone over three you've gone over the RGB ones but there's actually a fourth and that's the Alpha Channel right so the alpha of that final pixel and it's gonna get treated exactly the same way so the Alpha of the source color is going to get multiplied by the sauce blend factor which happens to be the source alpha by default and the same for the destination color alpha and this might make more sense if you imagine layering a bunch of transparent sprites over each other to get some kind of end alpha value for that pixel all right so that's the basics of how blends work but actually that is just the default blender that we've gone over and by that I mean if you look at our general formula at the source flan factor right so that doesn't have to be the source color alpha it's just that by default but if we multiply the source color RGB values and the destination color RGB values by something else we could get a different result of what our final pixels look like so this is where blend modes come down to so different blend modes will use different factors to blend the two colors together so for example there is a blend mode called additive and so while the source color still gets multiplied by the source color alpha the destination color just gets multiplied by one so we're actually keeping all of the destination color all of the old color which is adding the new color to it so additive it kind of blends the colors a little bit more because you're gonna get all of the and all of the red and if you can imagine adding colors together we're going to get closer and closer to white so it's actually going to make the sprite a lot brighter because all of our values are going to be closer to 255 so let's say we draw three circles onto a completely black screen so remember every black pixel has an RGB value of zero zero zero so this red one is completely red so it's pixels will have values of 255 0 0 right so no green and no blue just all red and likewise the green will have 0 255 0 and the blue will have 0 0 255 so this is the normal blend mode so I've just drawn the red one first than the green one and then the blue one so of course we're just getting overlapping circles but if we change the blend mode to additive then there's points of overlap are going to be adding the values together so at the overlap between red and green so 255 255 0 is gonna be yellow and so the same goes for the rest and at the very center at the overlap of all of them all of our RGB values are gonna be filled at 255 255 255 and that is white so we have actually made our own color pyramid which is pretty cool right so that's how the additive blend mode works another cool thing that we can illustrate is the subtract blend merge sir it works similarly to the additive blend mode but instead of adding the sauce color to the destination pixel right instead of adding the new color to the old color we are taking away the new color from the old one so we're gonna be subtracting color from whites to get other colors so in the case of the red one so we're subtracting 255 from the red channel with the blue and the green stay intact so we get cyan so then the same goes for the green circle on the right so we have everything except green and then at the points of overlap so the overlap between what was the red circle animal was the green circle we're subtracting all red and all green so we're only left with blue so it's kind of the inverse of our original one okay so hopefully that gives you a good idea of what blend modes are and how they work let's actually start to use them to make our object silhouettes all right so I'll just get you oriented with my own project so I have three objects set up my King which is just the player controlled objects I've got just some trees to put in the room and a knight so I've just got a few of them here in the room and right here is my room editor and my tiles and everything talked about one instances there here and that's where all of my objects have gone into and I've got two folders here so these are my tiles in the below folder that's where I'm keeping all of the tiles that are below my player so all of the grass tiles and then above that's just the cliffs yeah that I want to draw on top of my player so I'm not actually depth sorting the tiles I'm kind of cheating a little bit so for example if I grab the king if I come in front of this tile here I appear in front of the tile but if I am behind the tile I go behind it and that's just because this tile this cliff tile I've just drawn above the player all right so let's have a think let's say my player is partially occluded by this cliff here and just like we did before let's go through how game maker is going to draw all this so it's going to go through and draw all of these tiles first all the grass tiles then it's going to get to the player and it's at this point - right after the player draws itself is when we're going to start playing around with the curve because that's when we have to start collecting information about whether there is an overlap between the player and everything that draws after the player so we'll close out of this and we'll come into player objects and into its drawer event so you can see right here I'm just drawing a shadow and then the players just drawing itself so now I'm gonna set up a mask over the player after we've drawn it and then we are gonna set the mask at certain values and we know that if anything draws on top of this mask we know that it's going to alter those values and those bits will be the occlusions and that's where we're going to draw the silhouette so that's kind of what we're gonna do here but we have to draw the mask in a way that doesn't actually alter the original picture so what we're gonna do is we're only gonna draw that mask which is just going to be a rectangle over the player we're only gonna draw it to the Alpha Channel that way we leave the RGB channels completely intact so the original image isn't gonna change all right and this is gonna seem a little bit weird until everything is set up so just bear with me for now so the first thing we do is we turn off all the other channels so we use GPU set color right enable so with this we can toggle what channels that we're writing to so we turn off the three RGB but we leave the Alpha one on all right and then another thing I'm gonna do is turn off alpha blending and we use GPU set blend enable so by making this false essentially anything that we draw with any transparency so if it has an alpha value of less than one it's gonna be drawn and it's full opacity so everything is gonna be completely opaque don't worry this will make sense in a second because we are now going to draw the actual mask which is just going to be a rectangle over the player and now because my play is origin is at sort of the bottom in the middle to draw a rectangle over the player I have to get the top left corner of the sprite so the x coordinate for the top left corner of the sprite is just going to be whatever the x position is minus the sprite X offset because the X offset is just equal to the x position of the origin and we just do the same for the y that's going to get the top-left corner so now we can draw our rectangle so that top left corner and now the bottom right corner is just going to be the X plus the sprite width and the y plus is right height so there we go we've drawn the rectangle and we just put false here because we don't want an outline we want a full rectangle and now what I'm actually going to do is so I'm going to draw this rectangle at an alpha of zero all right so this probably seems pretty weird so why have I done this so I'm drawing a rectangle this rectangle here just over the player what would be just a white rectangle but I'm only drawing it to the Alpha Channel and I'm drawing it at an alpha observer so this is kind of like a completely invisible rectangle but because we've disabled alpha blending so it's still gonna feel the Alpha Channel but the value it's gonna fill it with is just zero so the Alpha of the area over the player is now going to be zero and what we're gonna do later is because we know it's zero we know that anything on top of the player with an alpha of one that means there is an occlusion there so we will draw the silhouette there but any area over the player if it has an alpha of zero we know there hasn't been an occlusion so we don't draw the silhouette there that's basically what we've done now because we've messed around with all of these things of course we have to remember to turn all of them off afterwards so we reset the draw alpha to one because I don't want everything else drawing in this odd way and we turn all the channels back on so that everything after the player can draw itself normally and we also allow transparency in our images so so the only thing that we've done is draw this kind of alpha mask over the player and you can see that if I run the game nothing visible should have changed right all right so now what I want to do is basically after everything has drawn itself I want to go back and then check on my mask so the way we're gonna wait until everything is drawn itself is we can just come to a different event called the draw end and this is gonna run once everything else has run their drawer event so after the tiles have run after any objects that are in front of the player so we come into here so actually first let's just draw the silhouette itself so basically what I'm doing is just going to get the player to draw itself again but I want it to draw itself just one complete color and you could use a shader for this but I am just going to use something called GPU set fog and this is sort of made for actually 3d because it sort of draws fog at certain depths but because this is a 2d game it's not like the fog is going to kind of fade as we go further back it's just gonna be one dimension the fog was there or it's not so we don't really have to mess with these values we can just enable it so we'd put true we give it a color so you can just go see like this and this will be the color of your silhouette so you can pick from any of these I'm actually going to merge a couple of them together and what this does is it just matches black and well for me maroon and it's gonna get the color that kind of halfway between them so from a value of zero to one and I'm just put point five and then finally it's asking where do I start the fog and where do I end it and we actually don't even have to worry about that we can just give it the default values it gives you if you just middle click on this and look at the documentation so I'm not even going to mess with that I'm just gonna put 0 1 and then of course when we're done we turn it back off okay and if I just draw that just to give you an idea of what it should look like of course it's just drawing it straight over the player so that is what the silhouette it's going to look like but we only want it to be appearing here right so let's do that so we're actually going to change the blend mode that we're using when we're drawing this I remember the blend mode is going to change the factors that we use to plan the source and the destination colors so the new and the old so we're gonna GPU sess blend mode and there's a couple different functions for this this one will just allow you to set one of the predefined ones one of these so this is the additive one subtracts normal max but these are the actual constants for the factors so this is just the source alpha this is the inverse alpha for the normal but I don't want to use any of these I actually want to set my own ones so we're going to use ext and now we have to set a factor for the source and for the destination so let's come into here and have a think so remember our formulas from before in our default blend mode the sauce color is getting multiplied by the source alpha and the destination color is getting multiplied by 1 minus the source alpha so it's all dependent on what is new but for our purposes we actually don't care about what's new we care about what's already there because we want to have a look at what the mask is equal to so if the mask is equal to zero then we know the mask is intact and nothing has drawn on top of the player so what we actually care about is the destination alpha so our new source blend factor is going to be the destination colors alpha so this way so the new pixel which is going to be the pixel of the silhouette if we times that by the destination colors alpha if that mask is undisturbed and then that will be the silhouette times 0 so when getting nerve silhouette where the mask is undisturbed but where it is disturbed and where there is something bad then a destination color alpha is going to be 1 or something between 0 & 1 so we're going to get the silhouette drawing that and then for our destination pixel well we just have to put the inverse of the destination color alpha so the old pixel where there is an inclusion we don't care about so the old pixel is going to get 1 minus 1 so it's going to get 0 so we're going to get none of the old color whereas if there is no occlusion than the destination color alpha is going to be you're still so we're gonna get one - sewer if the play is mosque is undisturbed that will just be the player so the two values we want is BM destination alpha for the source color and B M inverse destination alpha for the destination so we put all right and of course we have to turn it back off here and we can actually just reset it using the other function to normal to the default so let's have a look at this so we come behind the cliff and well it almost works it's only drawing the silhouette where there is an occlusion so we can see the top of that king's head is normal but it's just drawing a rectangle at the occlusion whereas we kind of want to see just the king's legs so why is this happening well as you probably know when we draw a sprite we don't just draw a cardboard cutout of the image itself we draw this entire rectangle here and it's just that most of this is transparent so normally we don't see this but because of how we've messed around with a blend mode instead of drawing those pixels at an alpha of zero our blend mode here is actually going to be using the destination alpha remember so where there's an occlusion that destination alpha is going to be one so it's gonna be those what's supposed to be a transparent pixel and what that actually does if we come back to spry is if you have a look at what is contained in the information about this pixel is transparent pixel so it's set to zero zero zero for the RGB values so this is actually a black pixel at complete transparency so at an alpha of zero and the only reason it's appearing maroon color is because of our fog so it's drawing black pixels at full opacity so we've got this one one problem to solve and luckily this one is pretty simple we're just going to turn on what's called alpha testing and what this does is it means there will be a cutoff value at which all alpha values will be set to zero so the default for this is just zero so this means so if anything has an alpha of zero it's not going to be drawn so it looks at the sprite it sees that it's alpha is supposed to be zero so it doesn't draw it so after we're done here of course we have to turn this back off and now we'll have a look so perfect so that's essentially it but as it stands you might want to make some more modifications because at the moment the silhouette is getting drawn when the player goes behind anything at all so object styles anything whereas you might just want it to draw when the player goes just behind tiles and also right now we're only drawing the players silhouette but you might want to get a bunch of other objects having their silhouettes drawn as well so we're gonna implement both of these changes now all right so remember our rectangle with zero alpha over the player so instead of just drawing it over the player we're going to want to draw it over the entire view so that way it can include multiple objects in this and also we know that when we draw this rectangle it's going to determine when we set the mass down and start collecting information about any including objects that are draw and afterwards so we only want to draw the mass to collect information about the tiles so we need a way of waiting until all the objects have drawn themselves and now this is where the depth system is going to come in and the method will change slightly depending on the one that you're using so firstly we'll go through what we'll do if we're just using our depth equals minus y first so we're gonna make an object I'm just going to call it objects silhouette and then if we come into the room so basically I want this obj slow it I'm gonna get it to draw the mask after all of our instances have finished drawing and the way to do that is just to make another instances layer drag it above the current one I'm just gonna call this instances last because I know anything in this layout will draw after all of these I'm going to drag the silhouettes into here doesn't really matter where we put it and just take note so it's at a depth that is much much much lower than the instances themselves and it's just this ridiculous value because all of our objects their depth is going to be related to their y-value because I'm just gone death equals minus wipe so we have to ensure that minus y so the lowest depth it could possibly have is just gonna be at the dimensions of the room so I've just put quite a large value for this one so it is now at a depth that is lower than all the instances but higher than the tiles so come into here and in its drawer event so we're gonna grab all of that stuff from the player because we're not going to get it to do this anymore and we'll put it in here of course we're not going to be drawing this rectangle over the player anymore it will be over the view so we need to get a bit of information about the view so it's X and y position in the room and also its width and height so I'm going to get rid of these and just make a few different variables all right so we're just getting the X in my position of the camera and also its width and height and I can use this to draw the rectangle now so here I'm just going to change this to be the so the top left of the camera it's going to just be it's XY location so we can put CX and see why and then just see X plus the width of the camera and see Y plus its height all right so now that draws the mask over the entire screen now let's come and grab the silhouettes so grab all of this we can delete this event from the file make the draw end for the silhouettes and paste us in here but now instead of just draw self because draw self will be referring to the silhouette I don't want to do that I want to refer to our objects so actually if I just go with the King object which is the player object and if I just run the game now actually everything should work exactly the same right so we're still getting silhouettes but we just also need to go with all of our objects and also now we should see that when we go behind the objects like the Knights and the trees so we're not getting the silhouette all right but now we need a way of getting not just the King but all of the objects so we could just go with the Knights but I am just going to make a parent and then make its children all of those objects that we want to draw their silhouette so add the king and add the Knights so now I can go with the parent object and get all of them to draw themselves and so now they'll all be drawing themselves just like this so if we run it now there we go and if you want and what you could do is so maybe you want like different colors for different objects so if we make us a little bit more complex we can actually change the fog depending on what object it is so I'm gonna grab this and then say so while all of the Knights they have their own unique instance IDs they will all have the same object index so they are all a kind of night so we can go switch object index so depending on what the value of object index is so in the case that it's the king or in the case that it's the night and then you would just keep writing cases for this depending on how many objects you're including so for the king I'm just gonna set it to that color as before but if it's the night I'm gonna change this to blur and of course remember to put your brakes and maybe I'll just prove default as well and I'll just set that as great so nothing should come up a set but if you don't specify it here then it will just be drawn as whatever the default case is so maybe you just want that for generic characters or something all right there we go so we're getting all of the objects drawing correctly all right so we're done for that method now just quickly if you're using the other depth method so that was where we had a depth sorter object that saw a grid of all the instances and their y-values what you do is you would draw the mask just after it had finished looping through the grid of drawing all the players so you don't actually need to set up obj silhouette we already have the depth solar object for that so you can just pop all that code into the drawer event there then in the depths holders draw end you would put all of the blend modes silhouette drawing stuff so you could also just use a parent here to get all the objects whose silhouettes you want to draw and then to keep the depth system working still you would just make our parent objects itself a child of the depth object so we're getting a little bit more of a complicated inheritance there all right so that's about it so the topic of this video was actually chosen by a vert on patreon so thanks to everyone who voted I thought this was a really interesting topic and of course I'd also like to give a special shout out to 3d monkey busy la grave max Molinaro and booth alien for their support so that's it for now I hope you guys are all well and I'll see you next time
Info
Channel: FriendlyCosmonaut
Views: 27,912
Rating: undefined out of 5
Keywords: blend modes, blend modes gamemaker, silhouettes gamemaker, silhouettes tutorial gamemaker, blend modes tutorial gamemaker, blending gamemaker, alpha masks gamemaker, alpha masks, blend modes gms2, silhouettes gms2, object silhouetets gms2, gamemaker tutorial, gamemaker studio 2 tutorial, gamemaker studio 2, gms2, gamemaker, friendly cosmonaut, friendly cosmonaut tutorial
Id: AhUDFm7Xo1M
Channel Id: undefined
Length: 31min 51sec (1911 seconds)
Published: Thu Nov 02 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.