Rendering Circles in a Game Engine // Game Engine series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys my name is channel welcome back to my game engine series been a while since the last episode we had the whole optimization october thing so we took a little bit of a break from the series october has now finished optimization october has only just begun but nevertheless we're going to return to the kind of weekly game engine series episodes i suspect that there's probably going to be a few over the course of the next week or two so more than usual just because there are a lot of minor things that we have to do and they're pretty easy and i just want to kind of you know get into it so let's take a look at where we kind of left off um the last thing that i believe we did was basically implementing this whole physics situation with box 2d being able to hit play and then seeing our game kind of thing work so this is pretty exciting because we now have like box duty physics working and we now have this kind of game world that we can design hit play and then simulate which is which is great i mean it's a step into the right direction in terms of what we need to actually make a game engine capable of producing games now if we take a look at the road map and what we're going to be doing today um this kind of uh this is by the way this roadmap is the roadmap of what we are doing in this kind of game engine series here on youtube but it's also like the road map of what we're doing on the live stream so for those of you who don't know every like thursday morning afternoon australian time i live stream on twitch.tv slash the journal my twitch channel and i do specifically game engine series stuff so last thursday we resumed the streams because optimization october or at least october has finished so you can always check back there because the vods stay up for 60 days after which i usually upload them to patreon for patreons so you can actually check and check out the whole backlog if you're a patron but nevertheless if you check out that live stream that's a good example of where we're heading and in fact i think that a lot of the work that we're going to be doing over the next few episodes has been done in the previous live stream or even live stream before that anyway point being that this road map may in fact say that for example circle colliders have been implemented but realistically they haven't actually been implemented in the game engine series yet they've been implemented uh during the live streams if that makes sense and i think if you go to the official github page for this game engine series repository for hazel 2d which is github.com hazel real hazel is actually on gitlab so it's entirely separated from this but there's a dev branch and this dev branch um you can see like has circles and stuff so this is stuff i must not have pushed the latest code from the live stream but anyway um so if you want to keep up to date with like stuff that's basically marked as completed here in the roadmap definitely make sure that you check out the dev branch because we are currently on the physics branch and that is in sync with these videos so just a little bit of like housekeeping and a little bit of like explanation as to what is going on where everything is because i know it's been a while and if you're kind of keeping up with this series um you kind of need to get into this i'm actually working on a website as well so that will explain this so that i don't have to say it like maybe in in every video or whatever could have added it to the readme but anyway point is um soon i'll have something to link to that will explain like the workflow and how everything is working so what are we doing today well circle colliders would be fantastic to have but the thing is we need to be able to render circles because if we don't have a a way to actually render a circle then how can we make a circle collider well of course we could simply render a quad with a texture applied to it because we know that we can you know choose to texture these quads if we go to textures and drag in like the cherno logo there we go we now have the turner logo and that is you can see vaguely almost looks like a circle rather than a square because it's got a lot of transparency in it so we couldn't we could in fact just drag on like a circle texture right so something that we've made in like photoshop or paint or whatever where like the edges are kind of transparent not the edges but you guys know what i mean like literally drawing a circle and making like the the outer sides just transparent and then we could actually like add a circle collider to it but i think it would be a lot better if we had the ability to actually render circles uh because this is something that is just useful to have in general but also we're definitely going to be we're definitely going to need some way of rendering circles so that when we have a circle collider we can actually visualize it if you look back at this road map one of the things that we have to do is visualize colliders and that's actually done on the the latest live stream that we had so we need to be able to like show these the bounds of this box collider because of course we can offset it we can resize it and also for debugging the actual engine development to make sure that this is in fact the right size we can't see it we can kind of validate that by just looking and being like yeah that looks vaguely right but it's a lot better to be able to visualize those colliders and that's something we need to work towards now to give you guys a little bit of a better idea of what we're actually working on i thought i would open up the real hazel this is the hazel version that you can get on patreon if you support on patreon patreon.com you guys know all that stuff um which also helps to support this series by the way so it's it's worth doing anyway plugging aside um what you can do here is if you come into like the settings then we have this like show physics colliders thing and this works for both like 2d and 3d colliders so in this case we mostly have 3d colliders because this is in fact a 3d game world however if i go ahead and create like um you know some kind of let's just make an empty entity let's go to it and then if i add a 2d collider to it which is what we can do in hazel 2d as well a box collider 2d you can see that we can we can see it let me just maybe drag it up a little bit you can see that it isn't it's a different color just so that we can differentiate it from 3d colliders so 3d colors are green because physx 2d colliders i thought i'd make them blue and if we have like a circle collider on it which i think we can add both you can see that shows up as a circle not sure why the default radius is one but uh you can see that we we can actually show it up we can visualize it as a circle now this circle is a bit different than like the circles i talked about in my recent circles video which i'll get to in a minute because you can see it's actually made out of line segments this is just something we use for debug rendering it's just drawing lines same as this actual square but the point is you can see we can kind of visualize this collider and it's a 2d collider by just toggling on this kind of show physics colliders and there's even an on top setting where if i just turn that on then it will actually show everything like without depth testing so that's useful if you have some collider you know far away and you want to be able to see everything kind of through everything well not necessarily far away but if you have like a complex scene maybe you just want to see the colliders and you don't really care about like walls obscuring them and stuff like that but anyway point being this this is what i'm talking about when i talk about visualizing colliders it's just it's useful so that we can actually both debug our engine as we're developing it then also when we're working on a game maybe we want to make a collider that's like slightly bigger than we need for whatever reason and we can easily just make sure that it is in fact the right size by doing something like this now also when we have more complicated colliders in the future this is going to be absolutely necessary so with box 2d we have the ability to actually uh produce fairly complicated like physics things right so we can chain like joints together we can also make arbitrary polygon colliders and i plan on supporting that in hazel 2d because it's quite cool and it's quite useful and so in that case what we would do and what we would give the user the ability to do is actually like place a bunch of like points around in like 2d space i guess within our 3d world somewhere and then we could actually kind of use that to draw out a polygon and that obviously is really going to need to be visualized in some way because it really is arbitrary there's another way to see it right it's not something that we ultimately render it's just something that the physics system will will have and these these kind of visualizations i guess right these visualizers are a way for us to actually visualize the mathematical data that is then going to be used by the physics system anyway i think that you guys get the point of like visualizing these colliders i don't know why i went into so much detail explaining it all but let's dive in and take a look at circles today because that's really kind of what i wanted to do today um i spent a lot of time talking about colliders because that's what we're going to use circles for in part but also how do we render circles well i made a video recently literally called how to render circles um this is me this is this is a circle um the video is like pretty good i think it's about 40 minutes long it goes into depth it doesn't actually feature like an engine implementation that's what we're going to do today so this is going to be useful but ultimately if you go to this shader toy example here in the description then this is like the circle that we can render and we can have it filled in we can have it not filled in here is the shader code for how to render a circle if you guys don't know what i'm talking about why is there shader code how do we render how do we render a nice smooth soft circle definitely check out this video i'll have it linked and it'll be in the description as well um because this is going to teach you how to actually render this why it works how it works all of that stuff and why we want to do it this way but today i'm just going to be able to take the code and just not explain it that much because it's been explained in this video so definitely check out this video um if you haven't already seen it so how do we go about integrating this into our engine well the thing is since it is an engine since we are making an engine um and we want to integrate this kind of circle rendering into our game engine we need to think about like how one would use this so it's not just about like let's write a function called render circle take in some parameters and we're done that's great if you're building some kind of library or framework that's how it works but because this is a game engine there's a there's an entirely like uh separate level of complexity to it which is like how do i actually set up this game world to render a circle if i if that's what i want to do if i want to make this square a circle how do i interact with it here now what you can do and what i actually ended up doing i think in the live streams um where i integrated circles into like the dev branch of hazel 2d so on twitch or that all the stuff that i was doing is i ended up making like another component called a circle renderer right so a sprite renderer is specifically made for rendering like a rectangle that is the that is the geometry there now in the future we may want to create some kind of 2d mesh like a like a polygonal shape i guess that would wrap around a texture if it had a lot of transparency in it that's something that we may want to explore in the future it's a bit of a minor optimization if you ask me so i don't think we'll be doing it anytime soon but for now the way that we define sprites is they are a quad in the rendering pipeline in the game engine they are a quart they are a rectangle right now they don't have to be uniform we can scale these however we like right and they're going to be totally fine so they don't have to be like an exact square or anything but they have four edges it's like a polygon with four edges that is what a sprite is it can be textured it can be not textured and that's like whatever right you can just drag a texture in and it's now textured that doesn't matter point being oh we have no way to get rid of this texture that's nice we can tint the texture as well which is nice but the point is they are that that's what they are geometrically they are just a quad and they expect to maybe have a texture or a color and that's it now a circle geometrically is also going to be a quad because of how we render it however the appearance of it will always be a circle and furthermore we know that to render circles using our desired approach we need to obviously run it on a shader so we need to somehow have a pipeline now for rendering circles i could like somehow put it into sprite renderer but in my opinion i think that it would be just easier if there was a circle renderer component instead and then you can you know have your circle related parameters here and furthermore you won't be able to texture it why because there's no sense in texturing a circle if you want a textured circle make the texture be a circle and apply it to a sprite renderer right because the geometry at the end is going to be identical they're both being rendered on quads but one has this kind of shader that can render color and tint and tiling and textures and the other one is going to be able to render circles of varying softnesses and maybe with like like doughnuts and you know discs circles whatever all of that related stuff okay so that is basically my explanation let's dive in and implement this uh i'll put like i always i'm to try and always put chapters throughout these videos just to so that people can skip to the past that they actually want to see because i know that these are usually just a bunch of information and not everyone wants to sit through it but let's dive in and take a look at how we can implement this so step one is going to be to take a look at our actual renderer now what i'm actually going to do is probably something a little bit different so in this video i don't have any reference code i'm going to implement it just using that shader code that i showed you i'm going to pretend to be you watching this video and being like how do i implement this in my game engine i think that'll probably produce the most value hopefully to you people but uh we're also since we are integrating this into a game engine and not necessarily just like a framework or something we are going to think about the user kind of uh user interface and all that so we have to make a circle component and i'm actually going to start from that so if we go into components um we have all of our components here all right um now what i want to do is we have this like box collider component rigid body component we've got all this stuff now what i want to do and actually let me quickly take a look at i don't think i ended up doing this i just want to familiarize myself with this code quickly um yes we have all these all on component added we copy component if exist okay yeah cool so we didn't get around to doing the list of components yet we'll do that at some point um but anyway so we have a sprite renderer component let's just copy this component and i'm going to call it a circle renderer component now we have color no texture and we should have some kind of radius now we're going to start this off with 0.5 why because everything by default is one meter in hazel so in other words when you pre when you create like a you know a when you add a sprite render component to a um to an entity then it will appear as like a one by one meter quad in this case we want a one meter diameter circle so radius of course is half the diameter so we can make the radius 0.5 by default and that should be good uh by default i mean if i don't think we need like constructions like this mostly just a default constructor copy constructor is good because we have this here and it will be white by default now there are definitely other things we want to control um there's a parameter that's going to be called thickness now if it's a one and this is you can refer to the actual shader to see what these parameters should be if the thickness is one it's 0.5 here but if we change the thickness to one this is what it looks like it's a filled in circle right and if we make the thickness like point one it will be a lot thinner now this is somewhat resolution dependent i'm not sure if we'll stick with this we might be able to use like shader uh derivatives and stuff like that to make this a little bit better we might look at that look into that in the future i want to obviously implement this in a simple way so that it's easy to understand and also gets the job done for the majority of people uh but we yeah with the thickness we'll probably just leave it like this where one is a filled in circle and then something like point five is like half filled in or whatever and then we also have fade so this can be used for like stylistic effects if you want a circle like that you know why not give people the ability to kind of do that right i think that's probably worth doing um so fade and thickness are really the two parameters we expose of course color as well but we've already kind of talked about color because color is up here okay so um that being said let's add in that fade now by default i guess we'll keep this at like point zero zero five immediately it's kind of occurring to me that these are very weird numbers right like a fade of 0.005 like what does that even mean so i'm not sure if we'll keep them like this because we have to think about what this is like to the user now again a thickness zero to one i guess that makes sense one is like the completely filled in 0.01 might be like a thin outline but fade you know like realistically again 0.005 is a nice number but like i don't really imagine people will be like oh yeah let's make it .05 or whatever so i'm not sure like what this should be uh for now we'll just leave it like this and i will leave it exposed just in case people want like ultra blurry or whatever circles for whatever effect they're going for but yeah just like a note that we may have to revisit this because i don't see this being very user-friendly okay so now that we have that how do we integrate it with the rest of our engine well we have to make uh well that's kind of really it as far as like declaring the component but we have to add some ui for it and that's what this is for in the scene hierarchy panel so circle renderer component circle renderer so color we don't need any textures so we'll have color this will be like the thickness so the thickness is going to be component.thickness and uh we have like a a speed and then a minimax so speed i might make like point zero two five or something and then min and max is going to be zero and one uh and then we'll also have our fade which i will probably make really slow uh and then we'll make it again i guess zero and one like i'm not really sure what this should be the default value is like point zero five point zero zero five i think um and yeah this will be the fade so if we if we jump into the circle render component let's just make sure we have everything yeah radius is important so radius the thing with radius though and the reason why i don't even know if we necessarily need this is that we should be able to take that from the scale so a scale of one means a diameter of one so i think i want to cut radius i don't i don't see why we would have that uh again you know there are uses for it maybe you want to have like a circle renderer and a sprite render component at the same time and you want like a different size for the circle for whatever reason then i don't know there are maybe some use cases but almost all of them usually end with just make a separate child entity or sibling entity and give that the circle render component then it has its own transform component and you can do whatever you want with it so that's why we're going to keep it simple and we're going to get rid of the radius thickness of course is like the outline thickness i don't know if that's worth specifying but whatever um okay so we now have a way to control the parameters of the circle but we have no way to add it as a component so let's go ahead and do that so we should have like some add component um pop up here which is what we use like for sprite renderer components so we'll obviously duplicate this with the circle renderer component and we're pretty much done so this is cool now because we have the ability to add this component to any entity now in the ui and we can also modify the parameters that's really all we need to get started we also need to worry about serialization and duplicating entities and all that stuff but we'll do that stuff at the end so rendering wise how is this going to work well we know that we have to run a custom shader and we also know that uh more or less the the geometry is going to be the same so the fact that the geometry is the same tells me immediately that we can reuse the index buffer because we're literally just drawing quads well and we can also use these quad vertex positions to actually set up the geometry that we need in the correct location and we can match it together now we can't batch it together with our existing geometry because we're going to use a different shader obviously it's going to be our circle shader so that is important to know also the vertex buffer is going to be entirely different why because stuff like text quad text index tiling factor none of this stuff is relevant and furthermore we need a way to set thickness and fade so what does that mean that means that we need to make a new type of vertex and this is going to be called our circle vertex this is going to live in a special circle vertex buffer so we have a position we have color now um the rest of these are basically going to be uh let's see so we're going to have our um thickness that's it i was trying to remember what that other parameter was and fade now you could batch these into like you know some vector called params and then that's just kind of like you know excess thickness wise fade i don't know if there's really any benefit to doing that um there would be if there were like some alignment issues with this and there was like excessive padding like if it was 16 by padded or whatever and floats were 16-bit aligned that could be more efficient i think that again you know hazel 2d game engine series we'll keep it simple we'll keep it like this uh we'll keep them as two separate variables and i think that should be okay if anyone wants to correct me and be like no like it's definitely going to be more efficient to have it as a vector sure let me know in the comments below we can talk about it but otherwise i'm going to do this for now okay looks good to me i guess if you wanted to be really cool as well you could kind of do something like this where your um maybe i will do this just because uh if you know this would make this would make sense packing it like this but again um for now i'm gonna leave it like this because i can't tell you off the top of my head what exactly is gonna happen with this okay so let's go ahead and make it um inside uh here so we have um quad vertex buffer now it's probably worth correcting this texture shader to be called something else just because like it doesn't make much sense being called texture shader this is our quad shader really uh so we will probably change that later but let's go ahead and copy these three and we're going to call it circle vertex array because we're going to have a different vertex array for it we need to it's going to have a different vertex buffer layout and a circle vertex buffer and a circle shader so these three things let's go ahead and make them we'll jump to where we make this stuff uh and we make quad vertex okay yeah so the quad vertex buffer base and quad index count we're gonna have to duplicate this and have a circle index count this is pretty easy with an existing batch render again you really just need to duplicate a lot of these things for to be circles instead of quads find replace quad circle that kind of stuff but if we jump into here this is the next step i want to um copy this uh and let's come down here where we have some space maybe before the white texture circles and i'll set up the circle stuff so again this is very much just find replace um trying to get this stuff to be a circle instead of that we can probably reuse these max vertices do we need to also have 20 000 circles probably not um realistically it's probably a better strategy to implement some kind of resizing vertex buffer kind of like the way that like an scd vector would work the reason being that you know this is gonna depend on what game you're making maybe your game is all about circles so first of all why do i have twenty thousand chords that i don't need or vice versa my game doesn't use a single circle and yet i have 20 000 a vertex buffer with enough memory for 20 000 quads sitting around for no reason so i do recognize this stuff is not ideal uh but again this might be something we can do in optimization october next year or something like that um because i don't want to get bogged down with optimization stuff at the moment but yes if you're implementing this in your engine maybe you'd want to make it resizable start off with like 100 or something more reasonable and then just have it resize from there using some kind of result like plus 50 percent like an std vector would do or like doubling every time whatever you want okay um so uh s data vertex buffer is that really a thing no it's quad vertex buffer so circle vertex buffer circle fedex array circle everything basically now here's the cool part though um this index buffer that we have here we can actually set the same quad index buffer to also be used for our circle vertex array because again there it is identical geometry we don't need to make another one of these we can just reference that same existing index buffer since the indices are the same um use a quad ib i'm just going to add a little comment here just so that it's clear that this is intentional not like some copy paste error so uh i'm just what i like to do at the end of this by the way is if you just go ctrl f within this it'll show you the selection it's hard to see here because i'm in the way my face but that's okay if you just type in like the word quad into here uh we want to make sure that it doesn't show up where it shouldn't because if it does then we've probably just forgotten to replace it somewhere so you can see quad is nowhere to be found obviously quad ib is fine but otherwise you know we've we've successfully replaced it with circle everywhere so that's kind of just what i'm checking for okay so position color and then the rest we can take from here from the rest of our parameters so we have a thickness these names are absolutely useless by the way they're just for us really as strings i don't even know like we do this like in directx and hlsl you do need to kind of have these attribute names um but this is just we could have just made something that didn't have names and just had a layout uh but i don't know i guess i think we're sticking to this for now so we'll have um these these are both floats and uh i think that's pretty much it let's just curl some of this white space um and yeah we're good okay so there we go position color thickness and fade and the entity id so that will make our circles obviously clickable so that we can just click on them to select which is important as well okay um are we done with this part i think we are so how do we how do we actually draw these well again this is going to be quite simple um let's grab so how do we want to draw these so probably just by using a transform again position size useful but realistically this is how we're going to draw them like 99 of the time so um we'll do draw circle i know it's more like a filled in circle thing but doesn't matter because the circles can be both filled in and not filled in so it's okay um so transform transform color and then we need the rest of our parameters so we we need thickness which can have a default value of one if we want and we can have a um our fade as a default value 0.05 again they will realistically all be set the reason why i'm setting defaults here is because if we call this as part of like some c plus code because we're debugging something maybe we can emit some of the parameters if we need to okay so what is this going to do well let's refer to draw quad because it's really going to do the same thing the draw quad that has a color though so uh let's let's just start by copying the entire function because that's kind of what we'll be doing okay so we have a quad vertex account which we use to iterate through here i think someone like this code was like a pull request or someone pulled in i don't think i would necessarily necessarily write it like this uh but it's okay that it's like this um so quad index count max yeah so this whole next batch situation i don't even know where we sit on that so if we kind of get if we because the thing is this this flush function at the moment like it flushes just quads in the fu like the way that i'm going to write this right now it's going to flush both circles and quartz but they are separate so it makes sense to have a flush quads that's a separate function it will just present the quads and then that way you can start writing more quads if you exceed that 20 000 limit right i i did mention a resizable vertex buffer before but obviously you don't need to bash them into one draw call you can have a hundred thousand quads and that will be five draw calls and that's totally fine right so you don't need to implement the whole recyclable thing but maybe it would be more optimal obviously and if you start off with like 100 quads and then turns out your game's rendering tens of thousands that you just actually do resize your batches uh dynamically so that's kind of what i was talking about but yeah of course you could just flush keep flushing keep drawing and then you'll have a bunch of draw calls per frame okay it's a draw circle so basically what i'm saying is to do implement for circles we're probably not going to do this today um not that it's particularly difficult this can be an exercise for the reader actually or the viewer if you guys want to do this and submit it as a pull request feel free it's very simple to do um i'm just conscious of the fact that this video is already like half an hour long uh but you just need to make like a flush quartz flush circles and then obviously next batch you wouldn't just arbitrarily have next batch uh you would have like like separated functions to reset all of these things or at the end of the scene you know you'd flush everything and at the beginning of the scene you would reset everything like this is doing so that's all you're just separating them so that if you need to you can you can um actually call you know reset and flush on a specific type of geometry that render it is rendering and by geometry i mean like primitive type i guess because we're also going to add lines later and that will be its own thing as well okay so everything has four vertices i don't really see the need for that constant um so uh quarter vertex buffer pointer it becomes obviously circle vertex buffer pointer position color stays the same um and then uh yeah and we obviously reuse quad vertex positions but oh we actually need one more thing um sorry i kind of forgot see this is what i mean by implementing this stuff from a shader from memory uh we actually do need a few more attributes because we need to know the local space now um we don't have a uv coordinate this has a uv right because that's just what shader toy provides it's just one of the shader inputs is this kind of um frag quad thing which actually it's right here right but we don't have that we could use like gl frag chord or whatever i don't really want to do that because obviously we're not filling the screen either so what we need to do is basically have a value that is from negative one to one like this so that we can actually run it through this this equation basically in this algorithm so um the way that we're going to do that is we're going to add something else called local position now do we still need normal position well yes because this is this becomes like our world position and obviously this is in world space with the transform matrix already applied it's very different than the other thing right whereas this is like our local position i don't know why i decided to make that a um a float but it's a vec3 right so this local position because i just thought zero to one but it has to be obviously nature in each axis and they're probably not i probably could just have it be like a vector ii instead but um we'll keep it as a vector here so level position maybe we can make some cool 3d sphere circles later so local position is just going to be one of four values basically um and it's going to basically fall into being the quad vertex position because if you look at this we can just approximate it from here so this gives us a value of negative 0.5 to 0.5 we want to be negative 1 to 1 so i'm just going to multiply this by 2. that's it basically what that will end up being is just negative 1 negative 1 on the bottom left then positive 1 negative 1 on the bottom right positive 1 1 positive 1 positive 1 on the top right and then negative 1 positive 1 on the top left that's what that does so thickness thickness and then fade fade okay that's it um quad index count uh becomes circle index count we want to draw these independently obviously that's why we have the two different counts and then um [Music] yeah so this is a stat thing uh we can leave quad count because that will these are really quads that we're rendering again if you i guess you could separate this up and whatever too many too many choices is a game engine do whatever you want um okay that's probably looking good now obviously we just modified this so we should definitely make sure that we modify this now if these are vec3s though uh we're just these are vect4s right yeah these are vectors this is a vector3 so there should be an implicit conversion here into a vector3 because that's a vector okay i don't know maybe maybe it is worth making this like a uh a float two instead difficult difficult choices i just don't see the need for the z component at all but we'll see okay so um let's move on so what's the next step well we need to make sure that we integrate this with like start batch and stuff so start batch uh basically just resets our variables which need to do the same thing for circles so circle index count and the circle vertex buffer pointer needs to be reset and in flush we simply need to draw this now quad index count return that's not really how this works anymore uh more so if quad index count we need to draw this so we do this um and then if we have a circle index count so if that's not zero because it gets reset to zero at the beginning of the batch then we draw the circles so how do we do that well we need to first set the circle and you can you guys can see this is literally like just copying and pasting everything um but it's obviously a different set of data here because these are going to be filled with completely different completely different bytes of data um not just because they're circles and not like not not just because it's like a different instance of the vedic buffer but the layout is different and everything so circle circle circle is the gist of that no textures to bind um but we do have to bind this and we do have to increase the draw calls so texture shader is now going to be circle shader so let's go ahead and go to where the texture shader gets loaded duplicate this circle shader and i'm going to call this renderer 2d underscore circle okay we're going to rename this to render a 2d underscore quad or something a bit later but um but this circle shader uh is what we're going to bind here obviously we haven't made the shadow yet we're about to write that and then we do draw index with the circle a vertex array and the circle index count and i believe that is it i believe that is all we need to do um i don't think there's anything else that needs to be done really so it's pretty simple that's how we integrate that now let's write the shader so over here in shaders uh i'm just going to open up this actual file explorer thing uh let's copy and paste texture and we'll call it render a 2d underscore circle since we're here we might as well rename this to render a 2d underscore quad and then i'll obviously rename the texture shader so let's rename this texture shader to quad shader uh and then we will also rename the file that we're trying to load to be this okay so we've got our quad shader we've got our circle shader uh hopefully that will work um it should clear the cache and recompile like well the this will be it'll be gone from the cache because we've changed the name so it's okay and um let's go ahead and refresh this shaders list and look at render tv circles so i copied this so this is our renderer 2d circle shader hazel 2d renderer hazel 2d will be cool with our little branding or whatever you want to call it how cool am i i think it needs some of this there you go pretty cool um okay i don't like the way that looks at all maybe i'll change that but anyway so so now that's done all right um let's copy that kind of layout that we had so we had a world position we had local position and then we had color and then we had uh two floats so thickness and fade and then we had the entity id let's change these attributes one two three four five and uh we'll still have the camera because we need that uh do we need that i guess we i guess we do view projection well the view should be like are we yeah no that's fine yes of course we need the view projection sorry the transform is a thing that's baked in um so vertex output color text chord uh and tiling factor changes to color um well we need the local position in the fragment shader the color and then the thickness and the fade so the text index so yeah we kind of need to have uh now this will change i think i never know what this is going to end up being man so i think this is i think every 16 bytes is one location slot and it's probably padded as well so uh so how many bytes is this 12 plus 16 so 28 and then 32 36 so 36 and every 16 bytes so what does that mean that means it takes up three slots so this will be number three still am i correct i don't know i know i never know um so let's just do this uh that's location three and we'll see if it works out um [Music] otherwise and the reason we have to have this here in the first place is because it needs to be flat and we can't make it flat in there so uh tiling effect has also gone oh well actually no italian so let's do the local position then we can do the uh thickness and then we can do the fade okay so let's make this in the right order as well so it's easier to understand thickness fade okay good and then gel position remains the same so that's our vertex shader done uh then the fragment shader is going to be a bit easier to do hopefully so let me just copy the um vertex output struct to make sure it's the same obviously we don't need this and this should be number three now i think maybe um no textures either and now we can go to shader toy and um so i've got shader toy here i'm just going to literally copy everything and we're going to go from there so paste and let's discuss this so uh circle color is now an actual thing right so we can replace circle color with input dot color we call it input yes input.color so that's done thickness also a thing now so input.thickness and that's done fade fade is uh input dot fade this shader is actually getting shorter um so uv so uv is literally just like that negative one to one thing i was talking about so uv is just going to be the local position um now the aspect ratio it completely doesn't matter actually this is important though because um [Music] the local position but we're ready but we're changing the quad so yeah no this is fine so we don't need this either so the thing is like what's gonna happen here is um [Music] the like if we if we modify the transform like the scale of the actual entity then it that's what will stretch out our circle otherwise we don't need to do this aspect ratio thing because we assume that we're rendering on a square if we're not rendering on the square the only way we get to that state is if we actually play with the scale and obviously that's a deliberate thing so therefore that's kind of we would we would allow it to be an ellipse because that's what we would expect so um that means that yeah none of this needs to exist so uv is just going to be input dot um local position now in the shader toy code you can see that this u this uv was in fact a vector so that's what i was talking about there's no reason for this to be a vec3 um to be honest so i probably will change it to be a vector okay so i think that actually is is is it i mean obviously we need to set like output color i don't know why let's just call it out oh color and what's color to color 2 is the entity id right so entity id uh becomes um a v entity id and then color is what this is and that's it so really quite simple um [Music] yeah that's i think that's all there is to it and that's how we render circles so um now we have to actually implement it in our scene class so the same way that we go through in the i think it's on update right so on update editor we go through and we draw all the sprites if there's a sprite renderer component let's just put this in a scope um let's do the same thing we can't group them because that actually like plays with the memory layout um and we've already decided transformers render it together so let's call this a circle renderer component this is going to be a view instead so we can have our emergency review uh i think we can just list it out i never know what version of ant i'm using um because there's a few but uh so we're going through all the entities here i'm going to do view dot get this and that this should be referenced they are and um draw sprite will do draw circle instead and then this is where it's just going to take in all of our parameters so color is the first one so sprite let's call this circle or circle renderer so circle color circle thickness and circle fade now i guarantee to you that i probably have made a mistake somewhere but that's actually all we need to do so do we have a on update run time as well this is this must be on update runtime so we need to do the same thing here um so where we do the draw sprite stuff with the group this code is actually identical i believe so let's just copy both of these just because i added that scope as well and i want to keep it the reason i have a scope is just because it's easier to kind of separate this so draw sprites draw circles um by separate i mean you know stuff like view i can always use the variable name view because it's in its own scope and it's not going to leak into any other scope so that's just how i roll adding in our comments and i think if we hit f5 now uh we might be able to actually render some circles which will be pretty exciting but as i mentioned i will be shocked if i get this right from the first try so we'll see uh this is just our typical on component added error message that if you guys have been following the series you know what appears every time i add a component because i've forgotten about this useless contraption that we have here but uh we have to add this like so and um [Music] yeah what do you guys think is it going to work is it going to work is it going to not work um let's find out so apparently the shaded isn't compiled that's okay i forgot about that so a position undeclared identifier and that's basically the only problem it looks like yeah that's because i called it like world position or something so let's make sure that this is uh called world position take two uh still not compiling uh location overlapping use of location three really i thought i okay well it's not an overlapping use of location here but three must be overlapping so i guess my brilliant math or whatever i tried to do didn't work out let's try four uh still not compiling uh different error though assign convert from four component flow to three components so this is line 26 um is it the fragment shader though or the vertex shader weird that our code doesn't say uh that's a bit annoying isn't it so what is sure what stage is this thanks man is there any way to see what stage this is without looking at this oh we can look at the path maybe that's the fragment shader because it's dot frag anyway that's terrible we should definitely print the stage but fragment shader line 26 problem is our lines start from 45 45 minus 26 is like 19 i think so that doesn't help us at all doesn't it 45 plus 26 is what i meant so if that's so it should be it's i think it's this one here so input color oh because input colors of x4 that's why well in that case i think we can just do because what are we doing we're doing color and then with times equals just for the rgb so this is just let me just do color times input color um and that's kind of it i think that should be okay but yeah those error messages definitely need some work uh still bad um oh yeah sorry so this color is of it yep so let's do that um yeah vec4 times that i feel like let's just set the color to maybe be the input color and then we can multiply the rgb by color because that's a vec3 that might be that might look a little cleaner i don't know this is obviously just up to however you want it to look like we'll just do it that way sure shouldn't have any more errors anymore so what can we do well let's go let's open our physics scene for fun um now we don't see anything though where is our where is everything now we're not rendering anything so that's how good i am apparently i broke just rendering in general so let's figure out what's going on there what how did i manage to do that so i'll take you guys through the debugging i have to sit through this because i do as well so so draw spry let's just make sure that's still happening and i mean i don't really know right well we have a different shader right but we're definitely still trying to render sprites and we obviously should be rendering them the same way um that hasn't changed so flush should uh try it so it is trying to draw stuff and it's doing chord shader bind let's render 2d quad and then draw indexed and that seems to be drawing but we don't see anything on the screen so and we're not drawing any circles yet i believe no we're not so why why why is it suddenly not drawing anything so the only thing i can really think of is um the fact that i guess we we try to steal the index buffer from here but surely it's not that we should be able to share index buffers right oh okay oh i know what this is i remember this problem ah yes i remember this problem because this happened during the live stream like a month or more ago when i implemented this we have quite a fatal flaw in our actual render commands because when we uh do flush and so here we are trying to draw a bunch of quads guess what we totally don't do we totally don't actually bind this vertex array so we say we want draw index with this vertex array but you can see here nothing is binding the vertex array so if we look back i mean we're binding the shader and that's great but we obviously shouldn't be expected to bind the vertex array outside of this function especially if we're passing it in so if we go back here let's just do um a gl and i don't know why we suddenly decided to unbind the texture as well that i feel like that shouldn't be there that's a bit weird um but gl bind vertex array and we can do vertex i mean vertex ray might have a bind function but i like to uh well apparently we don't have a get render id i was going to say i was trying to actually put all the open gel code into here but that's okay so we'll bind the vertex array then we'll get the count and use it here and yeah that weird texture on binding thing i don't think we should necessarily be doing that um but anyway so scenes and then physics 2d so now we see this and now we should uh go back to um uh what did i disable i disabled so yeah the uh the index buffer we'll put that back so now let's see if we can render circles yeah see that's the benefit of doing these live streams as well the fact that um the fact that we encounter some of these issues on stream and it's a bit more of a easier place to debug it than when i'm making a video okay so let's try so how do we render a circle well let's add an empty entity here it is and let's add a circle renderer component and that should be it and you can see we see a circle now there's looks like there's like definitely some issues with alpha it's not blending properly at all now i think we actually set the alpha to be one though um so let's go back to render a 2d circle so color color is input color which i mean has an alpha of up that's fine but then the outsides okay so the outsides here so this is a color oh yes of course so this is one of the things i talked about in the actual in the actual circles video where i did the the whatever it's called the um [Music] the shader toy example so on shader toy we were playing with color because we were making an opaque thing right but in in reality what we kind of want to do here is we don't want to play with color we want to just have a kind of an alpha value so this should be our kind of circle circle alpha or something and it should just be a float it doesn't need to be a vec3 because we're not we don't care about a color so the only way we made it at 3 is we just duplicate it across all the channels the data that's it so this just becomes circle alpha output color.rgb can be this dot rgb if we want and you'll see why i'm separating it in a minute but then the alpha right oh actually let's do let's do this let's do uh output color equals input color and then we'll do output color um dot a times equals circle alpha the reason being this way um if we have a lower alpha as a as the color it will also apply to this it'll make the whole circle be partially transparent uh but that that's that's it so i don't know if circle alpha is the best thing here maybe just circle circle circle circle um now we have to recompile the shader by clearing the cache so let's open up the cache folder i this is very annoying i know i will fix this by having like a shader registry or something where we can just store like a hash of the shader and then recompile it if stuff changes um i like that approach uh okay so let's create our circle again move it over here and then let's um see it work perfectly because that's how i roll so um there you go there's your perfect circle uh you can play with the color and you can see it works and then we can also um basically go to the alpha channel and make it partially transparent and it works now at the moment the reason why blending is working perfectly is because we rendered the circles physically after we rendered the sprites this is just like a fluke kind of that it's working oh and yeah selection works as well so we can select um but but here's something so you can see i can't select the square behind it because the bounds of the circle is actually the geometry whereas if i move it here now i can select it so let's fix that that's very easy to fix we just need to make sure that um uh we just need to make sure that the entity id is only really being output if we're within the circle so um [Music] how should we do that so i guess if circle is greater than zero then we can output the entity id i guess that would probably be a sensible way of doing it right um let's recompile that shader though yeah super annoying believe me i am as annoyed as you are if not more um it's a epic one hour video as usual okay so let's drag that in all right let's make our circle again we can't serialize anything yet because that's also how we roll circle renderer orange because that's the best color obviously um and uh now let's try and click on this and that failed why is it selecting that what i keep dragging this hang on why is it so oh yeah why does it select the floor how is this the floor oh well actually um [Music] okay let's do this instead the reason is obvious i think it's it's going to fill the buffer with data anyway so what we should do is we should probably discard if this is the case so if we're outside of the bounds of the circle let's just discard those fragments and that way what we're writing in is stuff that definitely needs to actually be written in so if it's greater than sorry if it's less than one um but one is also not really see unfortunately it's gonna depend on the fade right because you're going to have a little bit of because we're smooth stepping it so you can probably calculate this by looking at the fade because the less than no but i guess to be honest we we should only really discard if it's exactly zero though right because if there's even a little bit then it's it's being it's like part of the circle so that would make sense so let's do this um let's try this but yeah that makes sense it's because the the data there is probably garbage um because it is still gonna write something uh it will just be whatever it yeah i think um so let's go empty entity and adding a circle renderer um i'll just differentiate the color so it's easier to see but let's see if we can select this now okay and we can okay now what we should be able to do and what we should have tested is like the thickness so you can see that also works so now to be really cool we should also be able to select this as you can see through the circle so that's the circle over here and then if we click here we select the thing behind it right so that should still work again we're doing this on a pixel level um that's why it's so nice to do picking with like you know this kind of pixel buffer because it's always going to be pixel perfect and you get you get so much control over it whereas try and do this if you had raycasts it's not going to work because the geometry is physically there right um so yeah so this this approach is quite good and i quite like it for this kind of stuff okay um so we've confirmed that works let's play with the fade yeah that obviously works as well so see this is what i mean like if we now click on this part it's still the circle right but if we click here that's already not part of the circle because we made it equal zero so i think that's probably a good move um yeah there we go so we can have quite blurry circles um and yeah we also should be able to make them as thin as we want by just making well let's let's go back to like having point zero zero five or whatever and let's make this like point one or point zero one and you can see this is kind of what like a normal thin circle that we might use for visualizing like circle colliders uh would look like and we should still be able to select it yeah kind of hard but we can still click on it select it again it's per pixel so it's literally going to be perfect which is great and then of course as i mentioned you can you can stretch these out now if you do that a lot then these edges are going to distort right so if i finally find this you can see how much thicker this is that's kind of expected because we are doing this in that local space uh you could probably fix that by taking in taking a scale into account or using like shaded derivatives like we talked about something like that um how do i get back to where i was but yeah that's in general that is hopefully uh helpful to you guys as to how you can implement my circles video into a game engine uh let's hit play um do we see the circle during uh playing now we should it's hard to see where the circle actually is no actually we should have seen it then i think let's make it a bit thicker huh we don't see it do we why is it not being rendered during play mode that's interesting so if we go back to scene because i'm pretty sure i added it there so this is update editor this is update run time so this is where we actually do it if main camera then we should be drawing it um this is all in the begin scene thing so it should still oh yes okay so when we do begin saying we need to make sure that we oh no it's just a uniform buffer right sorry i thought that maybe it needed like a per per um a per shader buffer thing but that's not how it works and also obviously it works with the editor camera so very suspicious why this isn't being rendered in oh no it's not suspicious at all it's because i'm not the entity doesn't physically exist in the runtime because i'm not copying it so duplicate entity let's quickly add in um circle render component and then if we look at like another place maybe where we're doing this or when we do run time when we do the actual scene copying which is uh copy then we need to make sure that we copy the circle renderer component as well now we're going to change the system to just iterate through like a list i think or something like that in the future of components and then that way we can not do this manually because of course it's very error prone every time you add a component you have to add it to like 500 different places which is really annoying but that's how it is for now so now we have our circle our beautiful orange circle which i will replicate perfectly um and then if we hit play you can see it here as well okay brilliant so that is basically circles now there's a few things that we have to fill in fill in the gaps of such as the serialization of circles right we want to be able to actually serialize the data again super simple i don't know if it's even worth me doing this on stream or like on video but i i guess i will probably do it at the beginning of the next episode um actually let's just do it now like who wants to watch that right you guys can probably just end the video here if you want after you leave a like um but basically to serialize it we just have to go to the serializer let's look at how we did the sprite renderer component let's copy the sprite renderer component let's call this circle renderer component i'll do this little speeder on this because it it's pretty easy so circle render component color thickness and fade are those the only three things i think they might be how's my speed running going pretty badly thickness and fade circle render component yep okay um whoops that's it uh that looks good and then we do the same thing for the deserialization which is here circle renderer component [Music] so there's our so we'll call the circle render component crc color thickness and fade so thickness is a float and so is fade and that i think is it so add this are these parentheses let's go back to here i just want to make sure yeah call things okay cool so let's try and now just save a scene basically and make sure that works so scenes physics 2d we'll add a circle we'll call it circle add circle circle renderer don't have circle colliders yet soon um thickness let's make that like point one we want we won't make it too thin and then i'll just put it like here or something brilliant let's save this now do we have control s no wait we need to add a control s so assets scenes and physics 2d yes replace get rid of this well we don't have to we could have just dragged it in but i guess this is more proof and it works okay civilization is done thank you guys for watching the video if you did enjoy it please don't forget to hit the like button below and also help support the series by going to patreon.com where you will be helping to support this series as i've mentioned but also you'll get access to the big hazel which i also showed earlier in this video you'll be able to play around with all that stuff in 3d and uh yeah it just lets us keep making these videos so huge thank you to all of your support thank you for sticking with this one hour video next time um i'm not 100 sure what we'll we'll probably just move on to like line rendering or something next time we're kind of doing this rendering thing so we might as well kind of finish that but after that it's going to be like circle colliders and more kind of box dirty physics things thank you guys for watching i'll see you next time goodbye [Music] you
Info
Channel: The Cherno
Views: 18,450
Rating: undefined out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, game engine, how to make a game engine, game engine series, circles, how to render circles, circle shader, rendering circles, opengl circles, opengl circle rendering
Id: OoKCfHERi3s
Channel Id: undefined
Length: 65min 24sec (3924 seconds)
Published: Sat Nov 06 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.