"Step by Step" Procedural Animation

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video I'm going to be talking about procedural animations and showing you how to create a procedural Walk Circle that you're seeing now I'll be showing step by step how I've created this in Unreal Engine but most of the concepts will apply to any engine whether it's a custom engine Unity or whatever you may be using I would recommend watching this video in full first and then trying to attempt it for yourself and maybe referring back to the video if you get stuck because most of what I'll be talking about is the thought process behind how we get to the end result rather than specific steps that you must follow every single time and hopefully after watching you'll be able to apply the same kind of Concepts to figure out how to make the procedural animation that you need for your project so to summarize what procedural animation is its animations created using a procedure and that means logic and variables as opposed to keyframed pauses that you would get from traditional animation so because the animation is based on logic that means it changes when you change the input and the variables and one thing that you could count as the input is the environment so if you change let's say the height of a step the procedural walk animation can deal with that by raising the like higher or if you choose to change a variable that's part of the system such as the stride length then you can change that and the animation will change based on what you've changed on the inputs what this means is that once you've set up the system that you need it can apply to many situations so you don't need to make an individual animation for every single possible step height or every direction they might be moving or any Direction they could be facing while they're going up the steps you just make the system in the first place and then it can adapt to many different environments so to start off with I'm just going to explain some of the concepts that I'll be following some of the techniques I use so to begin I'm going to start off by drawing a photorealistic spider and what we want to do first is to make his legs actually meet the floor so to do that you find the position of his foot and found some point above it let's say 50 units above and then found a 0.50 units below and do essentially a trace line from the top point to the bottom Point see where it hits something and that should be the floor and that's where you will place the foot then in the next stage we're going to imagine that he's moving from left to right and we're just going to lock the feet in position so this leg will actually be here and it will be locked back in place so it's locked in World space so wherever it is in the world it will be locked there and that will be the same for all Feats wall feet will be locked where they originally started even though the body's moving and after that step what we'll do is intermittently move the legs forward so from where they are when they're locked to where they want to be which is the best pause where they are in The Baseballs when they're relaxed however if we move it to where they are currently that's already too late as soon as it lands there the spider Carries On Moving and the foot's too far behind so what we instead want to do is predict a point where the spider will be in the future and move the leg from where it is now to where we predict it to be based on its current velocity and then instead of the foot just sliding from one place to another and along the floor at the halfway point so let's say 50 of the move we'll just add some height to it just so it lifts up and we'll do the same for each leg so they're lifting an arc and it looks a little bit more natural and it doesn't look like they're just skating along the floor I'm using Unreal Engine 5 but if you're using a previous version you may need to enable control rig from the plugins menu so the first step is to right click go to animation and click on the control rig and select control rig as the parent rig and I'm going to name this spiderwort control rig and open it up and right click anywhere in the graph and search for set Bond transform or just set transform and Link the execution path up and currently there are no bonds to use because we've not imported the rig so I've got to rig hierarchy and click import hierarchy and select your skeletal mesh click ok and now you should see the mesh in the small viewport as well as all the bonds listed underneath and so now when we go to the drop down of name we've got all the bonds that we can select so I've selected pelvis and now we need to plug something in to transform so right click and search for get transform and select the same button which is pelvis and plug in the transform and now things are back to normal and we've not modified the values so up in the drop downs for transform and plug in rotation and rotation translation translation scale and scale and things about normal again and then on translation do an add vector and put in some number and you should see that the whole rig moves so now what we're going to do is we're going to find a point that's above the pelvis and below and do a trace line or a sphere trace and find way into six which should be the floor and then position the pelvis at that location so right click and do sphere Trace by Channel and for the start point we're going to do the pelvis location plus 150 on the z-axis and for the end position we're going to do an add Vector again but this time we're going to do negative 150. and plug that into end for the end of the trace and now plug in the hit location to translation and now you can see that the pelvis has snap to the floor so if we right click on the skeletal mesh and go to create animation blueprint open up the animation blueprint right click search for control rig plug in the execution path and for control V class on the side search for your control rig class that you've just created compile and it should be working so now drag in the skeletal mesh and in the details panel you want use animation blueprint and in the animation class or anim class you want to select the animation blueprint you just created and then if you simulate you should see that the mesh is snapping to the floor using the trace line if you open up the console and type control rig debug you'll find this a.mnode.control rig.debug set that to one and that allows you to use debug drawing so in this case I've had a draw line and I'm just going to plug in the Tris start and Trace ends to the A and B so then we'll see a line which represents what the trace is doing although this will be drawing a line when the trace is actually sphere Trace but we'll be able to see the path that it's taking so now when you simulate you should see a red line that's from above the pelvis to below and that's what it's using to find the floor and then it's snapping the pelvis to that location so I'm going to remove the jawline because we don't need that now clean things up a bit and next we're going to search for basic arcade and plug that in and for the effector item that's the end point of the leg so in this case it's l and Scott foot and then for Item B it should be the bone above that which is L and score calf in my case and then for item a you want the top Bond the top bone of the chain which is L on the score Phi and as you can see that looks uncomfortable um but we haven't set the effect to Target so search for get Bond transform and search for the foot bone and plug the transform in and something has changed and it's trying to position the foot at the end point but the rest of the bonds don't really know which direction they should be facing because we've not set the primary and secondary Axis or the pole vector so for the primary and secondary axis you can figure out if you look at the skeleton which direction the bonds are facing and this may differ between different 3D programs I'm not entirely sure um I think blender will always do it consistently but I'm not 100 sure on that either um so you kind of you can figure it out this way or what I usually do is just brute force it and take guess at some numbers so in my case I know it's zero minus one zero and then it's one zero zero and it still looks wrong because it's going through the floor but that's because we've not set the pole Vector so another high quality diagram I'm going to show what I usually do to find the pole Vector so if you found the top of the fire and the foot and the halfway point between the two and then you project forward to where the sort of knee joint is and you keep projecting that same line forward into the distance and if that's where the Ikea Target is things usually work out okay um I'm not going to do that in this case I'm just because it's a spider the elbows knees of the spider can all Point straight up so I've just put in for the pole Vector on Z 10 000. so now you can see that we're back to square one everything looks the same even though one of the legs is actually using arcade but you can't really tell which one is because it looks as it would in the default pause now what we're going to do is another sphere trace and for this one we're going to trace above and below the footpoint and use the hit result to decide where the floor is so if we get born transform set to L and score foot get the translation add some number to it I'm using 150. then add again and do negative I don't know 150 again for the end point and hit location we're going to plug that into the effector but we can't plug it in directly because we're using the transform so drop down buff plug rotation in scale but for the translation we're going to plug in the hit location so now you'll see that this one leg is actually meeting the floor as he ever likes uh intersecting and when it goes up the ramp you can see that for a short part of the ramp it actually lifts up the leg but then it drops down again because the start of the trace isn't high enough I'll increase the value so 450 and negative 450 so it traces from higher and lower and now you can see that the leg lifts up quite a lot when it goes up the ramp and exclusive like on the recording that'll disappear shortly but you get what you pay for so now I'm going to Loop this process so I can do it for all the feet so I'll create a for each nod and search for get children and this will get all the children bonds of the selected bone so in this case I'm going to use pelvis as the bone because that's equivalent to the root bond in my case and you want to make sure that you tick recursive and what that will do it will search for all the children bonds of the children bonds so now we've got every bone and you can limit the tap to search the bond if you want plug in the array to the for each Loop control drag on the execution Puffs to move them like that if you want and so from the element this is basically looping through every single bone so now we want to check if the name contains the word foot and so all of the endpoints of the legs I've named foot and create a branch plug it in and if true continue on so now it's limiting everything it does with the iCare to bonds that are named foot so drag up from the element and do get parent and this should be the ball and above it which is the calf proceed to create comments and then the parent of that and that should be the Phi so now we want to replace all the bond names that we've put in directly with references to these bonds so the cuff should replace atom B Phi replaces item a and the effector atom that's just the foot and that's the one that we're currently looping through so we can just plug that directly in from the element and now we can see we've made a squid um so at the moment they're all pointing to the same place they're all targeting where the Ellen's got foot is because we've not replaced these references yet so plug in the element to both of these and then each foot goes to where it should be so now if you simulate you'll see that the same thing applies to all the feet so both of the front legs lift up until the trace doesn't work um and I think if you move up and down the mesh you'll see that the feet are still trying to stick to the floor and the pelvis will snap to the floor if it gets low enough because of our trust where we're setting it to the floor so what I'm going to do is after we've do the sphere trace for the pelvis I'm just going to add on some numbers so it's not literally on the floor it's just raised above some distance from the floor so in the Z I'm going to add on 150. don't know I keep using that number um but I'm going to use an if which is essentially a select and if the trace is true if it hits something then we use the trace result otherwise we're going to use default translation of the bone and I'm going to just increase these values so it traces from higher and lower so now we can see that the pelvis is actually raised off the floor maybe too high but so there's an issue with the foot back here and it's caused by tracing from straight above the foot to straight below but the legs not actually coming from straight above or below so you get issues like this where if it goes over an edge it can snap down and the leg will actually intersect the geometry to fix that we can change the start of the trace to being a point that's closer to above the pelvis rather than directly above the foot so in the traces that we use for the feet I'm going to make a change to the start point so instead I'm going to search for pelvis for the bond transform and now you can see that did not help um so I'm going to undo that and I'm going to copy it instead and search for pelvis separately and we're going to interpolate between these two vectors so search for interpolate plug buffing and the t is the percentage between the two so I'm going to do 0.5 so that's halfway between straight above the pelvis and straight above the foot so now when we try we should see that if you remember to simulate before moving it we should see that the feet the legs not intersect they'll reach the edge and then it will fall off when it's got room to fall off and we don't get the intersection as much it's not perfect but for our users it's a good approximation everything's still working as it should and the legs are just snapping into place at the minute but we can see that the Ikea is working and each foot is actually meeting the ground so back in control rig create a setup event if you don't already have one so right click search setup event this is the equivalent to begin play from blueprints and we're going to copy the get children for each contains and the branch and also the get transform interpolation and the trace so we're going to copy all of that and move it up to the setup event and what we're doing here is we're going to save each foot location the initial location to an array so to do that we need to put the hit location into an array so we create a new variable so on the left click the Plus and give it a name so I'm going to call it World locked foot locations and you want to search for a vector make sure it's a vector and on the side panel make sure you've got it set to array so I drag it in search we get to add and we're going to want to plug hit location into the element but we're going to use the if or select um that we've used before so it's essentially doing the same thing so if there's a hit result we will use the hit result if there isn't we'll use a default Bond position so I've just copy and pasted that there result goes into element so plug in hit the condition so if it's true we'll use hit location and if it's false we will use the default position so that should be the default position of each foot now we should have an array that has eight entries one for each foot with their location so now where we do the basic ik instead of just plugging the translation in we're going to unhook that and drag in the get World whatever locked locations such forget or at and plug that in and now because the index is zero we've made the squid again because they're all pointing to the same place and also they're all pointing to a place in the global space which is actually rig space different to World space so in a setup event after the condition search for two world and this converts it from a global or rig space to World space the opposite of that is a from World which does the inverse and we're going to use that now to take it from the array back to the rig space so I'm dragging the from World node and now you'll see that they're all locked to an actual World position so when we move around all the feet are targeting the same place now what we want to do is make it so that each individual foot is targeting where they want to be so we need to get the index of the foot but from this get children nod if we just use the index from this array that's including every bond in the hierarchy not just the feet so create a new integer and I'm going to call this current thought count and make sure that this is an integer but not an array and before the loop we're going to set that to negative one so that when we increase it later the first one will be zero and the second will be one and so on so if it fans a foot successfully drag in the current foot count and do set then cut the execution path and then drag in the current foot count again to get and do the integer plus one plug that in so now as it Loops through the feet it'll be counting up how many feet we've gone through so then user current foot count as the index for the array and everything's back to normal and the feet are locked to their initial place in World space so when you move it around they're all locked in place and if you move it far enough again the squid now we're going to create a new function I'm going to call this calculate velocity and back to Mr spider who's now wearing his hat for another diagram so if we imagine that he's moving from the left of the screen to the right and let's say in the last update one second has passed and we'll say that he's moved 200 units in that time so he's moving at 200 units in one second which is 200 units per second but in a more likely case the last update would be shorter so he's only moved let's say two units and we'll say that in that the time passed for him to move two units is 0.01 which is one frame at 100 FPS so the mass would be 2 divided by 0.01 which co-cuts back to 200 units per second so now what we're doing is basically the distance or the displacement of the time equals the speed or in our case the velocity so we can use this to calculate the speed that he's moving at frame rate independent so to do that in the actual chord we're first going to get the transform of the pelvis and we're just using this because it's the root Bond so we get the bone transform pelvis and we want to save this location for later so get the translation and we're going to get to the user 2 world to get it in World space create a new variable set that to a vector and we will call this previous World location and at some point we need to set this so we'll do this towards the end of the function we'll do set previous World location and for now we'll just plug in the world the current world location but what we want to do instead is we want to calculate the difference between the current world location and the saved previous World location to find the difference in position so to do that we do the new position minus the previous position so that's the difference and then we want to divide this by a time that's passed which is the Delta time so if we do divide we'll see that's a vector and we don't actually have a divide by a factor so we'll do scale by a factor which is multiplying so then we get the Delta time and because we're scaling not dividing we need to convert the Delta term into whether it will make it divide it so instead of just plugging it in we do one divided by Delta time and then we plug that into the factor which should be dividing the displacement by the time and the result should be the velocity so we're going to save of well we're going to create a vector called calculated velocity drag that in and set that value to the value we just found but we don't necessarily want it to instantly update the velocity we want it to be a bit more gradual because if the rig is moving around fast it might be jittering and you know with frame time differences so we want to smooth it out a little bit so if we get the current calculated velocity and we interpolate towards the new value and if we use a number like 0.1 all the time it'll accumulate and get closer and closer to the actual value and we'll plug that into set calculated velocity so back in the red graph what we're going to do just for a test is instead of using the bond location that we got from the saved array instead we're going to get the initial foot location just from the default pause so to do that if we go to the array element that we're currently iterating through and we do get transform and tick initial and then get the translation and on this translation instead of plug it in direct label do an add vector and we're just going to add on the velocity and we'll plug that into the translation so now we'll see when nothing is happening and that is because we missed a battle step of actually using the function so um we'll plug that in at the start after forward solve and now we'll see that it's all pointing towards one location which is strange so from that we can assume that we've done something wrong in terms of switching from World space to Global space and we have because we basically didn't do that at all we named the variable previous World location but we're not actually converting it to a word location we're just getting the global transform of the bone so if you drag out from translation into two world and plug that into the subtract we can now see that when the rig moves the legs are moving forward so if we move it at 200 units a second in One Direction the legs are moving forward ahead of that by 200 units and this also makes a jumping spider Okay so back to control rig um what we now want to do is actually use the world location that we've used from the array so we can probably delete what we've just added to test things because the calculated velocity appears to be working now so I'll just get rid of that and well you can plug back in as it was and I'm going to duplicate the world locked foot location and call it World Target foot location so this is where the foot will want to reach when it steps so now we want to create another function to actually calculate this value and put things into this array so I'm going to call this calculate new foot targets and what we're going to do in here is well firstly we're going to copy some of the nodes from the setup event because we're going to essentially be doing the same thing where we're tracing to find the foot like landing spot and we should have used a function for this but I'm just trying to keep things simple and just do it one step at a time so we Loop through all the bonds and found all the ones that contain foot and get the world location but now we want to add it to this world Target foot locations array foreign we want to also clear this array before the loop just so that it doesn't keep accumulating new targets and adding so it only ever creates eight for one for each foot so now before we add it to the array we're going to add on that calculated velocity to essentially project it forward and at this point I should mention that another way to get the calculator velocity is just to input it from the animation blueprint if it's a non-velocity with a character blueprint but this works for any situation when it isn't a character with a movement component so the moment we're getting an error and that is because well firstly we are calling the return node inside the loop rather than on complete but we still have the error and I've just noticed that I managed to delete an execution path at some point so I've just put that back but that shouldn't be affecting the problem so what we can see is if we go to the output log we can see that it's trying to access values outside of the array and that may be because we're not actually calling this function and now everything works as it should so when we simulate we're back to how things were that it's projecting forward at all times but we don't want it to always be projecting the location forwards we only want it to do that when it decides to lift the foot and it should calculate a new landing spot so at the moment just when we move it if we remember to simulate it's just moving forward so we're going to make that more intermittent so it only updates these values every so often so as a quick test inside the calculate new foot locations on new foot targets instead of doing add we're going to change that to a set so set at so that means that we can change values or not change them if we don't want to rather than just adding to the array so the element is still the same but the index should be the foot index and once again we don't have direct access to the variable and we should redo a lot of this because getting repetitive but we'll get the current for index and make that a local variable just so we're not messing with the previous one that we used and within the loop we're going to set that to whatever the previous value was plus one and now because we're updating it we don't actually want to reset the array so let's just cut that out and we're back to an error so let's just set the current local index to negative one just for sanity's sake but we still have the error and it's still saying that it's out of bounds when we're trying to update these values and that's because we're using well firstly we need to plug in the index that we haven't used but also this is an empty array so we're trying to set values in a blank array so in the setup event each time that we add a new locked foot World location we're also going to add a add the same entry into the world Target foot locations just to populate the array just so it has eight entries and now you can see that things are working back as they were before and now what we're going to do is only set these values if a certain condition is met so drag it onto a branch and if true we'll set and update that value otherwise it does nothing so just to test it we'll get a random float and if that number is greater than 0.9 or 0.99 then it will update and you'll see that this doesn't actually work it will randomly snap all of the likes to a new location but instead it should be doing each load individually and so that's because for some reason in the loop it doesn't create new values so we're just going to seed it with the current foot index just so each number is unique and we can see that it's sort of working it's updating the new Target locations at intermittent times and it's doing it different for each leg so I'm just going to make that a little bit more frequent just so we can see that a little bit better and even though the legs are snapping into place we can kind of see that that's working so what we want to do now is replace just this random thing that we've done as a test to actually use some timing so we'll create a new float and we'll make that an array and we call it foot timings and since we've made a new array so we don't get the error that we got before every time we had a new leg in the setup event we'll just add a new entry to foot timings and we can leave the element at zero for now so in calculate new foot targets what we're going to do is whenever the foot timing gets above a certain value we're going to create a new Target point so we're going to get our at the foot timings array and the index is the index that we've already got from the local variable current foot index local and if this value is above some other value so let's do two in that case we'll update the Target location so every two seconds it should update a tag location but this array is currently empty because we've just created it and we've set the values to zero so what we're going to do is make a new function which is going to increase the timers so I'm going to call it increase foot timings get the foot timings away and for each entry in this array we'll get the current value of the element and we'll set at the same index that we've got from this for each Loop and we'll set the element to the current value plus the Delta time so that's the term that's passed since the last update so every second that should increase by a second and now I think if we test it and not forget to use the function we'll see that we're getting some errors and that's because we've got a lot of Loops going on um and by default there's some limit to how many Loops that it can use so if you search for limit the nod run limit and we'll see that this is currently set to 64. and before we increase that let's just make sure I'm not doing anything stupid um which we are we've got the return node once again in the loop and that seems to be a habit that I've got so put that on complete but we've still got the issue so let's just try increasing the limit so in class settings change it from 64 to 128 now it compiles with no errors so anytime the foot index is greater than two we're going to get a new foot Target but we also want to reset that value so we do another set at from the foot timings array at the same index and we're just going to set it back to zero so now you'll see what happens is every two seconds or rather than being random it's updating them all every two seconds and because we're not differentiating between the different feet in terms of the timings it's doing them all at the same time so now what we're going to do is lurp between the locked location and we need the from world because it's a world location so once again we'll use interpolate vector and we'll interpolate it with the world to Target foot location and the alpha we're going to get from the foot timings array at the current index which should be a number that goes from zero to two and then resets over and over again so because it goes from zero to two and we want it to be in a range of zero to one we can do a clamp and Clump it so that when it gets to one it just stays at one and when the original value gets to two it resets back to zero so now every two seconds it will start to lower to the new position slowly but as you can see it's snapping back to some old location and that's because we're never actually updating the world Target foot location array we're only using the initial values we set on the setup event so every time it finds a new foot location what we're going to do is also set the value for the world locked foot location and we'll use the same index and the value we want to set it to is the current Target so the previous Target becomes the locked location and we generate a new Target straight after so to do that we just get the world Target foot locations and the same entry from the array plug in the element and now we should see that every two seconds it just Lopes to a new position so I'm just going to quickly speed this up in the increased foot timings by multiplying the Delta time so I'll multiply it by four so it should be four times faster than it's going through the loop just so we can see how things look and now you can see that it's moving more frequently as well as the actual Loop is faster and now because we've sped up the timing it seems like the feet are moving too often so in the branch where we're checking if the current foot timing is above two instead we're going to do about four so it should be twasislaw or half as fast um so now we can see that the legs are still moving fast and it's more frequently finding a new location and I think we want somewhere that's in between the two so I think I'll try if it's greater than let's say three and a lot of these numbers will tweak when we have added more features and made it look a little bit better because it'll be easy to tell if things are looking right or not but we just want a baseline that's approximately right the main issue at the moment is that all the feet are moving at once and that's because we in the setup event where we are now we are setting the array element to zero for all the feet and we're increasing them all at the same time so they always reach to the maximum at the same time and reset at the same time so instead when we first create this array of the foot timings we're going to do the index so we'll do two float and then multiply that by 0.125 which is an eighth of a second so each leg will be offset by 0.125 so now we can see that they're moving slightly out of town but it's not entirely clear what's going on there so we're going to exaggerate things a little bit just so we can really see what's happening so as it is now you can tell that they're not moving perfectly in sync but it looks almost like they are and to fix this or to just adjust it what we can do in the calculate new foot targets instead of being greater than three we'll change it to let's say maybe greater than one and now because we're doing greater than one the feet are always moving and that's because we're using the lerp based on this foot timings which is only going from zero to one so every time it reaches its Target point it starts moving again so what we're going to do instead of just the clamp is we're going to do a remap and the remap node has a clamp option as well so we don't actually need the clamp anymore so we'll just skip over that we're going to set the source maximum to 0.2 and leave everything else the same so when it reaches 0.2 it will essentially be outputting one which means it's reached the full Target location so now the feet move a lot faster because in a fifth of the term they're moving the full distance so now let's just plug Delta tan back in without the multiplier by three because things have already sped up due to what we've changed there and now you can see all of a sudden it actually looks like a spider walking to some extent there's it's not perfect but at least when it's moving at low speeds it kind of holds up and if you do some weird Direction changes it probably won't but for the most part this is looking closer to what we're aiming for but because we're just doing a straight lip from one location to the next the feet don't actually lift off the floor so instead before we plug it into the basic arcade in order we're going to do an add vector and we're going to increase the Z height and to do that we're going to use a curve so I'll search for evaluate curve and this essentially takes an input and remaps it based on the Curve so we'll take the remapped result and plug that into the value of the Curve and because we want it to start and end on the floor we want the start point and the end point to both output a value of zero and somewhere in the middle we can bring that up it doesn't really matter where to but we'll put it to one and we'll plug the result into Z but that will only be adding one unit of height so the target maximum this is essentially scaling it or remapping it to 100. and now in the viewport you can see that the legs are well lifting and even though the spider isn't moving it's lifting the legs and we'll fix that later but let's just see how it looks when it actually is moving so you may notice that now the legs seem to sometimes be intersecting the geometry it's only when they move when they when they're stationary over the point they actually work but when it's moving it's going underneath the surface and this is because we're taking the hit result and then projecting forward using the calculated velocity what we should be doing is projecting the end point and then doing the trace to see where the end point actually hits the floor so in the calculate new foot targets function we're just going to move things around a little bit so it should be before the trace instead of after the trace when we add on the velocity so just rearrange some of these and we're going to add this onto the foot location before we do any of the trace so if we plug in the translation to the add node and add it on and then if you control drag from this it doesn't seem to work and I think that's because it's loot back in itself so I've undone that and I'm going to plug them in manually so I'm just replacing the connections that already existed and then the translation can go into a and that projects forward and then does the trace line from above and below that projected point to find the actual hit location and then saves that so I think that should have fixed the issue we had so now you can see that the feet are always actually meeting the floor when it's moving and I'm just going to tweak the lifting of the feet so if you right click on the points and select auto then it will be more of a curve rather than like a linear change um I'll smooth things around so it lifts up at first and then it gradually drops down towards the ground and I think that looks a little bit more realistic and we're not aiming for realism but it looks less robotic that way um you'll notice it does the issue that when it's stationary the legs are lifting so we'll fix that next so to do that all we need to do when we've got the target maximum 100 instead we're going to scale that based on the velocity so I'll drag in the get calculated velocity get the length of the vector which is essentially the speed remap that so we can clamp it and the target maximum we want to be well it would be 100 but I'm going to try a little bit more so I'll try 150. and the source minimum zero so that's when it's not moving and the source maximum that is essentially the value that you expect it to come in at when you want it to Output this maximum 150 value so I'm going to say well I'll say 400 for that as the the maximum speed that we expect it to be moving at and plug that into the target maximum of the Curve so now when we simulate it's the legs aren't lifting when it's stationary but when it moves the legs are lifting the next issue that I've noticed is that when the pelvis goes over the edge it instantly snaps down and that's because we're doing a trace from above and below the pelvis and just setting that position we're not lurping it we're not doing anything fancy we're just setting it to wherever it finds the ground instead we're going to save the pelvis offset so I'm going to create a new vector and I'm going to call it saved pelvis offset cunningly and we're going to make sure that that's not an array and we're going to set this value after we've transformed the pelvis bone we drag in the save to pelvis offset variable and do set and put this after the set transform node at the moment we'll just plug in the same value as we're putting into the set transform node but what we want to do is create a spring interp and what this will do is it will interpolate towards the target value with more of a spring look to it so it can overshoot the value and it will sort of wobble back into place so for the Target we have the actual Target that we want and for the current we plug in the saved offset variable and let's just see what that looks like first before we start tweaking the values so you can see that it's actually dropping down slower it's not instant anymore but it's not really doing too much so let's just tweak some of the values so let's turn down the damping and turn up the strength so it'll move faster but it will also have less let's say friction for the damping and I can see that it's well it's quite bouncy um that's maybe a bit exaggerated and a bit too cartoon if what we're going for and so I'll tweak the values again to a strength of 2 and 0.5 for the damping and that seems closer it still absorbs some of the weight when it drops but you'll notice that it's intersecting because we're doing a trace straight from the center of the pelvis so if you increase the radius of the sphere Trace that should help with that so it's essentially tracing a larger sphere straight down so it's not a line Trace it's just a sphere and now you can see that that's improved it slightly um I'll probably tweak those values later but for now that's good enough but the legs are sometimes stretching out too far so when we're doing get calculated velocity we're going to clamp the length of that Vector so that it limits how far it can sort of predict the legs forward so we're going to set the minimum value and let's just use zero for that and the maximum we're gonna have to tweak this number so we'll just try things out I'll just make sure it's working with a law value so now you can see that when it predicts forward the legs aren't moving very far they're basically staying close to the body so I'll try 1 200. and we can see that it's limiting it but not too much and we might want to reduce that later but for normal movement speed that's not the main issue at the moment the main issue is that the legs get locked behind so when the body keeps moving it's stuck far behind so to fix that we're going to get the world locked foot locations array and the current index and subtract that Vector from the vector for the location of the pelvis so what that's essentially doing is finding the distance between the pelvis and where the leg is locked now if the length of that after we've subtracted it is greater than some value then so in this case I'm just going to use the same value so I'll use 1200 if it's greater than that then we'll also use that as an option for when it should decide to move the legs so we've used that or if the timer reaches the time when it should reset the leg anyway so we'll try that and as you can see it's not working very well and it's oh it's resetting them all almost instantly because we've done something wrong and so let's take another look so instead of finding the distance to the pelvis which is not where the foot is it might make more sense to get the position of the bone so I plugged in the item which is the actual football so it fans how far it is from where it actually wants to be so that's where it was on the bass pause and that seems to have improved but there's an issue now that if they all reset at once because it's moved too fast they all get reset on the same timer so the legs become in sync so they're no longer offset using the circle timer that we had because they all reset into the same position so I'm just tweaking the values just to demonstrate that so you can see that they're all in sync and all the legs are trying to move at once because they all leave the distance or they leave the area of where they're trying to be at the same time so I'm just going to play around with the values to see if we can get the range right so I'll try going back to 1200. and that seems about right it's not going to work in all situations you know if they move too fast there's there's no way that the legs are going to make sense when it's moving that fast um but I think the main issue is that all the legs are syncing up so to try to fix that there's there's probably better ways to do it but what I'm going to do is instead of setting the value to zero of the timer when it resets I'm going to set it to a negative number um and that's only in the case if the reset is because it's out of the range so what I'll do with that is I'll get the index for the current photos of the seed so that it's always different and we'll set some minimum maximum values just so that the timers get reset to some random offset variables and if that's the case we plug it into true otherwise false we set it to zero because that's just a natural reset and now you can see that even though the legs are moving out of their range at the same time they still stay out of sync because we've added some Randomness to it and to help with this just to avoid the issue happen in the first place when the velocity gets to a certain level it's going to increase the Tam speed so I'm getting the calculated velocity the length of it and remapping that value so this will speed up essentially when it increases the time as it'll increase the Delta time that increases by when the calc when the calculated velocity increases so essentially the cycle time is relative to the actual speed that the character is moving at and I'm going to use the same except the inverse of that for scaling the clamp so now that when the legs are moving faster it brings the scales down the length that we clamp at so the legs can't stretch as far in the event that it's moving at very high speeds so when it's moving slowly that seems to work okay if we move it too fast the legs are still getting stuck behind but that's mainly because we're saving a global position and not a local position so the legs aren't moving locally and that can be difficult to explain so I'll try and demonstrate that better because this will come up in a lot of projects so if we imagine the spider once again is moving from the left to the right the position of his leg started off of at this side and now has to lurp all the way over to where it is or where it's predicted to be in the future so when the spider's here the position that the leg wants to be at is still back there because it's only through some portion of the move so the lerp is still saying that the leg wants to be far behind because it's still locked in World space Far Far Behind the actual spider whereas if we switch to local space The Arc is now all within the local space of the spider or the global space rig space if you want to call it that so wherever the spider moves it's still making the same Arc regardless of where it was locked in World space so to do that essentially what you would do is find where the leg is in local space even though it's locked at a world position found where the local position is for that leg and then set that as the new starting point in local space and then predict forward again in local space and then make it do the arc and then when it lands down you switch back to World space and lock it in a world space location and that's quite complex and not something we're going to do for this project because it doesn't need it but you might find that with certain walk cycles and certain speeds and especially with human characters that it looks a lot less natural if you're everything's based in World space and you're not switching back and forth between local and world so back to reality we're going to create a new function and call it calculate average foot location and what we're going to do is basically Loop through the legs as we've done before get the average location of the feet and then we're going to use that to try and make the body move a bit more naturally so it will try to move the pelvis towards the average position of all the legs so if some legs are a bit far forward the pelvis will move forward if they're to the left it'll move to the left and so on so essentially we're just adding the vector of each foot position to a location tally where we just keep adding on to the same value and then later we're going to divide it to find the average so before we return from the function what we want to do is get the location teller which is all the locations added up we're going to create an output for average location and we need to know how many times we've added um a vector to this Telly so we'll create an integer feet counted each time we add something to the Telly We'll add one to that value and then before we return it we do get location Telly and then we divide it I'm going to divide it by the feet counted integer so we need to just convert that to a float and we'll just plug it into X Y and Z and then we get the average location of all the feet and then we need to call that function somewhere but I'm not going to do it before we start moving the feet around I'm going to do it after all of the loops and the reason for that is we don't want the pelvis to move after the legs have moved because then the legs will also move along with the feet so essentially we're doing it at the end of one tick and then we're going to move it at the start of the next so we call the function at the end and we're saving it to calculated average foot location vector and now what we're going to do is instead of using the pelvis location as the trace we're actually using this saved variable so it will try to move to the saved location and as you can see that when it moves the pelvis is actually moving away from the natural center point because it's basing it around where the legs are and that looks a little bit more organic and when it stops it moves the pelvis into position and it looks a lot less static and more realistic and we're still using the spring interp for where the pelvis moves to so it's not instantly snapping to the average location of the legs it's gradually getting there using the inter so hopefully you've found some useful information from this video if not let me know in the comments um and I'll delete it and if you have any questions and things you need clarifying or suggestions for other videos in this format then let me know in the comments as well and in the future I may do a short video showing how I actually made the spider model I've been using here in blender because I did record that whilst I was doing it but it didn't seem relevant for this video um yeah so thanks for watching like And subscribe
Info
Channel: Lincoln Margison - Game Development
Views: 206,239
Rating: undefined out of 5
Keywords:
Id: vKiqs_h1WXM
Channel Id: undefined
Length: 58min 32sec (3512 seconds)
Published: Sun Dec 11 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.