Vertex Buffer Layouts | Game Engine series
The Cherno
·
Intermediate
·7y ago
Key Takeaways
The video covers Vertex Buffer Layouts, a crucial concept in rendering graphics, and demonstrates how to implement them in a game engine using OpenGL and DirectX. The video provides a detailed explanation of how to describe the layout of vertex data in memory, allowing for efficient rendering and manipulation of 3D objects.
Full Transcript
hey what's up guys my name is China welcome back to my game engine series so last time we took a look at renderer API abstraction check out that video if you haven't already we basically just pulled out a bunch of our code into specific classes that were kind of / render API so we're dealing with OpenGL at the moment so we created like an OpenGL vertex buffer and index buffer class that was specific specifically for dealing with those kind of render api like primitives or just things essentially in a way that was kind of abstracted out where when we kind of call it from our application or from our game kind of code or from our render occurred it doesn't care which API is actually used under the hood so definitely check out that video if you haven't already we're gonna kind of continue down that slope today but we're specifically gonna talk about buffer layouts and when I say buffer layouts I mean I'm really talking about vertex buffer layouts okay we touched on this I mean we've touched on this on my channel just in general because of course you can't really render anything without having to deal with vertex buffer layouts we have a video specifically about that in the OpenGL stories or I'll try and link it up there and definitely check that out if you haven't already and in general if you're not familiar with the OpenGL stories I would just take a look at pretty much all of it because that's really gonna help you out with what we're kind of building here at this moment in hazal and also I'm gonna I want to continue that OpenGL stories probably next week when we throughout this kind of next week because it's it's again it's gonna be really important in kind of taking a deeper look at some of these concepts that we're learning here in the game engine series so anyway today we're gonna talk about Baja layout so what does that mean why why do we need them what do they do and how do we write them in a way that is both abstract and works for every render API but also is actually kind of easy for us to use because that's kind of what I'm all about right I want the code that we write on the client side the code that we actually write like inside our game kind of project right or inside our renderer to just be beautiful that's kind of what I go for that's what I aim for right and it's actually getting dark outside because I left this video pretty late today I was just planning and just making sure that I had everything that I wanted to say freak it out because I really like I'm really I really wouldn't want to do this well this specific episode what all video is really come on but you know this specific episode so if it kind of gets dark I'm sorry because it is like the sun's gonna set in half now anyway the point is beautiful code right I think that's really important I think that if the code that you're writing if you design an API and the code that you're writing just looks disgusting or just is hard to do things with or isn't concise enough that's an issue right think about writing documentation or just writing like an English essay or something like that right if you take paragraphs paragraphs and paragraphs to kind describe the same thing and use can't make really like nice kind of flowing sentences that doesn't really sound nice it's not good for the Raiders frayed and it ended just apart from that not just like it's just not nice aside from that it's just not like actually practical isn't doesn't work as well right like the person might have to read your sentence multiple times well they might have to read a whole much more information that they otherwise would have to understand what it is you're trying to say in your English essay right and of course English essay is you're probably going for a high work cow anyway so you might just reiterate stuff over and over again but encourage that's really not the the case usually like you actually are trying to be concise right and just in general you want to use kind of grammar and sentences that both kind of sound nice kind of in your essays writing your English essays back to this but also stuff that actually gets your point across very just concisely and just nicely so that the person can wants to keep reading and that so that the person forms a good visual kind of mental image of what it is you're trying to do and everything is just beautiful and everything just feel solid that's what we want to achieve with all of the api's in this engine right that is what we want to do that's not easy to do right but because we're using a language like C++ it's extremely flexible and it actually means that we can do a lot of what we're trying to do and today specifically with Buffalo's I'm gonna show you how there's probably there's omits many different ways of essentially doing the same thing but I want to do it in a way that actually looks good like we're talking about a buffer layer we should just be able to visualize the code and be like I get everything right I get everything like we don't want some weird like what like weird kind of way of writing code for this Buffalo out where it just doesn't make sense or it just requires us to really think about what it is we're defining no we want it just to be easy we want it to just be really easy because if it is easy and if it is just so nice right and elegant then apart from just looking good and us feeling good about ourselves and also other people dealing with us and being like isn't this great this is so easy apart from that it's also actually going to reduce the bugs in our code why because everything just makes sense and if something is wrong we can intuitively kind of just pick up on that we don't need to just read the documentation be like yeah I guess that's wrong no we can just see the errors right there because it's laid out in such a way where errors are obvious okay that's what we're gonna talk about today we're gonna jump in and we're gonna take a look at just the practical example of what we actually have as well as talk about what it is we're trying to kind of create and I think that that's really important when you kind of talk about any kind of API that you want to design or any kind of complex concept it's what is this actually doing right and with vertex buffer layer specifically it's very simple you know what we're doing is we're actually telling OpenGL this byte array of data what's in it how is it broken down you know how many elements are there how many like what are the elements you know is this a three component vector of floats right or is just three separate floors you know is this a four kind of component color houses specified is just just maybe it's just an unsigned integer you know or maybe it's four separate floats or something like that right it could be just absolutely anything like if it's just a binary blob of data which is what alpha takes buffer actually takes in and uploads into the GPU we need some way to actually describe the layout of that data which again means you know the first four bytes might be a float the second four bytes might be another floor and then the third four bytes might be another float that's three floats in a row that's our three component vector that describes our vertex position stuff like that that's what we're trying to achieve let's try and do it in an elegant way let's jump in take a look practical example and we'll see how we go okay so last time I had this sum triangle today we're gonna basically aim to achieve the same thing but a lot more elegantly and specifically we're also gonna maybe jam in some other vertex attributes for fun just to kind of see how they work maybe we'll John well maybe we'll just throw in a vertex color or something like that let's just close this sir currently we are actually specifying a buffalo out right if we weren't we wouldn't see anything on the screen and that's this right here okay these two lines of code what is this saying is inside our vertex buffer this one that we're creating we have at index zero three floats right they're not normalized the stride between each vertex is that size so three floats 12 bytes and the offset of this particular element is nothing right now I I don't really want to discuss how this works too much because I do have an OpenGL video about it and as I said the Sun is setting and I have like other stuff to do with my life and I don't want to sit here for two hours just reiterating wasting your time just describing everything that I already have already so definitely check out that video but know that I don't know like that that's this is like it might be any quite simple at all to understand so if you don't understand this particular line of code make sure you check out that video because I'm not gonna really talk about it too much I think it is in this episode so a few things that I actually want to point out what this particular line of code is I guess the linkages of it so what it's referring to what it's linked to how what a corresponds to right so vete Satrapi's pacifically are actually stored in the vertex array not the vertex buffer now they describe data in a vertex buffer however a vertex array is kind of the parent type if you will um and a vertex array can contain multiple buffers right we can actually interleave our buffers and have you know just in this one vertice like right in this one what kind of vertices array we could just add you know we want a vertex color or vertex normal or something we can actually just add it like just BAM like that you know and that way you know everything every single vertex that we have is kind of going to contain in this case maybe both a position and a normal right or the other thing we could do is kind of just not interleave it so not have any of this right but then just make another kind of array here right another float array which has had vertex normals and then we can actually upload that into a separate vertex buffer we can create another vertex buffer just for the normals and then another one for the colors and another one for you get that you get the point right so because of that opengl doesn't really care how you do that you can interleave all your data and have one big fat vertex buffer which is pretty much what you want like 99% of the case by the way or you can split up your vertex buffers into separate kind of actual vertex buffers and separate buffers of memory and then upload them individually it doesn't matter because this stays the same right it's just you having to bind different vertex buffers and certain times when you actually describe your vertex array and will kind of maybe talk about that in the next episode because next episode we're going to talk about vertex arrays and actually abstracting them out into a class which means this kind of stuff anyway what I want you to know is that this particular binding this kind of I'm enabling a vertex a trip array and specifying look at the layout of my buffer that is stored in a vertex array if I bind another vertex buffer or something like if I don't need to re define this all I need to do is this stuff get this state gets saved into my vertex array if I want to recall it for rendering I just simply bind my vertex array again and it's done okay the second piece of information is that this is directly tied to our shader right if we look at a shader like we've specified one here look at this layout location equals zero back three a position right and that that's this piece of data written by a vector right three floats that's what a vector E is right non-normalized three times the size of floats or 12 bytes again the size of this type index 0 layout equals 0 rather location equals 0 right that is what that's tied in with if we suddenly want to take in a normal right we put that in location 1 let's just go with the color in this case because it's a different type a Veck 4 and this will be our kind of vertex color right what do we do we duplicate this right we have it at index 1 and by the way we also to enable it so enabling index one we have four floats and then the rest is kind of the same except this changes because that is oh and this is wrong by the way sorry this isn't decisive I should visit the stride so it's actually the size of each vertex not the size of each element right so it's kind of the size between each vertex in the array so if you if we have three vertices it's the size of each full vertex which would be the size of both the position and the color in this case which would actually be seven times size of float and that would be the same for both of them so this this changes to this right and then the offset is the offset of this particular element right inside the buffer so obviously this is back a back 3 that's 12 bytes three floats right 12 bytes so the offset of this is going to be 12 so it's simply 12 right and we just need to cast it to a positive ROI pointer okay okay so that's kind of what we end up with but you can see that it's directly tied to my shader that's the kind of the point that I want to drive home right here is it's tied to my shader okay and it's actually not really tied to shaders in OpenGL in the sense that there's no validation performed between that indirect tax it is absolutely performed right you cannot describe a vertex buffer until you've bound a shader okay so it's actually a bit different than how OpenGL works anyway that's kind of my point so because it's so heavily tied with my shader what I actually want to kind of do for my buffer layout is I basically just want to be able to set a buffer layout on to a vertex buffer right now I did just say that they're tied to vertex arrays however but a layout describes a vertex like a layout is specific to a vertex buffer it describes a layout of an actual buffer of memory so whilst OpenGL kind of stores the state in vertex array in DirectX there specifically on vertex buffers because there's no such thing as a vertex array indirect tax but apart from that it just makes it just makes more sense to us so it doesn't to us it doesn't really matter that they actually stored inside vertex arrays because we can still kind of work around that and store them wherever we like it's just that in the end under the hood will make that differentiation when we need to but the kind of surface level API should still set it onto the vertex buffer now how do I describe this layout well there's a lot of ways that you could do it but I'm not gonna waste your time and show you all the bad ways of doing it I'll just show you a nice way of doing it which is again what I'm talking about where we want to kind of have an elegant visual representation of this wouldn't it be cool if when we kind of described this layout because somehow literally just have this kind of code like right here and just be like you know our layout equals kind of maybe put this in brackets our layout equals like that all right now let me just I just realized I've got white spaces on which mean don't need wouldn't it be nice if we could just do something like that well that's kind of what we're gonna do we're gonna actually literally make it so that we can see a visual representation of our layout so our goal is to have something that's maybe called a buffer layer class right which is going to look like this and then maybe what we'll have is each element is going to be kind of defined like this okay and we're gonna achieve this by just using an initializer list and probably destroying these elements in a vector now we're not going to use it back three or back four there's a GLM types in this case one here they're obviously open G and the GLSL types inside the OpenGL shading language but what we're actually gonna do is come up with some kind of enum that describes this datatype so we're essentially gonna probably create like an enum class called like shaded datatype which will be kind of our cross api cross-platform way of just kind of defining each data type that is inside a shader so like in fact three back for you know floor it into that kind of stuff so we'll probably use something called like float three to describe a three component thing you know Veck three is cool and all but I kind of like float three that's kind of the hlsl style way of doing things and we are probably going to eventually switch to HLSL shaders you can use vector e if you want because that's kind of tied to our math library and like at the moment but I'm just gonna use flow three to describe a three-component flow okay because it makes sense and then we'll probably give it a name now you don't really need to give it a name it's useful to give it a name like indirect text we will have to supply some kind of string as you'll find out in the future but it's just nice to kind of give it a name just so that you know what this actually is and if you want you can actually call it the same thing which is what I'm kind of doing in this case so it might have that let's just get rid of this whole color thing I mean essentially you did the same thing for call it though you just make FX like a float for and do all that and that will that's gonna look really nice right we'll get her to color here and we'll get rid of this stuff changes back to three floats and we'll try and just ran it that triangle to begin with okay so this is my layout um and I'll set my my layout and that's kind of it that's actually how I wanted to find my layout and you can see that it becomes really nice because suddenly if I have a layout that's full of like stuff that I need you know like you know we might have like texture coordinates or something and you know you have something like text cord and maybe normals and then you might have like color or anything it's just so easy to see the layout of this buffer right it's amazing that's all I need to do and obviously if I want to like have an array of things like you know if I wanted to be normalized or not I can maybe add a third parameter but this is kind of what we're going for so let's take a look at the magic to make this happen so I'm going to define all this code inside the buffer file here because it is to do with buffer layouts and all that stuff so I'm gonna make a class called buffer layout okay and a buffer layer is essentially going to contain a vector of buffer elements okay and these are going to be called elements I'm immediately just going to give it a get up to return that because we we are going to need that so get elements on stand that will return elements again and then these buffer elements are going to be another class actually I'll pull this a struct buffer elements and this is going to contain all of the stuff that we need to actually specify okay so the first thing it will contain is a name so a silly-string name I mean in no particular order we need the offset we need the size we need what else do we need the counts I guess because we can have like multiple of these I'm not really sure if we need that to be honest because I'm just thinking about it like we definitely need that for uniforms if we have like an array but we don't generally I think if we just have that shaded data type as I said which is going to be the type of data will kind of know the count of how many elements we have anyway and we can always create helper functions to kind of compare between the two right so we'll maybe have the name the type the size and in the offset and I think that should be enough right now the way that we constructed this over here was just by writing the type first right and then the actual name so we can actually do that here as well we just need to create a constructor that allows that kind of construction all right so I'll write cons to a CD string name and then shade a datatype type all right and then over here we will set everything so name will set to name the type we all set to type size will set to zero to be our size we can calculate pretty much immediately I think because that's just the size of the type so we probably don't need to set that although we can here as a default and then offset we'll set a zero offset we can really only calculate once we have context so offset is going to be the offset of this element in our inside our layout so obviously to calculate the offset we need to be aware of all the elements in there because if this is like the second element its offset is gonna be the size of the first element right because that's how that's how much into the buffer it is so we currently calculate that just yet but we can't calculate the size so we might do that anyway in um class dadada type right and we can make this like I mean if you wanted to you could make this like you and a tea or something just tiny because it doesn't really need to be very big literally it doesn't really matter you know I'm not I'm not one to just like this isn't gonna be serialized this is not like maybe if it comes down to us trying to really pack this daughter entirely we can do that in the future but you don't need to in the like the time being so I'll have none will have floor it would have flowed to will have flowed three will have flirt four we'll have you spoken to like mat three mat for this is not just going to describe attributes by the way it can describe everything will have int will have in 2 into 3 into 4 yeah it's probably good enough for my topic struct or something for like uniforms well we'll cross that bridge when we get there okay that looks pretty good to me there's a good like basic type you can have boolean's as well maybe I was right pool at the end here okay that's pretty pretty good right so that describes all of our types now two things I'm concerned about as a size and also the [Music] the offset which we can calculate in a minute so what we can do is create some kind of function obviously the converts between this kind of shader data type and an actual size so what we can do is just create a static you into 32t shader dot it you know we just do share data type size I guess get advantage size share the data type type and then this will simply my letter e seems a pattern just like contacted without pressing hard this is just gonna be a switch the same this is just going to be a switch statement that goes between the basically two switches on every single type that we have associated data type you know in the port and in this case you know it just kind of I don't know two three four four now this just returns the size of it so a float is four bytes is no return that much and will also kind of do the same for pretty much everything else so a float two three four mat three mat for I'm gonna try and be comprehensive usually I like adding these things as like your just because this just takes in a little is just takes a bunch of time and makes the video more complicated but I'll do it at least for this for now because it shouldn't take too much time alright I think that's it so all of these right you just align these a bit okay so float two is gonna be four times two four three is gonna be times three times four right a matte three is gonna be times three times three right because the 3x3 matrix a float for is gonna be the same but four by four matrix and it's gonna be four you know in it it's gonna be and in two is gonna be that that you guys gonna get the point and then it bulls probably I'm not sure I might be one by my before we'll see about that but we'll just leave it as one for now and obviously we'll return 0 if we have nothing and also we should definitely set here pour assert false unknown shader unknown shared a data type okay and we don't need to print out the type if it's a week that'll just break here and we can just inspect it using the debugger ourselves okay there we go that's everything I hopefully I didn't make any mistakes I was kind of high school here but now we can actually see what the type of each piece of data is right now this is in buffer remember when we actually move this into shaders and have more stuff we'll deal with that kind of then okay cool right so what we want to do now is actually calculate that size right so it right here in size we can already just call shader data type size and then pass in the type all right and then we have that beautiful now and this is just buffer element of course not buffer when we create a buffer layer right what we want to be able to do is take in and initialize a list right so this kind of thing now this this is interesting because ultimately you could just say I can take you and I just want to take in like a constant vector right because if you take in a vector and it doesn't matter if it's constant reference or whatever that let it ease annoying me it doesn't matter if it's Const reference or whatever but if you take that in like this kind of should work it doesn't because there's two implicit costs happening but just say that you know you know if we just take this type technically speaking and we change that and make it this type right that will actually work right so you you can actually construct something like this now it's not working this yeah we've kind of put this the wrong way around I don't know how I did that so easily as well so we put the type first and then the name in actual list here so if we get rid of this and go back it should work again there we go see and then what you can do is actually decide that I want to make a layout layout from my layout right currently pull this out but whatever you get the point right but unfortunately I can't just do this okay because it there's one implicit cost to convert a vector like an initializer list into a vector and another implicit cars to convert the vector into a buffer layer because buffalo has a constructor that takes in vector so we can't actually do that what we can do however is actually just take in and initialize a list here right and then if we actually do that right then you know you can do like your constants here if we do that you can see this works okay beautiful so now we basically got exactly what we wanted which is pretty cool and then from this right how do we convert into a vector well as I said there's obviously a constructor for vector that takes in an initializer list so we literally just do I guess I'll do maybe layout or elements we'll call it just like that okay there we go so now we can construct one of these from here and all of the data that we've actually said is inside this vector which is very cool now once we have that vector we actually need to calculate the offsets so I'll say calculate offsets and there's one more piece of this one more piece of information that we need and that is the stride and the stride is the size of each vertex each complete vertex so all of the attributes the size of all of those together that's only known after we had the whole list same as the offset right so we can calculate that once we have the whole list we can't do that inside buffer element but we can do that here so we'll make au and 32t called M stride which will set a zero by default calculate offsets and stride will be a beautiful function that we have here that's going to be private private so void calculate offsets and stride that's going to go through all the lists all the elements that we have here so I guess we'll just say for order reference elements in this letter is really annoying me in elements right and what we're gonna do is we're gonna maintain an offset here and then I guess we can set m stride its to 0 equal to 0 here just in case we recalculate or something this is what we're gonna do we're just gonna say that the element offset right is gonna be our offset then we're going to say offset plus equals element dot size right and then we're also gonna say M stride plus equals element size okay so that she said all the offsets and all the and and also calculate the stride for our entire buff allowed that's I think that's about it to be honest what haven't we done I think everything's well I don't know we should just check it out and see if it works so we haven't automatic office that layout we'll do that in a second I'll just put a breakpoint here I launched this and see if that layout is everything that we want it to be and more potentially I should probably add something else that it'll out because it's just you know I mean this is gonna be pretty boring I think we just have one thing in in there but if we take a look so our layout has one element that's right of 12 which is correct and the position has an offset of zero size of 12 okay looks good let's just to test it a bit more I'm gonna add two more things I'm going to add a foot another foot three and then I'll float for maybe I'll put the foot four in the middle just to make it a bit different so we'll pretend that we have normal in the color we'll see what that looks like okay that okay I was gonna say to compile but that's because we put the comma in the wrong place let's just try again here okay so layouts I struck this write as 40 is that correct so 16 plus 12 plus 12 yeah that's correct 20 24 plus 16 size is 3 and these should have correct offsets offset of 12 and offset of 28 beautiful okay so there we go allow clearly works and that is really cool so now let's try and render something with it what I want to do is go into our buffer class right do a buffer file and just add you know a virtual void set layout all right buffer layouts I'll take that in as a constructor and layout equals 0 and then we'll also have a virtual const buffer layout and get layout so I want to be able to get and set the layout right we'll open up GL vertex buffer or rather GL buffer and inside here these should all be overrides by the way not sure why they're not because I was lazy I guess so now we're gonna have Const override for all of these and these two will get layout so when a still the layout here so we'll have buff allow em lay up and layouts get lay up is just going to return it and thank you Visual Studio for that or in this formatting and then this is just gonna set it right so M layout equals layout make but these yeah that's fine okay done so there we go I was gonna make them in line but there's no point that is done now we should be able to just rock and roll with this now as I mentioned this particular code is get it gets set in the vertex array we'll talk about that next video because we haven't abstracted that just yet so now we'll just do that stuff here and you'll kind of see how it works but in the next episode we'll move it into the appropriate location I could that end the episode here but I'm not going to just cuz I actually want to see this stuff in action and rendering and I did promise you guys vertex colors okay so to make this stuff work what I need to do is iterate through every element in the layout now I could write code such as you know for Const order elements inside layout get elements but I don't want to I just want to write code like this because it just looks better so I'm buff away out what I'm gonna do to make that happen is the same thing that we did inside layout if you remember which is we're actually sorry inside layer stack where I actually provided iterators beginning in so if we copy this code and then go in to buff up the inside buffer layout and get elements I can just provide an iterator here obviously in this case it's gonna be a buffer element instead of a layer and then this is gonna be M elements begin and and and then there we go okay so now we can just do that which just looks nice so we're iterating through every element in the layout and we just want to do this kind of stuff here so we'll keep track of which index were up to all right could have just use a regular for loop just that has that built in but this is also fine what's that the index here and then we'll increment the index now this is where it gets interesting okay so what we need for OpenGL is we can't just say that it's a vector e we have to say that it's actually three floats we have to say the time and then the count as if it's like not one variable now interact X you don't you don't do that you just say you know this is a focal partner vector this is a three component vector or two component vector so that's why like I don't that that's why I haven't written this in a way that is just like you know type and count as if we have type being float and then count being three that's weird I don't like doing it that way and DirectX doesn't want it that way anyway so what we need here is some kind of conversion to take place so it'd be nice if just regardless elements just had a component count right because that will just make that work so let's go back into buffer and actually just add that in so buffer element will make a little probably some kind of get component count thing here right we can probably like I'm not sure what the best way to do this would be I guess I don't think is gonna be called often enough for us to catch that and ruin the kind of you know sort of memory that'll be annoying so maybe we can just say get elements count and then we can maybe just do some kind of switch yeah I'm just thinking about this yeah it's probably fine if we just um left comes here and then we'll switch on the type here and we'll say that if we have a shader type floor three will just return great okay and that is the component cat what do you know water ten zero here any asserts saying that we have an unknown type again this shouldn't really happen ever but it might and I guess because I'm a good person even though I said I probably wouldn't will fill out the rest of these so we'll start with float then we'll have float two three four then int oops two three four what else we have Matt Matt for and stuff okay sure no more probably don't need Matt 4 and not 3 to be completely honest with you because it's Lana Lee's gonna be well I don't know this is the component calculator it's not gonna be used just for attributes so we might need that and then I've it everything I get will humble that's obviously one that's four that's three that's true that's one am at four is going to be four times four not three is gonna be three times three flat for twenty four to one all right now looks pretty good to me let's just tap this across and let's kind of try and align this some watch just so that it looks nice and there we go okay cool so there we go now we can put the element count sorry not element counts this is gate component count okay so just just how many components essentially we have here now unfortunately we also need so we've got the component count but we also need the actual OpenGL type and this is like the base type we don't we can't have like vector e we need specifically flirt so we also need something that figures that out now I don't really like the type that we actually have obviously is inside our element and it is like our like you know we have like element type essentially that's our shader data type so what I'm gonna do is write a function up here that's obviously not gonna live here forever it's gonna be called will have it return a you will have a return a GL email which is what that type I guess what the vertex the trip pointed parameter actually expected the type to be and will say shader datatype to OpenGL base type in case is gonna be conversion between the shader data type to the opengl base type so again we'll have a switch statement on type oh my gosh did that for me that's pretty cool might actually after - oh love it now I wasn't planning to this is the one this is the one time I was planning on not actually doing all of these but I guess I will have to know so in this case you know we're gonna just return jail flow and that's actually gonna be the case I think for a lot of these so this included right and you you weren't always need this function but you do sometimes need it and I guess for that for that it's fine so does this ends and we haven't dealt with unsigned ends but you know if we really want that in the future then we can just do that in the future okay I don't know if you know we'll just have a ball I guess I don't really know because this isn't something that we do all day so unknown that and wonder 10 0 okay cool so there we go so now what we can do is actually go over here and say that we have shader data type to OpenGL base type and that's how we get out you upload now whether or not it's normalized again really easy to do elements dots normalized oh my gosh I forgot about normalization didn't I normalized so if that's true then we'll do GL true I knew I forgot something otherwise you're false okay this pride obviously is going to be lay out not element that lay out dot stride don't get stride I thought I'd did that probably not and then the offset is going to be elements dot offset okay and will cost this to a constable pointer alright bit hard to see because it's pretty big but there we have our huge line of code which I probably should break into multiple lines that I guess I will break it up into multiple lines just so you guys can see all of it so we're gonna have all this stuff I guess every parameter on a separate line just like that okay and normalized so we need to add that so buffer will normalized which again like I don't know we'll just have it as false by default and no real way to set it for now but we might have a constructor I mean look let's just be nice let's just say bull well I'm actually try it this will work with initializer lists but if we just do that does that work yeah that's the works cool so we can now optionally specify whether or not this is normalized so normalization is good for if you're supplying like a like a an unsigned int essentially and you want it to automatically convert it into a back for of like floats um it can actually do that you just say that you're supplying an int and that it's needs to be normalized and you'll get that this has no member called guess tried yeah so what you can do now is if something were to be normalized you could just do that right and again not sure yes you wouldn't do that here but if you have like a color is it that's not signed in we can actually try that out you know why not um I'm feeling a bit adventurous today I'm feeling like actually doing stuff even though this video is dragging on anyway I'll stop talking so gets tried we need to add that so we have stride in line you enthuse you t get stride const return m stride alright I think that's it like if I hit a five now it should probably work let's just try oh and we haven't set the layout that's a we don't have to technically speaking because we're just writing it from here anyway we have a compiler okay notable constructors that's a good point so we need to add default constructors for all of these right buffer element because they need to be initialized and buffer layout now you could be less lazy with this and actually give your your things default parameters it works for here it doesn't work for here I'm not gonna bother for now okay let's hit f5 and see what happens okay look at that we have our triangle how cool is that that's really cool we had that last time as well let's try and um and actually add a color now so what I'm gonna do is inside my layout just add a new flirt for it's going to be my color and then I'm going to go into the shader and and layout location equals one in effect for color okay I'm not going to use it for now let's just see if this even works right in fact I don't even have to add it here let's just keep that out for now I might just take it out at the end so I can undo it and but everything should work here the only thing we need is actually everything here so let's specify color let's just make this thing pink I guess this will say 1 0 1 1 right that's kind of pink magenta so every vertex will be that color and then we can probably interplay between them in a minute as well just to see how that looks like but for now we'll start with pink which means we now have I guess 7 elements per vertex everything should be calculated automatically though that's the beauty of this and if we take away this I'm we should just get exactly the same result this last time even though our vertex buffer has more stuff in it hopefully everything else did not need changing look at that we still get our triangle even though I bet X bar is different clearly this stride and the offsets are working correctly otherwise it wouldn't you we would read the next three vertices as being this and our triangle would look different let's bring back the color and actually set the color inside our case we need to keep this to the fragment shader so we'll say out that for the color copy that paste that here call it in back for V color and then we're going to set color equals V color okay I'll just do that over here right after this one to override it f5 okay so here we get a black triangle which isn't right that's because I forgot to actually set the color Portwood right you guys probably thought that my awesome buffer like layout code just wasn't right but that's not actually it is actually in fact working because I wrote it so you know alright there we have a pink triangle pretty cool last thing I'll do is actually just change the color right so the color of this vertex I'll leave is pink the color of this vertex I will set to like blue or something so I'll get rid of this and these are very harsh colors obviously I'm not trying to be like an artist in this case and then I guess what's there maybe one of them to like yellow or something let's hit f5 and see what happens okay so now we have actually defined Vettes calls where pink yellow and green blue before I can't I can't honestly I can't commit this code cause it just looks like absolute trash so what I'll do is make some I'll make it just look nicer so we'll say point eight and point two just so that we're not kind of going all the way actually this it needs to be pointy so we'll say point eight I'm just scaling the colors down a little bit so they're not as harsh because like honestly like and adding a bit more of other colors in because otherwise like it just as you saw just looks so bad I really kind of hate it this will make it look a lot nicer so let's just hit f5 and see what happens I need to get that permission on t-shirt because apparently it's my favorite catchphrase ever ever okay beautiful there we have our triangle with Olivet has cars working all of this stuff is now you know the layout so we're all working correctly obviously what we actually needed to do is call this set layout layout okay and I guess what we can do just to be really cool is just to make sure that works is just to make sure that we kind of get the layout from the vertex buffer this is not gonna work because it's constantly and we don't allow consciousness that's fun we definitely should wait a constant iterative to make that happen which I don't know I thought that that would kind of just work but I guess not so I guess we need to also return a Const iterator which is you know fun Const Const yeah I guess that that should would work okay done and I'll do I'll actually put that in here just to make sure that we can't even access that way I think so this actually gets destroyed in this case after we've said it so now it should be stored in the other thing and I guess that obviously you probably brings out into a variable before putting it here but for fun I'll just leave it here let's hit f5 and see what happens yep that's it that's my phrase everything works beautiful and then finally just to clean it up and make it super nice I'll just do order Const or our reference layout equals that and I'll just pop this in here and just check that card and then now it's like ready to commit and it will look nice okay that's it so that is Buffalo outs this is very powerful what I've just written right like this stuff is really nice it's really satisfying to have a system like this in your engine because that way you can just be really nice in the script you can see that you can visually see it'll out right I look over here what do I see you know that three a position of Veck for a color now float three a position float for a color everything's here in exactly the same way that it appears here which is just amazing right that's the kind of stuff you want you don't want to be doing what fiddling with numbers working out strides doing all that stuff yourself and no you describe your data in this way it's going to be acceptable for DirectX it's gonna be acceptable for OpenGL everything is gonna work it's gonna be beautiful and you know if you make an if you make a mistake like this you know you know look clearly it's different right and now we'll you can see kind of how that works so this is kind of the idea of what I was kind of getting out with nice elegant code kinda like that English essay hopefully that makes sense and I hope that you guys can learn something from this now next time again I do want to move this into vertex alright and then this actual stuff this actual kit this actual what figuring out these vertex rip pointers that will be in the OpenGL vertex array like you know class so that'll be all kind of done through there anyway I hope you guys enjoy this video if you did even hit the like button you helped small the stereos by going over to patreon icon for session the Cherno please help support this series if you liked about episode because all the support from all those people is what makes this kind of stuff possible now if you do want to kind of skip ahead and see what I've written and you don't got like a full PPR and eruption it off a few times probably will make a video like specifically showing it off sometime this week maybe but if you want access to that source code just right now today you can just go ahead and go to patreon don't go 4/2 turner helps about Sirius and you will get access to that now let me know what you thought what you thought of this whole kind of buffer layout um I quite like this way of dealing with it I probably wouldn't even a gunner I feel like there's probably no better way they're gonna do this unless you actually maybe like I don't know it's weird what you could do is obviously pause the shader and then just figure out what it is cuz indirect tax they're linked anyway but if you pass the shader and you just kind of figure out what your actual be is actually your arm and you automatically set and validate and the Buffalo out like that maybe that would be even more robust because that way there'd be zero code duplication and the layout would be actually automatically figured out from the shader but aside from doing and stuff like this but I don't feel like that's necessary to be honest you get the stuff right and you can have a vertex buffer and your shader kind of laid out correctly and and everything should just work so let me know what you thought in the comments section below hopefully I taught you guys something new and you kind of um I'm now able to just write more elegant card that's my heart but anyway next time as I said about X arrays we want to kind of get on with that and actually moved some of this code that we've written here today in the application class need to vet x-rays as you can see it's dark outside because that's how long this episode's been going for I will see you next time goodbye [Music]
Original Description
Patreon ► https://patreon.com/thecherno
GitHub repository ► https://github.com/TheCherno/Hazel
Instagram ► https://instagram.com/thecherno
Twitter ► https://twitter.com/thecherno
Discord ► https://thecherno.com/discord
Series Playlist ► https://thecherno.com/engine
Gear I use:
-----------------
BEST laptop for programming! ► http://geni.us/pakTES
My FAVOURITE keyboard for programming! ► http://geni.us/zNhB
FAVOURITE monitors for programming! ► http://geni.us/Ig6KBq
MAIN Camera ► http://geni.us/t6xyDRO
MAIN Lens ► http://geni.us/xGoDWT
Second Camera ► http://geni.us/CYUQ
Microphone ► http://geni.us/wqO6g7K
Watch on YouTube ↗
(saves to browser)
Sign in to unlock AI tutor explanation · ⚡30
Playlist
Uploads from The Cherno · The Cherno · 0 of 60
← Previous
Next →
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
3D Game Programming - Episode 1 - Window
The Cherno
3D Game Programming - Episode 2 - Game Loop
The Cherno
3D Game Programming - Episode 3 - Arrays
The Cherno
3D Game Programming - Episode 4 - Drawing Pixels!
The Cherno
3D Game Programming - Episode 4.5 - How Rendering Works
The Cherno
3D Game Programming - Episode 5 - Playing with Pixels!
The Cherno
3D Game Programming - Episode 6 - Performance Boosting
The Cherno
3D Game Programming - Episode 7 - FPS Counter
The Cherno
3D Game Programming - Episode 8 - Alpha Support and More
The Cherno
3D Game Programming - Episode 9 - Beginning 3D
The Cherno
3D Game Programming - Episode 10 - Floors and Animation
The Cherno
3D Game Programming - Episode 11 - Rotation
The Cherno
3D Game Programming - Episode 12 - User Input
The Cherno
3D Game Programming - Episode 13 - Render Distance Limiter!
The Cherno
3D Game Programming - Episode 14 - Basic Mouse Movement
The Cherno
3D Game Programming - Episode 15 - Textures + More!
The Cherno
3D Game Programming - Episode 16 - Walking, Crouching, Sprinting + More
The Cherno
3D Game Programming - Episode 16.5 - Exporting Runnable Jars
The Cherno
3D Game Programming - Episode 17 - Small Adjustments + Birthday!
The Cherno
3D Game Programming - Episode 17.5 - Creating an Applet
The Cherno
3D Game Programming - Episode 18 - The Beginning of Walls
The Cherno
3D Game Programming - Episode 18.1 - A Few More Things
The Cherno
Episode 18.5 - Creating an EXE File in Java
The Cherno
3D Game Programming - Episode 19 - Rendering Walls
The Cherno
3D Game Programming - Episode 20 - Continuing Walls, Fixing Bugs, and Managing Crashes
The Cherno
3D Game Programming - Episode 21 - Texturing Walls, Fixing Clipping, and Fixing the Mouse
The Cherno
3D Game Programming - Episode 22 - Random Level Generator + Properly Fixing Clipping
The Cherno
3D Game Programming - Episode 23 - Graphical User Interface (GUI) Launcher
The Cherno
3D Game Programming - Episode 24 - Making Our Launcher Work
The Cherno
3D Game Programming - Episode 25 - Writing and Reading Files
The Cherno
3D Game Programming - Episode 26 - Custom Resolutions
The Cherno
3D Game Programming - Episode 27 - Decorating the Launcher
The Cherno
3D Game Programming - Episode 28 - Continuing our Custom Launcher!
The Cherno
3D Game Programming - Episode 29 - Launching The Game
The Cherno
3D Game Programming - Episode 30 - Colour Processing In-Depth
The Cherno
3D Game Programming - Episode 31 - Sprites!
The Cherno
3D Game Programming - Episode 32 - Sprite Mapping
The Cherno
3D Game Programming - Episode 33 - High Resolution Rendering
The Cherno
3D Game Programming - Episode 34 - Entities
The Cherno
Genesis - My Game for Ludum Dare 24
The Cherno
Vlog + Ludum Dare Results
The Cherno
Game Programming - Episode 1 - Resolution
The Cherno
Game Programming - Episode 2 - Threads
The Cherno
Game Programming - Episode 3 - Game Loop
The Cherno
Game Programming - Episode 4 - Window
The Cherno
Episode 5 - Buffer Strategy
The Cherno
Game Programming - Episode 6 - Graphics Initialized
The Cherno
Game Programming - Episode 7 - Buffered Image and Rasters
The Cherno
Game Programming - Episode 8 - The Screen Class
The Cherno
Game Programming - Episode 9 - Rendering Pixels
The Cherno
Game Programming - Episode 10 - Clearing the Screen
The Cherno
Game Programming - Episode 11 - "Out of Bounds, Baby!"
The Cherno
Game Programming - Episode 12 - Negative Bounds
The Cherno
Game Programming - Episode 13 - Timer
The Cherno
Game Programming - Episode 14 - FPS Counter
The Cherno
Episode 15 - Tiles
The Cherno
Game Programming - Episode 16 - The Map
The Cherno
The Walls 2 - Minecraft PvP Survival Map
The Cherno
Game Programming - Episode 17 - Key Input
The Cherno
Game Programming - Episode 18 - Controlling The Map
The Cherno
More on: Systems Design Basics
View skill →
🎓
Tutor Explanation
DeepCamp AI