Writing a Basic Renderer in OpenGL

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hayward's look guys my name is Ayana and welcome back to my opengl series so today we're gonna be talking all about the renderer and we're gonna be writing our first renderer which is pretty exciting so if I all we have is in our main file we've basically just got a list of well classes that get created and then later get bound and then get drawn and it's just a little kind of a mess and none of this is going through a central pipeline which is really the big issue that we have here it's still perfectly fine for us to do something like this but well instead of us actually telling someone hey I have some data I would like a drawn we're having to do all of that work and that's a problem for a few reasons first of all it's bad because we're doing all the work every time and if we want to render something again well we have to make a draw call for that and we have to go through that kind of pipeline all by ourselves again and again and again which is bad because we're repeating code it's error-prone it's also just annoying all those problems and then later when things get more complicated and we have multiple rendering targets or even something simple like blending we have no kind of central glue that ties everything together and actually keeps everything organized and debuggable and and running smoothly and that's kind of where the renderer comes in the renderer is like the factory where we say here are some parts I want you to make something for me I've literally made that up on the spot but you know what I guess it works so we're gonna stick with that so basically the idea here is fairly simple we have a bunch of data in the form of like a vertex buffer an index buffer a shader whatever and we want to be able to give that to someone and say hey this stuff that I'm giving you I want it to appear in the screen please and that's kind of what the job of a renderer is now of course it gets a lot more complicated matter and we can tell the render a lot of things but to keep it simple our goal for today is really just to move away the last remaining OpenGL call that we actually have inside our main file if we take a look at our code you can see that pretty much all of this is abstract away I mean we have like the vertex array vertex buffer we've got index buffer we've got shader we've got all this stuff that is just complete we abstracted away into our custom classes however well we I guess we have to open jail calls we've got beat jail clear which should be handled by the by the renderer and then we've also got destroy elements so this is basically a draw this is something called a draw call as we've discussed previously it's where we actually tell OpenGL I want you to take what it was bound and just draw this on the screen somehow and that's what GL draw elements does that should be something that is taken care of by the renderer as is that clear thing but the clear things kind of a minor thing which we'll probably get into later anyway how are we gonna do that well we're gonna start by making a render of class and then inside that render of class we're going to be writing a draw function which basically takes in a bunch of arguments so the data that actually needs to draw something and then draws it on the screen and from that approach even though that might seem like a really simple thing we can grow that into into something extremely complex and extremely powerful so let's get right into the code and check that out so the first thing I'm going to do is right click on source here get add new item gonna make a header file called renderer H and apparently I've already got the render order H and recipe B yep that's why we put all of our opengl stuff so that's great so inside our renderer by H I'm just gonna make some room here and actually make a class called renderer now whether this class should be static or there should be a singleton or anything like that that's it's up for debate I mean some people like to actually make this class a singleton and make sure there's only a single instance of that some people don't like to do that because maybe they might want to have multiple instances of the renderer that's perfectly okay it's not me the approach is really wrong it's just how you want to do it we're just gonna make this not kind I'm not gonna make every method here static or anything like that we're just gonna treat it as if we can have multiple instances of this if we so choose to that might be something you might want to do if you have multiple layers or something like that inside your actual like graphics application but there's no reason for us to kind of go every board and just start making everything static here so I'm just gonna treat this as if it was a normal class so our first goal is really just to make a function called draw which takes in a bunch of stuff so let's think about what we actually need to draw something in OpenGL well we need a vertex array we need an index buffer and we need a shader that's we know so far right the vertex array actually has the vertex buffer bound to it so we don't need to worry about vertex buffers at all but we do need to have that index buffer the vertex array of course as I mentioned and also a valid shader so those three things are really all we need now the index buffer has the index count and if we kind of pass in an index buffer into this draw function we can kind of assume that we want to draw that entire index buffer because if we wanted to draw like a partial index buffer would probably pass in an index buffer which just had a partial set of indices so over here in draw I'm going to write vertex array I'm going to pass all these by reference by Const reference so vertex ravy a Const index buffer IB and then Const shader reference shader cool so there we go and we can make that Const as well since we won't be modifying anything into the renderer I'm going to include all of our classes here vertex array index buffer and shader and that's looking pretty good to me so in render or CPP I'm going to write that function so void R and draw draw it's my little sister wedding for me remark as Const as well and now we can actually move out draw call here so let's go back to application and see what it is we actually need to move so we had this vertex array binding this index array binding and this shader binding now what's interesting here is we're actually setting a uniform so how is that gonna work with our draw function well we'll come back to that later but for now let's just travel of this code I'm going to go in to render or dot CPP let me just play these other files gonna paste that in here like that don't worry about the set uniform so we have our shader binding our vertex array binding and our index buffer binding and then finally back in application we'll steal that GL draw elements just like that and so we'll do GL call GL draw elements triangles now instead of six we're gonna have index buffer don't get count unsigned int I think we assumed that this is always going to be an unsigned int as you can see here with the data so we will just basically hide code this to be unsigned int but in the case of you may be having unsigned short as your index type you might want to actually pull that out of the index buffer or where or wherever you're storing that and finally we're drawing everything as triangles for now we will definitely get into kind of different modes of rendering in the future but for now it's just going to be triangles because that's what we're doing okay cool so everything looks pretty good in our code you can see that compiles just fine we're not going to bother unbinding any of this in a more traditional I kiss whole concept of unbinding I really should make a video dedicated about that about this but like unbinding stuff in opengl not strictly necessary it is useful for debugging I will say that but and it might reduce some bugs maybe but ultimately speaking on binding stuff in OpenGL is just a waste of performance you really need to do that because before we draw the next thing we'll be binding all this stuff anyway so there's no real point more kind of complex systems might have bite like unbinding in debug mode and then in release mode the unbind calls just do nothing that's one option and we might implement something like that if we were actually making a game engine but for now we're just gonna write our code like this and it would be fine you could probably argue that it would be wiser for me to actually just put on binding code here because again we are strictly kind of talking about OpenGL here we're not really writing a game engine so we probably don't really care about performance or anything like that I do like to keep my card kind of lean though and just having three more lines to I'm buying all this stuff needlessly like I just don't want to clutter the code up too much so that's the reason why I'm not doing that here okay so back in application we still have this uniform issue there's nothing really stopping us from just doing this like we can still do this and then we don't need to bind any of that and then finally for the renderer what I'm gonna do here is just create a new instance of this renderer class just like this render a renderer and then over here we're just going to call render a dog crawl we're gonna pass in our vertex array when I pass in our index buffer and we're gonna pass in our shader just like that and so we're basically telling our renderer here hey I have a vertex ran an index buffer and a shader please draw that onto the screen and that's kind of what our function does so if we come over here and we actually run this application of ours we're gonna get a whole bunch of errors here because something's not found it's probably because we're actually including round in here and then we're all best being included into renderer as well so we kind of got a cyclical include thing going on here so let me go ahead and check that vertex rankness that has Buffalo because we do need that that is a reference though so we could eliminate that let's see if I think that I've got a layout yeah is the reason this happens is because the Vedic buffer layer calls assert I think that's the only reason we need renderer here isn't it well actually we also include up in jail okay sure so to kind of solve this what we'll do is we will actually go to vertex array dot H I'm not going to include vertex buffer layout in here I'm actually going to be forward to clarify this type and class vertex buffer layout like that and then in the CPP file I'm going to include other things buffer layout just like that so that way we don't actually include vertex buffer layout you hear the problem really is that vertex buffer layout includes renderer and then we include vertex array which includes vertex buffer layout inside renderer beige so it's like we're including renderer in vertex array and we're including vertex array in renderer and it's kind of it's getting into like an infinite loop of inclusion well I'll have a C++ video about that available at some point in my life click there if it's there so if we try and compile our code once again we should be okay all right so back in application of CPP we also have to include that vertex buffer layout so I'll include that like that and compile our code all right there we go succeeds let's go ahead and launch this application see if we get the same thing rendering and you can see that we have the same result great few more things that we can actually do to clean this up is we have this GL clear here I don't really want to do that here of course so inside render o2h I'm just gonna write clear and then inside the CPP file I'm going to implement that function clear and we'll just basically copy and paste what we have inside application which is color buffer bit just like that and we'll just call render or clear like that and to be a little bit more correct what I'm going to do is this function as Const because of course it doesn't do anything doesn't get it over constrained or anything like that and if we go back to application let's just see what we've done so essentially what we've done is we've gotten rid of every single GL call I think that we have in this entire file yep and so what we've done is that whole rendering situation that we've had we've basically changed we've made some kind of drawing functions so that we can just call draw with the appropriate data and then clear if we actually want to clear our screen we do still have this kind of issue here with the shaders where we actually still have to kind of bind the shader so that we can set the uniform to whatever we want every frame I not a big fan of leaving that Cody here the only real way to solve that there is because we should like the way that you would solve that is by using materials instead of shaders so what we have in our draw function and render robot draw we're taking in a vertex array and index buffer and a shader that's a bit weird in a more traditional setup we'd be taking in like you know vertex array whatever index buffer that's all fine but then we'd be taking in a material instead of an actual shader and what a material is is basically a shader plus a set of data so a shader plus all of its uniforms whether that be kind of render a specific uniforms or kind of per object uniforms like for example this rectangles color would be like a kind of per object uniform that we actually have and that would be stored inside the material alongside the shader and so that way when we pass in the material to the renderer the renderer will basically bind the material meaning that it would bind the shader and set up all the uniforms that it needs to and then call the draw function for our vertex array our end index buffer and all of that kind of stuff so that's how that's how it should work we don't have material 0 or anything like that so for now we have to actually if we want to modify a uniform for a shader we have to do that ourselves manually a little bit annoying we might get into materials in the future we definitely will in the game enter the series not sure about opengl series but we probably will have to though this is gonna get pretty complicated pretty soon so for all of you people who are thinking this is getting there's a bit simple so far it's gonna escalate pretty quickly anyway that's pretty much the renderer we now have a class that we can keep adding to when we actually need to render more and more things I can't wait to get into the more complicated stuff next time we're going to talk about textures and how we can render text and load textures and all of that stuff and open jail and after that I think what were we going to move on to things like 3d models or cool I don't know there's so much so much to do I think 3d models is probably a good idea we probably want to move on to some kind of debugging interface as well and like a GUI system so that we can play around with that once we have 3d models we can move on to lighting and cool stuff like that we also need to do text rendering at some point just gonna be a nightmare of course I hate doing a text rendering I might actually write a library specifically to make text rendering easier for this series because it's really quite annoying and I don't really want to deal with that but then on the other hand I need to show you guys how to actually make text rendering work without using libraries so that's going to be fun anyway I hope you guys enjoyed this video if did give me that like button you can also help support this series by going to patreon I'll come for such the chatter huge thank you as always to all of the supporters of all of the videos that I make your on YouTube because they wouldn't be here without those wonderful people next time textures I will see you next time next time next time I'll just say that would have been more often good bye [Music]
Info
Channel: The Cherno
Views: 78,005
Rating: undefined out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, opengl, opengl tutorial, opengl renderer, renderer
Id: jjaTTRFXRAk
Channel Id: undefined
Length: 14min 43sec (883 seconds)
Published: Wed Jan 24 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.