Transformation Gizmos | Game Engine series

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys my name is vicino welcome back to my game engine series it's been a while but we are back and today we've got a bit of an exciting episode because we're going to be talking all about gizmos last time i think we did like civilization stuff check out the video linked up there and today as i mentioned is going to be all about um adding in some kind of manipulation gizmo so that we can actually like translate rotate and scale entities and their transforms inside our scene by using like an on-screen gizmo like much like what you would see in any other game engine or like unit or um blender or any 3d program really so that is uh what's up yeah you guys can say hello youtube so it's been so long you know um i do want to mention quickly that i stream a lot of my development for both hazel dev and and this game engine series version of hazel live on twitch.tv slash the churno that's why i'm streaming this right now but also um you know as as this series gets more complex as we kind of begin to uh i guess go deeper into this game engine and obviously it's going to get to a point where it's going to be harder and harder to actually i guess um you know work out the code that needs to be written and solve these problems this this series is not going to contain me trying to work out problems right this series will be me kind of showing you the solutions that i come up with obviously and how i solve those problems the process of solving the problems mostly i stream live on twitch so if you're interested more in seeing how i even come up with these things or how i decide how to implement certain features then following along with my twitch live stream and looking at past broadcasts or supporting me on patreon so that you can get access to the whole library of past broadcasts it's probably a better like a good thing for you to do um essentially because it'll obviously showcase a lot more of kind of uh leading up to the solutions instead of just presenting those solutions in their final form which is kind of what this is about um so uh that's that's kind of my little disclaimer out of the way and today let's talk about how to actually get gizmos in and i'll show you basically what i've done and this is going to be the result of what i've spent the last couple live streams uh thinking about and implementing so if we take a look at what we've got so far um there were some uh pull requests that did make it in i'm not gonna discuss them today some of them are not that great and we'll we might talk about them later i'm going to have to reverse some stuff but it doesn't matter um for now what we've got is basically this hazelnut editor and if i try and open um a scene here we've got like this 3d example and the reason it's called a 3d example is because the camera i think is a perspective projection camera um what i've added right and copied and pasted is this pink cube.hazelfile i'll commit this at the end of this episode so you guys will also be able to see it but basically pink cube.hazel is this lovely little pink cube that i made during a live stream and i think this was actually while i was planning serialization before i actually recorded those episodes so definitely um you know take a look at that and pull the latest code so you can see this stuff um and this is kind of going to be our starting point for gizmos just because this is going to be able to showcase it a lot more so basically what i want to do today is i want to be able to uh select top right and left you know camera doesn't really matter too much but as i click on these entities right i want to be able to uh you know bring up a gizmo around the origin of where that entity is like pivot point at least is where that transform is essentially in 3d space which doesn't have to be exactly in the middle of all the vertices obviously because the vertices can be completely offset but wherever that transform is which in this case is in this world space position i want to have a gizmo pop-up obviously i want to have translation rotation and scale so that i can modify the translation rotation and scale using an on-screen gizmo as i select these now we're not going to be doing mouse picking today that's a completely different story has nothing to do with gizmos um today is just going to be all about gizmos so how do we do this well you could write your own gizmo library i'm not going to do that um i actually had a bit of a rant on this live stream earlier today about using third-party libraries and how i not necessarily how i decide which ones to use but you know what i think about the whole process of using third-party libraries um tarek thank you so much for your prime subscription does that still that doesn't show up on the screen does it i'm sorry it should um it's just i guess because there's no chat maybe anyway whatever sorry we'll fix that for the next episode tara shout out to you um anyway so uh what was i saying yeah so um you know regarding like third party libraries and all of that um we'll we'll save that for a different day but ultimately uh i'm gonna use a third party library called i'm wismo which basically integrates really well with i am gui to actually render these gizmos now the default look and feel and usability and the way that that library works is not um perfect i think well at least for for what i want and for what i would like gizmos to be like in hazelnut and in hazel um excuse me they uh like it it doesn't it doesn't like i've made some modifications to it basically to make it a little bit better in my opinion so uh what i've done is i've forked it um this is the fork and as usual we're just going to add it as a sub module i've forked it i've uh i have not added um [Music] pre-make to this right but i have forked it and if you look at i guess these latest like this latest comment you can see i've just tweaked a few things here just to make it look and feel a little bit better um so that uh and i don't know like this might need some revision or whatever but i've just changed the look and feel of it a little bit better um because i think it looks a bit nicer and i've changed the tweet tweaked the colors and just minor editions but mostly it's just the imprisonment stuff and this is just something that's been in hazel there for a while so we're going to be using that existing code so the first step is going to be to actually add this as a sub module so i'm going to go into the root of my repository here and i'm going to as usual just do git sub module add and we're going to add that now i never remember the path of it i guess the path comes after that um but basically hazel and vender and then i guess just i'm guilty right i'm quizmo so hazel van der and i think i can just not type in a path i do sometimes you have to sometimes you don't um like that there you go so we've added a sub module um and again i'm not going to compile this as a separate module i'm just going to compile it into hazel because i don't know like in my opinion i think it's it's like realistically i think it's like two um files so what like i just don't think that's worth making like a static library out of so what i want to do um and i'll be referring to like my diff of what i've already worked out during the live streams for all this stuff just to speed this process up otherwise this episode would be probably a couple hours long um so what i'll do is i will um find the uh inside hazel let's find the pre-mag file um and i'll see what i've done here so basically all i've done is to the compilation here just like we we did with glm i mean this isn't really to the compilation it's more like to the project i'm going to do the same thing here but add the i am gizmo stuff so i am gizmo was the directory um and then i think there's again as i mentioned two files there's the header file and there's a cpp file no need to add the examples or anything like that even though they're included we can just keep them still there for reference code but we don't need to compile them so we'll just add i'm gizmo like that and then as far as the include directories go i'm going to specify um the include directory and i think the include directory we usually specify like the list of them here right so when we have all of the include directories in the premade file that is inside our the root of our project i'm going to add this so we're going to do hazel vendor um i am guizmo and i believe um that's it i think it's just there there's no include directory right so that's kind of it i guess we've included these and then finally uh in order to be able to use this we'll also add on gizmo as an include directory um and then finally the last thing i want to do that will stop um uh well it'll enable us to actually not modify uh the files themselves is we have to deal with our pre-compiled headers because obviously every cpp file that is marked as using pre-compiled headers has to include the pre-compiled header as the first include i'm gizmo is not our code technically i mean i've modified it so i could have added the include but i don't want to so what because it's not going to be using any of hazel's code anyways it's like a separate module so what i'm going to do is probably over here i'm going to add a little filter specifically for a file so you can do files vendor i am guizmo and then basically any cpp file in that directory or any subdirectory so i've added that filter and then what that's going to do is i'm going to create a flag that is called no pch that will mark the file as not using pch right so in other words if you go to like a maybe that's a bad example because that is the pch but if you go to like this for example and you look at the pre-compiled header you can see this is marked as use not using pre-compiled headers right is what that will do in visual studio only for that file or only for any cpp files there so therefore we're going to compile without any any issue that's it i think so if we go into scripts and we rerun the generate project script and reload it should be able to see um i'm wismo and we'll control f7 just to test that out uh it should work okay so there we go we've now got i'm gizmo i don't know i'm guizmo i'm gizmo whatever we've got our gizmos so we're going to go into the i'm gui layer now and talk about how we can actually render them and how we can use them api is very simple i really like the library by the way um i mean like as i men i i may have been harsh with my oh i fixed some things in it i didn't really fix things i just changed the style to suit me more and to see what i what i wanted to look like more but props to the author because i think it's a great library it's quite well written um and it does a lot of math stuff that i would not want to be scratching my head over for sure okay so inside i'm gooey layer i'm going to include i am guizmo because we basically have to call something at the beginning of each frame um after we start the imgui new frame what i want to do is call which is actually here i want to call i'm quizmo begin frame because again it taps into imgui code which is great because it's part of like our ui which is the gizmo so it should be i don't want to be i don't want to like you know um it's really nice to have it tie into i am gooey's draw list and all that stuff like that's really nice because it just ends up being part of our ui pass instead of being like some kind of separate opengl rendering thing so i quite like that also means it's quite efficient because i'm going obviously batches everything together and it is rather efficient um so now that we've done that right all we have to do is basically use the gizmo now um so if we go back to our editor layer which of course is like our layer where we draw the viewport and do all of the fun stuff what i want to do is um actually start drawing the gizmo so if we go over here to our viewport code and it's probably worth bringing out maybe some of the viewport stuff because this is going to be quite annoying but basically before we end because we obviously want to draw it in the viewport um we're going to do our gizmo stuff here so i'll just have a little comment called gizmos zoom in a little bit how's chat doing everything fine yeah that's good sweet sometimes i like to check in on chat a bit because when i get when i start recording these these episodes i just get lost in my own little world as if i'm recording a video i'm not even live streaming but i am live streaming so the the important thing for us now is to select an entity right like we want to know what is the currently selected entity because obviously that entity's transform is what we're trying to control so how do we get the currently selected entity um and i'll just call this selected entity well that's where our api falls apart because at the moment we basically need to ask the scene hierarchy panel hey what is your selected entity now whether or not that should be like that is debatable because in the future when you for example mouse pick to select entities that doesn't really involve the scene hierarchy panel you need to tell the scene hierarchy panel hey i've selected this entity so please display its properties selected in the tree all of that stuff but at the moment our only source of selection that exists in this whole thing is inside the scene hierarchy panel so i'm adding this here um the way it works in hazel dev is there's basically a series of callbacks right so every time you select something in scene hierarchy panel you can kind of subscribe to that event and receive a callback when the selection changed because it was kind of like an unselection changed event and then vice versa as well you can tell the scene hierarchy panel hey i selected this entity so it always should work both ways because there's obviously going to be cases for both of these things to work this is annoying this is probably another pull request i might deal with that later okay so um and this is really easy because we have a selection context so really all this becomes is entity get selected and here i'll make this a const function and we would return that and thank you visual studio okay so that's done now we have this get selected entity function we know what we've currently selected now rule number one is is anything selected so obviously we can just check that with a simple if statement is this a valid entity or is it not right so if it's a valid entity so it exists it's not zero it's not it's not like no entity we can actually start setting this up for drawing so um in terms of i'm gizmo we basically need to set orthographic to false we will be setting this to true in the future for orthographic projections the first step and what we're going to do today is make it work for perspective projections just because it's a little bit easier to know what we even want to do in the first place and let's also obviously include i am gizmo i am whiz more you're happy no you're not you know why because this is hazelnut so let's go back to pre-make um and add this as an include directory into excuse me into hazelnuts pre-make file i don't even know if that was like in the diff i didn't don't think i noticed that there you go so it's not completely scripted um all right so uh now we should be good um unfortunately it's reloaded everything so i don't know where i am here i am i set all the graphic to false and then we'll do i am quizmo set draw list right um which i think uh you know you just call it before manipulate to draw gizmo to that window that's it and then um we need to set basically like the viewport so set rect and this is where things are going to get interesting so we want to basically get from from i'm gui get the window position i'm not 100 sure what the best way to do this um because i don't know like apparently in my diff i've written it as get window position [Music] y and then i've also got the window height so window uh window width is i'm going to get window width but like i've used get available content area before or get available content region or whatever it is and i'm gooey sometimes the api if i'm going can be a little bit all over the place just because they seem to have a bunch of functions that do the same thing but maybe they don't maybe they include padding maybe they include like little title bars so i'm not sure like this this not guaranteeing this to be perfect but it should be okay for now so we're setting the rectangle now this is like excuse me coughing a lot today um setting the uh like the the viewport in a way um and then we need to um basically draw like the gizmo and to do that we need to basically work out like where the camera is right because obviously the camera is going to define how we render this let's we have to set the view projection matrix basically um and then also get the transform from the entity which is kind of the easy part now the camera part that's where that's where it's a bit tricky at the moment we don't have a camera and we don't have an edited camera we've only got like a runtime style camera which is really a camera component right on an entity so we need a way to get the active camera right so what i did um for this is i basically was able to retrieve the camera entity by adding a function to our scene so to our currently active scene and i called it get primary camera entity which might seem a bit dogecoin and uh i don't blame you if you think that but um i don't think it's that bad um basically this is a bit of a convenience function to just be like hey get me the primary camera um and specifically the entity that the primary camera is attached to so the way that that's implemented is quite simple we just simply uh create a view so registry view uh with our camera component and then we cycle through the view because remember we're not just looking for the camera we're looking for the active camera for the primary camera because we can have more than one camera in the scene but only one obviously um is being rendered at once so we'll we'll iterate through that we'll retrieve the camera um which is actually like uh actually no this is the um camera component for the current entity so let's maybe make that a reference const reference maybe um and then if primary is set to true we'll just full-on just return it so we'll have to construct a hazel entity out of it which as we know is just the entity id and the current pointed to the scene which is our context otherwise we'll return just an empty entity that's it easy so now if we go back to editor layer we should be able to get the primary camera entity which of course is uh the case so next step um so this is trying to get our camera um the next step is going to be to uh well let's get the camera component from this right so now that we've got the entity let's get the camera from it so get component camera components i hope our camera has everything we need by the way i haven't really checked but basically what we should want we what we want to get is the camera view matrix um because that's what the trend that's well no actually the camera view is going to be the tran the inverse transform of the camera so the invert the transform components transform the inverse of that um so actually this is going to be glm inverse uh camera entity dot get component transform component uh get transformed speaking of which i think there was one thing that i wanted to adjust here at the moment we're kind of um actually creating the matrix like that right um but i think there's a better way to do it an easier way to do it with the api because i i changed it to that so i think all you really have to do for rotation instead of doing this is just do glm to mat four from the quaternion i think and you can create a quaternion from those euler angles like that so that just looks a bit cleaner right there's our rotation um and i think for that we we do need to um include some maybe this wasn't a better solution but we'll need them anyway so we'll include the experimental stuff um because we'll be including something from gtx which is like the experimental stuff so glm gtx plutonium quaternions are experimental so i mean you know it doesn't really mean it's like dodgy or anything um okay done so next step um is uh now that we've that was just a bit of a side thing but anyway we've got the camera view the camera projection though we should be able to pull out from there and i think that's just going to be camera get projection um which doesn't exist so see this is what i mean i might have to ah actually nah it does exist good might as well get the camera here that just avoids this so glm matt4 and is that a what does that return a const okay sure so cons reference camera projection so we've got the camera projection we've got the camera view right so now we've got everything we need basically to render so let's get the entity transform now so from the selected entity selected entity we can get the transform component um and i guess we'll just do glm not for uh transform equals tc dot get transform okay so that's using the function that we just basically modified a little bit to add the quaternion map for thing all right hopefully that's not slower than than the code we replaced but it looks cleaner so that's why i went for it okay so now i mean there's some other stuff that i've got here that will add later like snapping but um you know for now we'll just do i'm gizmo manipulate so basically long story short we set the autograph to false because well you don't need to do this every frame i don't think but um we're doing it because we might alternate between orthographic and perspective based on the camera obviously we set the draw list so that it draws the current window we set the rectangle that's our viewport and then we call manipulate this is just us getting the data we need for the manipulate function which is what actually is going to deal and render our deal with i was going to say and render our um gizmo so we want to do glm value pointer the first parameters you saw was the view so we'll pass in camera view we're just doing value pointer because this wants a float pointer then we will do the same thing for the camera's projection so camera projection right then the next step is the operation okay so for now we're just going to do i am gizmo operation it's just to translate okay but we will obviously um keep track of this and we'll be able to switch this up to um you know rotating scale based on like a hotkey so the mode uh local is pretty much all we're going to do for now we want to be in local space um and then the matrix is going to be the whatever we're trying to transform right so our transform matrix so we'll just pass in transform um after that uh we've got a bunch of other stuff like the delta matrix which we don't really need for this and uh snapping which we'll leave off as well that's it okay so if this if something changes here where what we're going to have to do right is reconstruct this matrix now so we've obviously inside our component we store these separately so we convert into a matrix i'm quizmo manipulates it and then we need to decompose it back into the individual um deconstructed matrix thing so translator rotate and scale so we'll do that in a minute let's just see if this renders anything that would be nice how streamed doing just talking about other stuff that's cool um okay so let's go to our pink cube and it's already failed um oh that's because this was wrong um so if you actually look at this um i think that this should have been zero and this should have been was it 45 i don't remember what it's supposed to be oh and this should be zero no how do i get it to be oh maybe they both are 45 or something like that i don't remember i'm trying to hack this um oh there we go 19 45. there we go so it's just because our rotations were in the wrong order before so let me save this as the pink cube why don't we have a normal save anyway whatever so now you can see beautifully right whatever i select we see a beautiful gizmo right top camera camera you can't really see it because we are the camera that's what we're looking through um now right oh that's a that was a bad move you didn't see that we'll deal with that later um [Music] uh so yeah whatever we select we see a transform and more most importantly you can see it's at the origin of this mesh right of this um actually it's a sprite but it's like you know it's a vertex it's a piece of geometry right it's at the center because we know that our coordinates are from negative 0.5 to positive 0.5 so this should be in the middle um and obviously the camera's projection and everything is working properly because we see it in the right place now if we try and move it it's not going to move anywhere because we're not doing anything yet right that's where the next step comes in so let's do translation first because it's easy so technically this whole thing is easy right because once we've got this this transform matrix has been modified so we can just do a little check first because remember this runs every frame this manipulate function doesn't just manipulate our transform it also renders it so we need to know whether or not it's actually been used because otherwise we don't want to be continually decomposing and setting our matrices and all of our transforms if nothing's changed so there's a nice little is using function and if using is true that's when we want to apply the changes so what we'll do is well for this this is the easy case right for our translation this is as simple as just um getting from the transform right uh the last column and it's going to be a back four can i just cast that to effect three probably like is there a constructor that takes that in maybe maybe i can just do that we'll see if that works yep okay so now you saw that was really easy obviously keep stressing that um magic right look at that everything works right our trend well not everything but translation works perfectly fine i can move this wherever i like let's maximize this make sure it still works it does i can move this wherever i like select something else move this wherever i like and you can see that it works beautifully right that's exactly what we want to see and then the left one as well right okay great so that obviously works um now how do we do it with a rotation scale well different ball game a little bit more complicated than just this so scale is easy scale is just the length of the diagonals um length of those vectors um so that's pretty easy but then we have rotation which is a bit harder now the thing is glm actually has a function called decompose which takes in a matrix and gives you a whole bunch of stuff and i mean a whole bunch of stuff right it gives you the scale the orientation the translation that's what we're after right but then also the skew and the perspective which we're not after and furthermore if you look at this function which i did during the live stream there's like to do fix me and i notice that sometimes this just returns false which means none of this actually works not to mention that it does a whole bunch of stuff like tries to figure out figure out the perspective and you know runs like inverse functions and does a whole bunch of expensive stuff that we don't care about so i took the liberty of copying this function and stripping out everything that i don't care about and just keeping the stuff that i want so i got rid of skew and i got rid of scale and i also changed the quaternion orientation which is this code to just be their kind of commented out euler angle one because that's at the end of the day at the end of the day what we need anyway so if i use this version i would have had to have converted into oil angles anyway right and uh i came up with my own little decomposed function which i'm going to copy and paste and then kind of go through roughly because i'm not going to type it out for you but if we go into hazel make sure we're in show all files mode inside source hazel i'm going to add a little folder called math and inside there i'm going to add a header file also called math and this is just kind of generic because we don't really have a math library we'll include uh no i've ruined everything i'm gonna reshoot the whole episode um so this is just gonna be a bunch of math functions basically and we could hide this by math name space or something like that i don't really care maybe i do hazelmouth maybe maybe because it's not i'm i'm not planning to put this i didn't do this during the live stream but maybe i'll add a little math name space um just to hide it behind that um but basically this is going to return the same thing as the glm one i'm just going to call it decompose transform right because it's not going to do anything with perspective or you know anything like that it's just going to be translation rotation scale which is a transform so i'll take in a glm.4 transform and i will take in a vec3 uh translation and this is what we're outputting this is like our out translation i guess i'll call it that just to be completely um obvious rotation slash orientation kind of the same thing in this case and scale out scale so that's kind of what it looks like um nice big function and then we're going to implement it in a cpp file so let's grab this math.cpp include our pch include math namespace hazel math i guess i'll do that um uh and then we'll copy and paste it from my diff so let's grab that all right um i left this in here because i'm not sure if we ever need this um and it didn't bother actually working out but we'll do this here so you need to include the whole matrix decompose thing also which is this let's talk about this briefly so what did i do well i left a comment saying what it's from just in case someone needs to fix it or change it um i added using namespace glm so because in their code it assumes that and i didn't want to add glm everywhere inside this function and also did using t equals float because originally it is a template function um which runs i guess for like a different amount of um different data type or different um i don't know like it's it's just it's it's templated but we don't really need that so i just kind of added a using t equals float here because we're going to be using it with floats just so that i wouldn't have to replace t absolutely everywhere as you can see in this function but ultimately i just stripped the stuff i didn't need and as i mentioned uncommented out this rotation code that's it really simple um and it should be a lot faster than their matrix decompose as well because obviously um obviously uh theirs does a lot more and it's not cheap some of the stuff that it does so yeah anyway that's that so now in editor layout i will include hazel math math right and the idea here is instead of using uh this translation like this we could do that but we'll be a bit more obvious we'll do um uh math decompose transform so it's hazel's math function now transform will be the transform and then we have glm vect3 translation rotation scale translation rotation scale now by default these won't be initialized obviously so just keep an eye on that um but this should set all of them as far as i'm aware because the only it might return here in which case it doesn't set all of them but otherwise it doesn't return whereas the glam one returned in a bunch of places and that actually um had me stumped a few times anyway so now we set translation to this translation which again is the same it's just more of a convenience thing but we also have rotation and scale now here's the thing with rotation um if you don't if you just get the rotation from the matrix you can easily wind up with gimbal lock really easy way to fix that as far as i'm concerned um is to just apply rotation as a delta right so instead of apply because that that way you're always just adding something you're never gonna wind up um with uh something being locked because of like an equation because you're always just adding an angle so to do that um we basically need to store the original rotation um which is easy because our transform component already has it right so when we get our transform component in here right we can just do glm vect3 original rotation equals tc dot rotation easy right and in fact if you really wanted to i guess you could do it here because the transform component hasn't been set here and then we can do actually we can just do delta rotation which is going to be our decomposed rotation minus the transform component's original rotation that's our delta rotation and then we can just say rotation plus equals that delta okay this is perfect no gimbal lock no nothing everything will work as expected okay finally scale tc dot scale equals scale and that's it that is our whole gizmo situation now the only thing i would love to do is be able to change what gizmo is currently active so let's see how we can do that now this stuff um honestly we could store this as just an ant i guess so if i go over here um and i'll do int gizmo type equals negative one which means no gizmo right because translate is zero rotate and is one scale is two and there's also this bouncing which we're not using uh which is three but um if we just replace this with i am gizmo type and we cast this to an i'm gizmo operation we can also have that kind of nun type which is negative one so um we only want to draw the gizmo if the selected entity exists and gizmo type does not equal negative one right so if it's actually a gizmo let's let's draw it right so the cool thing here is that if i now want to um you know look at the rotation gizmo which i think is number one right well actually what i should do is actually use the enum so rotate let's see if that works i should probably just have it load the cube by default there's our rotation gizmo should be able to rotate stuff now and you can see i can um and everything seems to work perfectly and you can watch the rotation obviously over here change now you might notice something um if you're um looking closely here these never go past the kind of negative 180 to positive 180 range the reason is that with a rotation obviously zero degrees is the same as 360. it's the same as 720 etc right you kind of have this situation where to solve a rotation equation obviously like there are multiple solutions um and uh i mean hopefully that makes sense right so um a lot of a lot of engines and 3d programs like i think blender unreal and unity all have this kind of concept of a rotation that is past that range so you can have a rotation of a thousand degrees actually show up here and it will make sense and you can see that technically speaking if we do this ourselves using this it's gonna work because at the end of the day remember this is just a vec3 right so you can see we have a thousand degrees but what happens now if i start rotating this well technically this is equal to about well that was equal to like about zero degrees or whatever but you can see in general that um this is this also is the same as that minus 360 degrees minus 360 minus three whatever so if i start rotating it now and you watch this value here right this all works as as expected you can see nothing weird happens with the rendering but suddenly this is snapped down to 25. now whether or not you want to keep it this way is i think up to you and your engine i think this is fine because fixing this problem as far as i'm aware is kind of a complex issue and i was not able to come up with an easy straightforward solution i think this what i've written here is quite straightforward um so i'm going to leave it as is for now programmatically doesn't matter because that rotation is going to be identical to all those others and you can see that i can you know this does not stop me from you know interacting with everything else as usual it just finds another solution usually one that's inside that unit circle so um therefore i would say it's fine programmatically if you want to increase this like just have something that increases the angle by one degree every frame or 10 degrees every frame it's not like you have to check to make sure that if it's above 180 set it to negative 180 otherwise everything will break it's not going to break you can see right um go.engine i noticed also does this they don't go past 180 degrees with gizmos and stuff like that right um but everything else that i could find does and so i just chose this this kind of solution because it just happened to be really simple as you saw and everything seems to work fine okay so that's that um look at me trying to switch gizmos if it works let's make that happen eh so to switch gizmos um we should just add a little uh you know key code thing here so um at the end of these things let's add our gizmo shortcuts so i'll do gizmos um so case key q so q um i kind of like these controls q w e r so these are from like i think most 3d programs but i remember this in like 3d max and maya and everything really um blend just has their own kind of you can use g to just move stuff without having to use gizmos and i don't think that gives them a shortcut the same here but um q is kind of your selection tool so it's just nothing w is translate e is rotate r is scale so it's kind of like q w e r uh your kind of select and then trs translate rotate and scale so um this is as simple as just setting the gizmo type to negative one if it's q because that's our selection tool that's no gizmo at all and maybe in the future when we have tools we'll rewrite this um and also this maybe should be customizable shortcuts as well but whatever for now um w is translate so we'll set it to i am quizmo operation translate um and then obviously this is going to be rotate and scale so scale rotate isn't this just all really easy i love it when programming is just as simple as adding that stuff in a matter of seconds you know it's good it's always good when you write code like that um now uh none of this works because i am still setting it every frame so let's remove that someone said that's why most engines use radians i'm using radians as well has nothing to do with radians radians are just a different a different unit it's kind of like meters versus centimeters right or i guess celsius and fahrenheit also that's a bit different there's a direct conversion between an easy conversion i'll say between radians and not radians it's the same thing it's just a different unit um we're storing everything in radians we're only converting to degrees for uh for this view here so if i look at um [Music] pink cube that took me too long um this view here is in degrees but internally it's all storing this in radians like if i uh look at i guess this is fine where's my transform component here you can see that the rotation for the selected entity is 0.78 that's equivalent to 45 degrees i think um so uh it is actually in radians right it's this one here 45 degrees okay anyway um yeah so now right q you can see gets rid of the gizmo entirely w r beautiful let's test out scale works perfectly fine we should be able to move this somewhere now let's move it over here um we can rotate it wherever we want we can scale it non-uniformly everything seems to be fine right uh we can scale it to zero and everything's fine doesn't break um and then scaling it up will take a little bit of time but there we go right everything seems to work so um you guys can play with this and try and break it and then we can fix any bugs that come out of it but for the time being as you can see i think i'm pretty happy with it now the last thing that we're going to add this is a long episode isn't it we haven't had one in 43 minutes okay good i'm happy this is this makes up for like the fact that we haven't a big juicy episode makes fact makes up for the fact that we haven't done an episode in ages um but uh the last thing that i'm going to do is uh add snapping to this right so if i hold the control key down i want to basically snap to angles of 45 degrees or like to maybe 0.5 meters if i'm translating or scaling now pretty easy to do this should be configurable in the ui maybe you don't want to snap to 45 degrees maybe you want to snap to half of that maybe you want to snap to 90 degrees i don't know um it's totally something that you should be able to customize i think um so what i'll do and why do i have this there we go this is a little hand cursor for ages um i see every program has problems so don't don't be too harsh on hazel um so what we'll do is uh maybe over here we'll we'll deal with snapping so i'll first of all whether or not we're snapping it's going to directly uh depend on whether or not at the time of us rendering the gizmo is key pressed um and we'll just say the control key i think left control right so that's if snapping is enabled or not now the snap value that's what you want to snap to we'll set to 0.5 however totally going to depend on the tool right so 0.5 might be good for translation and scale but for rotate 0.5 degrees bit silly right so what we'll do is we'll say um i could write this as like a ternary you know but this will probably be easier um if uh m gizmo type equals i am gizmo operation rotate snap value equals 45 snap to 45 degrees for rotation snap to 0.5 meters for translation so um hazel uses meters for units in case that's not already clear um [Music] i think most game engines probably do um okay so we have a snap value beautiful now we actually need to create like a little um float array out of it so that we can do it for x y and z because you can actually i'm gizmo lets you set a different snap um value for each uh axis but that's probably not that um useful most of the time so snap values and then we'll just do snap value snap value snap value because that's what i am going to wants and then we just um pass in snap values into manipulate if we need them so this i think is a delta matrix which we'll leave at uh null pointer and then if we're using snap we'll pass in our snap values otherwise we'll pass a null pointer and that should in fact be our snap argument and it is all right so hopefully now if we hold the left control key down we will snap now obviously this will snap based on where you currently are it's not gonna just it's not gonna be like a world snap maybe that'll be a good feature as well but ultimately what this means is that if i'm at 0.6 and i try to translate with snapping it'll move me to 1.1 not to 1 or to 0.5 so if i select like this one and i move and then i hold ctrl a you can see that i now snap to place and you can see over here that i'm at 0.35 x and if i uh hold ctrl and by the way you can start moving but then halfway through hold ctrl which i really like because you can see that's perfect and you can see that this is all is a one by one quad so one by one meters which means if i do two increments with snapping on i'm perfectly at this edge and you can see the math here work out perfectly might be uh slightly incorrect or whatever no actually i don't think it was that it was this is this is displaying to that because you can see that's a bit off now this was displaying to two decimal places which was not um which is not obviously that accurate as accurate as what it actually is uh because i think if i load that again and we look at this one well it's still explained to two decimal places here anyway whatever i give up anyway there we go that works and with rotation again if i start rotating hold down control there's your 45 degree increments and you can see the degrees drop here even throws it up in radians as well which is nice all right beautiful so we've got snapping what more could you want perfect right so there you go that is that is gizmos implemented what do you think chat stream you happy um let's bring the let's bring the chat in um ah the chat's gone i deleted it that's that's a bit um unsettling it's back though all right so that is that's that right it's really not that difficult when you're using a third-party library that you have already modified to uh look nice and to you know to work like you want to and you've spent the time to work this stuff out and you have your own decompose function and everything else has already been done for you it's pretty easy um but that's basically it um i i'm gonna quickly look through the diff to see if i missed anything oh yeah one thing that is really annoying that i noticed is that basically the way this is set up at the moment is that if i um well first of all let's just try and activate a gizmo here okay doesn't matter it's not gonna crash or anything which is good if i load pink cube um this is really annoying i'm the right gizmo here right i've clicked on left to select it e r doesn't work even when i'm hovering over the viewport wei doesn't work until like click and then it works now this is already a problem because when we have mouse picking we can't just click arbitrarily on the viewport because that's also going to probably do a raycast and pick an object so that's super annoying um and the reason this happens is because i'm a fool who accidentally doesn't understand how logic works and wrote this little piece of code here so when we block events i did viewport focused all of you but hoverboard is both files what we want is to only block advance if neither viewport focus nor viewport hovered is true so in other words if you're neither focused on the viewport nor are you hovering over it so actually this should be and because what we're looking here for here is we want this to be false if either of these are true and obviously they have to both be true for this to be true and thus block events is true so yeah a little bit sometimes they can be a little bit annoying these things um okay so now if i do this basically it's a really really subtle thing but now the cool thing is if i do this right w e r not working because i'm hovering over scene hierarchy but as soon as i don't have to click on it as soon as i hover there you go see it immediately gets set as long as i'm over the viewport i think that's how blender works as well um but you can decide how you want to do this yourself um in hazel there we have something a bit more sophisticated because i think that if like you're maybe typing the name here but you're hovering over here you can see it still changes um and you can actually fix this by seeing if i'm gui has the focus of a particular control we're not going to cover that today hazeldev does that though um but yeah otherwise there you go gizmos knock yourself out um uh yeah they'll always be dependent on i think the size of the screen so you can see they're kind of kind of small here but you're not really going to be doing that and then here they get kind of big so they're kind of in the screen space size i guess um but yeah that is your whole gizmo situation and as you can see everything seems to work pretty well and that is gizmos so hope you guys enjoyed this video if you did please do not forget to hit the like button or subscribe on twitch um patreon.com is the best way to help support this series and also get access to the hazel dev code which is really exciting take a look at the latest hazel devlog i'll have it linked up there as well um we've got like shadows now and i'm working on some other really exciting stuff that i can't wait to reveal so everything's going really well doing tons of work on this we've got a wonderful community of people and i'm so happy with everything that we have been able to achieve and thank you so much to all of you for your support and make just helping to make all this possible it's just amazing all right next time what i don't even know what we're gonna do next time i never know because we've done like this now oh we should look at the road map we'll look at the road map at the beginning of next episode and decide what we're doing don't forget to follow on twitch as well if you want to catch the latest live streams and twitter as well because i usually announce live streams there i will see you guys next time goodbye [Music] you
Info
Channel: The Cherno
Views: 44,353
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, gizmos, manipulation gizmos, transform, transformation gizmos
Id: Pegb5CZuibU
Channel Id: undefined
Length: 52min 23sec (3143 seconds)
Published: Thu Dec 03 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.