How I Deal with Shaders in OpenGL

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey little guys my name is the churner and welcome back to my opengl series mixing it up a little bit with the set I mean last one you you guys were certainly noticing that that I was just I waved my hands around a lot I was coming pretty close to hitting that cactus occasionally and that was just I don't want to lose a hand so we're basically mixing it up with basically Cheney I thought I make a subtle kind of change just to get rid of that whole risk of losing a hand I didn't want to overreact or anything like that so I changed the set slightly kind of got rid of cactus it's still in this room but it's all the way over there anyway hope you guys like this new kind of format it's gonna be a lot more casual because I am not a big fan of being professional quite do it to be quite frank with you guys and hopefully this is just gonna be gonna be a little bit a little bit a little bit easier for you guys to watch and listen to as well without kind of me going through everything like a robot and just quickly kind of end up having to spend like an hour or two editing every single video so anyway welcome back to my opengl series last time we talked about shader stuff and in fact the last two episodes we've been kind of talking about shader stuff specifically we talked about what shadows were and we actually had a go at writing a very simple vertex and fragment shader the basically just made our triangle read if you guys haven't seen that episode yeah definitely click up there because you need to watch that in order to get this video because what this video is going to is going to be about is just basically continuing on with that and more specifically I'm going to show you how I like to deal with traitors because kind of what we've been doing right now with the code is basically I mean if we look at the code that we had last time we have this function where we compile a shader and then we kind of created and all of that but we still have to basically take it and well the biggest problem here right now for us is that we still need to take it in kind of as strings that's a bit of an issue because well first of all looking at these strings you can see we have to add new line characters and quotes everywhere it's just not very like comfortable for us to write shaders at this point in it it's pretty easy to just miss a new line or something like that and end up with some kind of bug and I don't want to really do that so we're going to fix that up so that we can actually take our shaders in from a file and specifically what I see a lot of people doing which is completely reasonable because OpenGL does kind of enforce it to a degree is that what people will actually do is create two different files one for the vertex shader and one for the fragment shader I'm really not a fan of that to be honest I mean having two different files of Y I mean in some cases it can be useful to divide shaders up for example you might have a vertex shader which just takes in like a certain amount of parameters set amount of inputs and just outputs a position and that's it'll provide some kind of data to the fragment shader and it might be a really simple vertex shader which you could pair up with three different fragment shaders for example and in that case you might argue well okay you know I'm loading this file I don't want to necessarily tie the two shaders together like the vertex and the fragment shader together don't necessarily want to do that's one argument but we've got us like we'll deal with that as well in a minute here but the big thing is that I don't like having to it like why I have to I have two different files right there's no actual reason for that it's actually a little bit annoying you have to make two different files you have to read in two different files when you're editing them you have to like switch between the two I have them open side by side it's just not very comfortable and I'm all about comfort like clearly I'm sitting on a couch here instead of a chair and a table so what I like to do is combine the two shaders into one file right just have one file with a vertex and a fragment shader and of course in the future if you want to use one vertex shader with a bunch of fragment shaders you can still do that you can still because obviously when we give the shaders to opengl at the end they still need to have that clear division right we can't just simply give opengl one like one string of source code and then it can deal with it it still needs to kind of know it still needs to kind of have that distinction between this is my vertex shader source code and this is my fragment shader source code and we're still gonna provide it with that it's just on outside basically as the users the programmers the developer writing this kind of code we're going to write it all in one file and I'll show you how we divide it into two shaders in a minute this is very much like DirectX you might you might actually kind of throughout this series you'll probably see me reference direct3d 11 specifically quite a lot with how I actually organize my OpenGL code because when you deal with you'll be using multiple api's multiple graphics API is most likely give us a serious engine and you kind of will probably if your engine supports direct3d or even if it doesn't you'll probably find yourself making OpenGL behave more like DirectX because DirectX is just a better API anyway let's get into some code and I'll show you how all this is going to work so the first thing we're actually going to do is just create a file which contains these two shaders so that we know how we're actually going to deal with them so over here in my client source directory I'm actually going to right click on OpenGL hit add and then new folder we're gonna call this rest which stands for resources and then under that res folder I'm actually going to create another folder called shaders and this is specifically going to be for shaders well we will have other resources like textures and stuff like that in the future so I just want to keep all of this really nice and tidy we'll right-click on shaders hit add new item and then here I'm just going to add a file now doesn't matter what you click here because we're kind of gonna change the extension anyway we're just going to call this shader dot shader or specifically we might rename this to something like well I don't know it just makes a it makes a triangle red we're just gonna call it basic shader because this is just going to be like our basic shader that we deal with I'm gonna hit add and now we have a shader you can see that it's not showing up as like the C++ icon which is very important we don't want to accidentally compile this as C++ code because of course here won't compile let's go back to application or cpp I'm going to copy this entire kind of block of code and I want to paste it into this file now we need to clean this up a little bit specifically I'm going to get rid of this string of course from both of these here and then to actually clean this up we could go through this kind of line by line it's gonna be a bit hard so I'll show you guys a bit of a trick if you hit ctrl H that will bring up the Find and Replace dialog which you can see over here we're going to grab quotes and replace them with nothing if you hit alt a or I think there's a replace all button here okay we'll get rid of all that and then finally want to get rid of through new lines as well so I'll also replace backslash and with nothing okay done and there we go you can see how much easier that was and kind of just going through this code and cleaning everything up manually okay fantastic we've got this kind of hard to tell the distinction there between a vertex and a fragment shader so what I like to do you just come up here top and I'm gonna hit hash shader and then vertex okay and then I'm going to copy that and just above the fragment shader call this fragment so when we have all of our different shaders we might have other shader types like tessellation shaders or something like that geometry shaders that kind of stuff we can also probably add a section for that but for now you can see that I've clearly kind of divided this into my fragment shader and my vertex shader don't worry too much about the syntax highlighting here because we are we have actually specify the dull shader exception Visual Studio is probably go to try and highlight this as if it was a cello sounds like a direct s kind of shader but anyway that's they're still kind of sort of helpful for us because it highlights some things like the numbers and it kind of makes that easier to see but you can see how this is kind of my strategy for laying out chatters it's very easy you can see what's going on all at once you don't need to flip between two different files and it's just yeah it's just really nice and easy and and clean and organized so let's go back to our application I'm gonna get rid of this entire block here now now to kind of understand what's going on here we have our create shader function which takes in the two strings of source code we still need to provide it with two different strengths of source code so now really our plan is just to take this file and divide it up into two blocks of strings right into two strings our fragment shader source code and our vertex shader source code let's go back to application and do that I'm gonna scroll up here our up here to the very top more to try this function at the top why not static will make it void for now and we'll call this pause shader and then I'm going to just make this take in a Const sed string and this will be a our file might call this file path and the way that we're actually gonna read this in is of course first of all we need to open a file and I'm going to do this in a bit of like a C++ modern c++ way not necessarily the way that I would personally read files in a game engine because C++ tends to be a little bit slower than the C kind of file API but because this series is obviously just about OpenGL I want to kind of write car that's a lot easier to read and a lot safer and all that so I'm just going to basically include something called F stream which says the file stream and then over here I'm going to write s/pdif stream we'll just call it stream input file stream and then I'll kind of give it that file path that's the the actual file that we're trying to open yet that already opens the file so now what we need to do is actually go through that file line-by-line and just check to see hey are we specifying a certain shade of time because we've kind of added our own syntax right we've got this hash shader vertex thing you know which basically says hey this is a new shader section and this is the type of the shader that it is so we need to kind of read in that and we're going to go through the file line-by-line and the way we'll do that is we'll actually do while stream yeah we'll use a function called get lines so well get line stream and then we'll make a string here called line which will contain our actual line while that doesn't equal zero basically now get loan is a function that actually is inside the string header so we need to include string so while get line is still kind of valid which means there are still more lines for us to read inside the file we're going to just basically check to see line or find if that actual line contains our shader on a custom syntax token here and if that doesn't equal STD string and pause which is basically an invalid string position because fine will return us the actual string position you can see it returns a size T it doesn't return a boolean or anything like that with whether or not it actually found our string it actually just returns us the position of it so if it's end positive means it doesn't it hasn't found it so if it has found shader on that line we need to basically find which type of shader it is and again I'm just gonna use line defines if it if it's gonna be vertex if it finds vertex then we're going to basically have to set the kind of mode to vertex which we'll do in a minute and otherwise though if it finds fragments so if that doesn't equal STD string and pause then we're going to set them are true fragments okay so that's kind of how this is gonna work we're just going to go through it line by line and we're going to keep adding vertex well if this if the type is set to vertex we're going to keep adding these lines basically to our vertex shader string if it's fragment were going to add them to the fragment shader string pretty simple so now we actually need to add the strings that we're reading out these lines that we're into some kind of buffer where we can just pile on line by line what the vertex chatter the fragment shader is so to do that I'm going to use something called string stream so we'll have to include that and that'll be on the include s stream if we scroll down here I'm just going to make two different string streams so we'll call this s s and I'm actually just gonna use a kind of stack allocated or right here to have two of them one of them is going to be for the vertex chatter of course one of them is going to be for the fragment shader and the idea is we we need to have some kind of mode as well so are we currently reading in a vertex shader or a fragment shader but to do that I'm just gonna create an enum class here called shader type and then we're gonna have nine which is negative one then we're going to have a vertex of course which is zero and fragment which is one I'm being very explicit with these numbers and I'll tell you why in a minute we're also going to store the current shader type that we're reading in so we'll set this equal to none by default okay cool so if we find vertex if we find shader vertex on a line we need to set the mode or the type to actually be shared a type of vertex and then of course for fragment we can set it equal to fragment I'm kind of setting this up loosely I could be a little bit cleaner with my code and actually have some more functions and stuff like that to work out what the type is from string but again it's stoical this is a really simple function so once i've done that if if i kind of if we see hash shader on a line we know that when you just had a type otherwise if it's any other kind of line of code then we actually need to add it to either the vertex or the fragment shader source code and the way we do that is to this string stream let me just arrow to this extra space to this string stream I'm going to basically push the line into a non internal which one to push too and that's why we've got the trader type so I'm going to grab the type and just cast it to an end and use it as an index into this array we know that the array contains two elements and we know they're basically the first element in that array is going to be vertex and the second one is going to be fragment so I'm kind of using arrays here in a little bit of a clever way to actually you know automate this little bit more so that I don't have to have a branch where I basically say if the type is you know vertex add it to the vertex trick stream if the type is fragment add it to the fragment string stream I can kind of just use the type as an index into the array which is just gonna be a little bit better basically so over here I'm going to basically add lime into that strength stream followed by a new line character just like that and that's pretty much it I mean if you look at this code this should divide our shadow into two different types and add them to the appropriate string string so finally at the end here I need to actually return my code now we have a little bit of an issue because we are trying to return two strings and of course you can only return one kind of you can return one variable in C++ so how do we return two variables now we could use something called a tuple or a pair I actually have a lot of feelings about that actually I might make a simple splice video this week maybe that actually deals with with this kind of multiple return type thing specifically I think I will actually that's probably a good idea I don't like using that stuff and I'll explain why in the syphillis video I don't want to bore you guys here but what I would do if I need to can return multiple types here is I would actually make a struct called shader I don't know shader sources or something like that we might actually just call this shader program sauce and this is actually going to contain our will call this vertex sauce I kind of like to capitalize a bit I'm kind of treating this almost like a c-sharp property that's why I'm capitalizing this because there are just public fields so we're taking vertex sauce and fragment sauce okay cool very basic struct and I'm going to just return that struct and then at the end here of my function was I have the - once I've built up and I've read all the source code from that file I'm just going to return basically a struct that this structure I so I'm gonna set the vertex source to be SS 0 dot s TR and then SS 1 STR ok which gives us the string back from the string stream and that's all we need to do right now so this code should set us up with the actual share the source code for both the vertex and the fragment shader awesome so now let's scroll down and actually test this out so the first thing I'll do is I'll kind of we might just get rid of our shader for now just by commenting it out I just really want to see if my function works first to be honest so we'll go shader program sauce sauce or something like that equals positive and then we'll take in our file path which is just going to be res slash shaders slash basic shader which is our file so res slash shaders slash basic shader now this is kind of the first instance of us actually reading a file in C++ in the series on my channel so basically what you need to know about this is that if you specify a relative path like that so not something that is an absolute path you know like C uses whatever starting from the C Drive was whatever since we're specifying a relative path relative paths are always from the working directory now if you run the executable outside a bit of studio the default working directory is just going to be the directory that contains that executable so everything will be relative to that but if we're running this through the visual studio debugger the working directory is actually set by our Bureau studio debugging kind of properties so if we right click on open on the open shell project hit properties you can see over here we have a tab called debugging right and under here we have a working directory you can see here that is set by default to our project directory so we know that this file is relative to the project directory that is the directory that actually contains our project file which in this case is this directory which is has our VCS proj so you can see it should be relative to this so res slash adders slash basic dog shader and that's exactly what I've written over here now that we've got this let's actually just see our source vertex source and also I'll do the same for fragment source now to divide this in some way just to make it extra clear I'm also going to copy this kind of twice here and write you know vertex like that and fragment so that we can really see the two different shadow types we have and I'm just gonna hit f5 ok I got one more syntax error here when we do jail to lay shattered by the way this code was wrong from the last episode I added a little thing kind of just in Premiere Pro much like in my video editing software I just had a little kind of nard being like this is what it should be it should not be GL delete shad I don't know why I wrote that it should be jailed delete pro Brown okay because shader is actually just one shader type our program is to actually go to delay our programs that's what it should be let's comment that out for now though because we did kind of comment that shadow code let's hit f5 to run this program hopefully we can see our pausing working correctly so if I go to my console you should see that we have vertex and then do actuator and fragment and then the fragment shader so it looks pretty good to me they look like they're out correct shader there's nothing cracks or anything like that looks pretty perfect to me let's go ahead and actually pipe that into our source code or specifically to our shared a compilation function so I'll bring this back and I'll bring back my GL delete program as well and then instead of kind of providing vertex shader and fragment shader now we've got this we can just provide source dot the vertex source and source dot fragment sauce just like that let's hit f5 and you can see that we get a red triangle if I go back to my basic shader file let's go ahead and change it let's make it I don't know let's just make it a nice little blue so I'll make a 0.2 0.3 0.8 and then hit at 5 as you can see we get a nice blue triangle awesome so I hope you guys enjoyed this video we basically just took what we had with shaders made it a little bit better combine it all into one file and now we can crash edits from files which is pretty cool and gonna be way more easier it's gonna be way easier for us to actually do that as we progress on with this series now in the future we will probably abstract all this into a class as the code based kind of keeps drawing found we're not gonna worry about it we're just gonna move on we've covered vertex buffers and shaders the next step that I really want to cover is going to be about index buffers okay because we need a way to actually render our triangle using something called an index buffer and we'll talk about why we want one of those what that actually is and all that in the next video because it's probably not that apparent the need for it probably isn't that apparent with a triangle but as we kind of get more complex valve geometry I mean even if we try and render a square which is pretty complex right it's gonna benefit it's gonna basically be a huge benefit for us to use something called an index buffer anyway I hope you guys enjoy this video if you did you can hit the like button you can help support this series by going over to patreon for such the churner there are some pretty cool rewards I mean I'm not gonna lie there's I would never lie to you guys right first of all this series would be absolutely nothing without my patreon supporters there's no way that I would be sitting here on a couch spending this much time making videos for you guys unless I was getting the support so this is thank you so much for letting me do this first of all but second of all you'll get videos early you'll get access to all the source code kind of episode by episode for this series and really for all of my series and there's this really cool thing where basically if you're a top-tier kind of supporter this is hangout that we do once a month we're basically all the supporters get into one like video chat thing on discord and we just talk about we just hang out for an hour basically just talk about whatever it's a really good time so definitely sign up for that if you're interested in help support series this port is also a really good place to talk about this stuff rather than just leaving a comment below which you could do as well of course I try and respond to all my comments you can also head on over to discord com4 sorry the cherubic home slash discord where there's basically just a community of people like a instant messaging kind of format thing with multiple channels where you can talk about this triangle the opengl seriously plus whatever it is that you want to talk about a lot of people there as well that can help you out with all your problems and of course don't forget to follow me on Twitter and on Instagram the conference at the channel as well just plugging absolutely everything also you can buy the merch at this I'm kidding I don't have that link yet but I'll get back to you with that shortly next time index buffers Cherno out goodbye [Music]
Info
Channel: The Cherno
Views: 131,423
Rating: undefined out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, opengl, shaders, glsl
Id: 2pv0Fbo-7ms
Channel Id: undefined
Length: 21min 14sec (1274 seconds)
Published: Sun Oct 29 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.