UE4 - Tutorial / HowTo - Line of Sight Vision System

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
this how-to tutorial will cover the method i use to create my own version of a line-of-sight vision system this type of vision system can be used to create really cool cinematic effects and types of this system can be seen in games like darkwood or monaco this is my first time using the chapter system on youtube for my tutorials rather than breaking it apart into smaller separate chunks so we'll see how that goes i will also have a written version of this tutorial on my documentation page since we're breaking down the development of this line of sight vision system into smaller more manageable chunks we're going to start here with a post-process material that we're going to create to kind of handle the logic we need and we're going to build upon it as we go so i'm here inside of a twin stick game nothing has changed here except i've added in a quick png it's called sample render target i'll make sure this is available on the documentation page the written documentation page that goes along with this video the only thing special here is i've made a 1800 by 1800 image it's got some black area and some white area that we can basically use from some masking purposes so i'm going to go ahead and create a new material here and i'm going to call this one los vision post process i'm going to wander over to our post process volume and i'm going to go down to post process materials and i'm going to add an option to the array here make it an asset reference and drag in this material i just made we're then going to pop in here and we're going to make some modifications this material before we actually start writing making nodes here the first thing is i'm going to make this into a post process material domain then i'm going to go scroll down all the way to the bottom just about and i'm going to change blendable location from after tone mapping to before tone mapping and this is just to avoid some jitter issues with the temporal anti-aliasing that really uses by default so the concept we need here is i need to have a region of our screen that has the normal game screen and then a region that has just black or some other color so what i'm going to do here is i'm going to add myself an alerp node let's call it i hold down the l key and just clicked and i'm going to hold down the v key and i'm just going to give myself a color and i'm going to change this for for now for development purposes to something more obvious that we know that we are not basically inside of and this isn't any shadows also going to right click and get myself a scene texture node the scene texture node is our window into the different render passes that the deferred render system in unreal uses and i'm going to use post process input zeros this is going to actually give us just the general render from the screen i'm going to connect that there i'm going to wire that to the emissive and to fix this error it's going to give us i'm going to change i'm going to give this a mask component this is because this is actually a vector4 and it needs to just be a vector 3 for this and that'll take care of that for our alpha pin here on our lerp i'm going to use a texture object and i can't plug our texture object we're going to use our sample render target i can't plug this directly in here and i can't add a mask in if i try to use a mask it doesn't like it we're going to actually use a world aligned texture this is kind of the magic node that we're going to be using that's going to let us apply this to the world itself i'm just going to use that z texture because it's uh it's kind of already set there for uh for just having one channel for our alpha go ahead hit apply and we can even take a look now and we can actually see that we're already starting to get this to show up here on the world uh kind of like basically applied in the z direction uh so the le this thing we need to do is just actually tell this what size this texture object is so i'm going to hold down v i'm going to add in another vector node here and i'm going to plug that into texture size and we're actually going to go tell it that it is a 1800 by 1800 image just gonna just for some or just for com consistency's sake i'm going to make those all eighteen hundreds now if i hit apply and go back to our world we can see that we have this larger shape still repeating throughout the world but if i hit play now you can see that i can wander in and out of view and the objects that are within that space in 3d do in fact appear where they're supposed to be everything else does not end up showing up so there's our there's our first step the next thing we're going to do then is this would be really really handy to actually have centered on the player themselves so we're going to actually center this on the player so in order to actually kind of move this texture around them with the player we're going to actually utilize a collection parameter and we need to actually create this so let's go ahead and create that now i right click here i'm going to go down to materials and textures and i'm going to create a material parameter collection i'll go ahead and call this player position and i need a vector parameter because i need their location in 3d space and i'm going to go ahead and expand that out we're going to name that player position all right now that that's been saved i'm going to go ahead and point this towards player position i'm going to use the parameter player position and i can't directly utilize this here um i can plug this in for the moment but you're going to see an issue here let's go ahead and just apply that and then we'll fix this afterwards but remember this this should not be connected directly there so i'm going to wander over to our twin stick pawn i have it open here we can actually find it a couple different ways we can click there edit blueprint open blueprint editor that'll get you there and i am going to go ahead and in the event graph i'm going to override the event tick here i'm going to add another sequence here for this particular thing and we're just going to move these down for cleanliness i'm going to drag out of here and i'm going to say set parameter set set vector parameter value and under collection i want to change my player position and for the name i want to change the player position and for its parameter value i'm going to go ahead and split this structure out and i want to just get actor location i'll go ahead and split that out uh you know what we don't actually need to split that i'm just going to recombine these just drag that in and i'll let it convert it and that'll be fine so now every tick we're going to update where our position is on our vector parameter value now if i hit play you're going to see that you're never going to actually see anything i promise i'm moving but you're kind of seeing everything is kind of going wonky and this is because we actually need a a shift basically not an absolute position so we want to take our absolute our old position and we're actually going to subtract these so i'm going to mask this because if you as you can see this is a float 4 and i want to do some float3 math and i will subtract and so i'm going to take this position wherever wherever this position is in world space and i'm going to subtract from it to create a vector towards that position in world space i'm going to plug that into my my position now for my world-aligned texture and i'm going to apply now if we hit play you can see that those positions are kind of staying still but it's not quite centered on us this is because it is currently centering it at a corner remember this is 1800 by 1800 so we have to add an offset so we're going to go back here and we're going to go ahead and we're going to add an offset and then we're going to go ahead and make a float3 and we're going to go ahead and hold down s give ourselves a scalar and this is going to be called offset x y and we're going to set this this value to 900 because we want to center this image on us so now that i've added those together like that i'll go ahead and apply now if i hit play you'll see that this is now centered on our character and it is now following us around so we now have the basis for a post-process material that we can begin building a way to create a more custom image that we can use rather than our sample render target to actually create and draw this vision field out with so here so this first step is now finished the next step then we're going to talk about how we would potentially create dynamically during play and render to a image some kind of a map png basically that we can then use for this all right so to start creating a custom shape that we can then use in place of our texture object that we have here the first thing we need to do is actually create a target that we can draw to so go ahead and right click under materials and texture we're going to create ourselves a canvas render target and we're going to call this one los vision zone or something just lost vision target is what i'm going to call it and we're going to jump inside of there because we need to make some modifications the first thing we need to do is make sure that we make this 1800 by 1800 and this is just for my purposes of this example you can make this larger or smaller for whatever you need if for example if i hit play here you can still kind of see on the left hand side there that we still do have like the text repeating and such so if you have the camera pulled back more a simple solution would be just make this material larger and then it won't end up repeating so 18 by 100 by 1800 that's fine we also want to make sure that this is not generating mipmaps so no mipmaps we we only want this as a raw data go ahead and save that and then this is basically what we're going to be trying to draw to and work with so we're going to open up and we're going to go back to our twin stick pawn here and we're going to give ourselves some space to work with so instead of just setting this vector parameter value what we're going to do is we're going to create a custom function here and we're going to call this one los vision system go back to our event graph and we're going to run our los vision system every basically every tick because we need this to update every single tick unfortunately there's no there's no real way around this this is one of those mechanics that i i can't actually push off off of the event tick nor would i really want to i want this to occur every frame because every frame the character may be moving and that's important to constantly give them new information go ahead and delete those after copying them and we're just going to move those into our vision system and so we're going to get our get actor location we're going to set vector parameter value player position and give it that okay so here's our sequence then we're going to give ourselves a sequence here this is the first thing we want to do is update this positional information with the player and then the next thing we want to do for this node and this is going to be update the los render target [Music] okay and so to do that we just need to actually first basically get a reference to it so what we're going to do here is we're going to clear render target 2d and i'm going to use this just to get the right asset here that we want so we're going to promote this to a variable this is going to be our los render target compile that and we are going to point that towards ls vision target so step one every every frame we know that where we're working with we have to clear it we're going to clear it to the black color so that's good then add ourselves a reroute node we know that we want to begin drawing to it the next thing we want to do is we want to draw a triangle i draw a material triangle we just want to draw a triangle i got that from dragging out from the canvas so i get that reference and we can leave render texture as is just empty default we're just going to use white that's all we really want because it's going to give us a value of 1. and then we have to drag out from our context pin for afterwards just so that the we can basically let uh each frame know that we are done drawing it after we draw our triangles we're done and so let's go ahead and give ourselves a a sample example triangle we can draw so i'm going to go ahead and i'm going to say make we're going to make an array from here and i'm going to go ahead and split this structure pin out so that we just have basically one version of this so we can see what this particular thing is trying to ask for and it's asking for an array of these and what these are are basically three copies of the same kind of information sets we have position uv color position uv color position uv color and so a triangle is three points these are basically three vertices so we have a vertice position a vertice uv which we're not going to utilize and then the vertex the vertice color which we will end up utilizing when we actually draw out to the triangle itself so what we're going to do here then is just add in some generic values so that we can kind of see on this picture here what's going on so i'm going to leave this at 0 0 i'm going to make this one 1800 and i'm going to make this one 1800. so i've basically made vector 0 of our triangle 0 0 i've made sorry vertex 0 of our triangle 0 0. i've made vertex 1 of our triangle 1800 0 and vertex 2 0 1800 and we do need to change the colors here to pure white so now if we simulate this we will still see this uh kind of empty grid pattern that's just because we have the alpha channel enabled so if we don't use alpha you can see that everything is now being drawn white that's not that and so there is there's the simple concept of how we actually will draw to that image if i actually switch our vision system over now here this is back in the los vision post process i'm going to go ahead and close this this collection parameter i can actually switch my texture object now over to our los vision target go ahead and apply and you can definitely see that now we have a a very strange shape that we're kind of dragging around the screen with us that we can use as a mask so let's go ahead and actually make it somewhat more useful in a way that we're going to be building upon later to make this a actual dynamic los system so the next step is to then test this system out by creating a centered static kind of triangle shape that we're going to use is a rudimentary vision cone we're going to do that by basically giving ourselves sort of a static single triangle to work with but we're going to base it off of our direction so i'm going to go ahead and get actor forward vector and i'm going to go ahead and get actor right vector and we're going to use these then to kind of uh override the the vertex positions of our triangle so go ahead and multiply this out by a float let's say 700 for the length of our triangle and then i'm going to give myself add vector and i'm going to give myself a subtract vector and i'm going to go also ahead and copy this node right here and we'll leave that at like that 700 is probably fine and so now i have the right vector and the forward vector a 700 length of those directions and i'm going to add and subtract those both now the next thing i need to do is actually shift these because if you remember for our vision system 0 0 is right there so i want the first vertex of our triangle to be at 900 900 and then i want whatever the addition of that is to be based off of that position so i'm going to go ahead here and i'm going to add another vector and we're going to do a make vector and this is going to be our offset go ahead and label that offset i'm going to duplicate that add that there and then i will plug the offset into our vertex 0 so that we can start it at 900 900 and then our vertex 1 will go to this position and our vertex 2 will be located there just cleaning things up a little bit now let's go ahead and compile that and test it out so if i simulate it there we go we have a simple triangle that we've drawn if we run over here to the game instead of simulating actually hit play can see that we do have a vision cone but if you look carefully you will notice that it's kind of behind us and so we actually need to reverse and modify how the uh line of sight system here is treating it because we want to write to this image in a in a organized fashion such that forward is forward and right is right we have to worry about any kind of math over here we'll just handle like any switches over here so what we will do here for our positional data is we're going to go ahead and break this component out and we're just going to reverse some directions on things so multiply by negative one copy that paste and i now i'm just basically reversing the coordinates for my x and my y after that i will remake this float three just give this a reroute there to make it a little bit cleaner let's go ahead and drag that out and we're going to put a box around that and this is going to create we're going to center the view and we'll plug that into our world position i'm going to go ahead and apply and now we can go ahead and test it and lo and behold it is now working properly so there is now a triangle in front of us based on our forward direction at all times and so the next step we're going to instead of just writing a static shape here we're going to create a system using line traces that will then basically sample the environment in front of us and then draw out the shape accordingly so in order to create our own custom shape here based on our environment we're going to utilize a series of line traces and we're going to talk about more about why we'll need it but we're going to need them to be somewhat ordered so we can't just cast out randomly or start the middle and go right then left we're going to start at the left and then we're going to move our way right so let's go ahead and jump into our twin stick pawn here and we're going to go ahead and create ourselves a new function and we're going to call this function create cone and so the first thing we're going to do here is we're going to get our actor forward vector and what this is going to give us is a reference direction that we can start using for what is forward and so we're going to actually grab ourselves a rotate here because we're going to rotate our forward vector and we need to rotate this a bit so that we first start at the left and then we start rotating back to the right so we're going to start make rotator here and we need then something that we can kind of modify as we go if we decide that we need more points later on so i'm going to give myself two variables here the first one i'm going to have is an integer this is going to be num traces and my float variable here is going to be degrees per trace and this is going to be a how many degrees should there be between one trace and the next i should note here that when we're using this the num traces should stay as a even number if it's not even you're going to potentially encounter some issues here so i'm going to go ahead and compile this just so i can set this as like 20. we'll start with 20 traces and then for our degrees we'll go with like three degrees per and what i'm going to do here is i'm going to multiply these together and then i'm going to divide it by negative 2. the reason i'm dividing it by negative 2 is because i first off only want to move my rotator or my forward vector halfway to the left and so half of that is going to be the 2 and then the reason for the negative is to indicate it should move to the left i'm going to connect that to my z axis so i'm going to rotate my forward vector in my z i'm then going to give myself a for loop here and this is going to control the number of traces we're actually going to occur so i'll go ahead and just for cleanliness i'm just going to drag drag another copy of num traces out we're going to connect it to our last index and then i'm going to take my degrees per rotation here and i'm going to go ahead and drag out so actually let's get a new one here we're going to get ourselves a multiply we're going to multiply that by our index and the idea then here is this new rotation starting from the left we're going to then rotate it again we're going to go ahead and split this and we can then rotate this slowly back to the right each for loop so let's go ahead then with this we can now go ahead and make ourselves our line trace we'll do a line trace by channel and so we can kind of see it we're going to d we're going to actually draw a debug for one frame so this will keep redrawing it each frame as we create it we want this to start at our wherever our actor is so we're going to a get actor location and there's our start and then for the end of this we basically want to take whatever direction this vector is currently pointing in multiply it out a little bit so it has some length so let's say 700 and then we're going to then add these two together so that we can kind of go in that direction all right and let's see how this actually looks on screen so let's go ahead and compile this go ahead play and before we actually get to see it we actually have to indicate that it should run this function so let's go back into our event graph uh so we have this line of sight system we're using so the first thing then we're going to do is going to add another uh thing to the sequence here we're going to then move the pins down so that the first thing we do is set our position the second thing we do then is we run this create cone function now that we've compiled that we can see that we now have a very ordered series of lines here that we're casting out and as we move around they're going to basically be sampling the level in front of us and around us and you can then set this basically for any kind of width that you want for like if you want like your player to have a narrow cone of view or like a wider kind of view and you can add more uh points then if you need it to be a much more finer mesh so now that we are actually drawing our line traces out we need to save this information so let's go back into our create cone function and then the last thing that we need to do then is based on our hit results we need to save something but we need to be careful that we're actually saving useful information if there is no information so if i hit play here again you can actually see that if we don't encounter anything if everything is too far away we don't get a line trace result there's no kind of point there that we're actually going to get so the idea here is we need a branch statement that if we are hitting something we want to save the location that we encountered an object if we don't hit anything we want to save the position that the line trace ends at in space i'm going to go ahead and add a branch and the condition it's going to run off of is this return value if there was a hit we want to save the hit if there wasn't a hit we want to save a different value basically this end pin so i'm going to go ahead and just for now add a reroute node here so that we can then reroute this around here and we'll spend a little bit of time right at the end here kind of cleaning this up visually i'm going to go ahead and split the structure pin and so now we need to save this somewhere so what we're going to do here is we're going to add ourselves a new variable here and this is going to be trace results and we're going to make this a vector and we're going to make this a vector array i'm going to add in a reference here right at the beginning because the first thing i want to do is make sure i clear this every time i use it i'm going to have different results so i need to make sure that i clear this every single time now over here what i can do is i can add a new result each time so that i know that entry one entry zero is the first line trace entry one is the next one and so on so i'll have an ordered trace result that i can then use let me go ahead and copy that for the false wire that back up to the trace results and so now our out hit location if it was hit we'll add it there if it wasn't hit we'll go ahead and add in the end position that we actually created or actually using for the line trace so now we have this ordered pair or this ordered series of uh of points in space so let's go back to our line of sight vision system and this is where we can then utilize this information so we're going to go ahead and actually get rid of this uh in fact this also and we're going to make ourselves a new function here that we're going to use to prepare everything so we're going to go ahead and drag this down and we're going to create ourselves a new function here then we're going to call this prepare triangles for canvas now let's jump back real quick to our line of sight system and we're going to go from this triangles thing we're going to drag off of this and we're going to promote this to a variable and we're going to call this one canvas triangles so now let's go ahead and while we're here drag out prepare triangles for canvas and just wire that into the sequence and jump back inside and we'll actually start preparing this so the first thing to do then is grab a reference to our trace results and we're going to grab a reference to our canvas triangles now we're going to take that canvas triangle's reference and we're going to make sure that the first thing we do in this function is we clear it because since we're running off of each frame and each frame our trace results will change we want to make sure that our canvas triangles is cleared so that we have a clean array that we can then pass over to the canvas and we're going to then take our trace results and we're going to grab ourselves the length and we're going to use this to run a for loop and we need to subtract an integer from our 4 from our length so that we can run it through the last index now we don't want to leave this at -1 so if our trace results is like length 20 21 etc we don't want to simply do the standard minus one for the last index because we actually are going to be going forward one each time that we run and what i mean by that is we're going to use our our index to grab ourselves a reference so let me grab that right now but this is only going to get us one of the vertices of the triangle remember since we're going from left to right as we're drawing through all of these line traces from the array we need to get whatever index we're currently on and then the following one so that we can create a triangle out of it in our position so we're going to make this minus 2 and then we're going to go ahead and drag this down here and get ourselves a second get reference and i will simply wire up the first one to the index but i need to wire up the next one to the index following wherever i currently am and then this will get me the results so i'll have two of them the current one and the following one that i can make a triangle out of along with my own position so the next step then is to grab ourselves our canvas reference our canvas triangles reference we're going to add a new uh in a we're going to add a new index to it i'm going to go ahead and wire that up and we're going to go ahead and split this out and this is where we have to remember we can't just send it our current position we need to send it a relative change since we're going to be drawing that again to the canvas so we're going to go ahead and get our actor location and we need to then also grab ourselves a offset so we're going to go ahead and make vector and this is we're going to plug in the 900 900 again and we can just plug that directly now into vertex position zero and for these other ones then we need to then subtract because we want to draw a vector from our locate from from our location to their position so we're going to do the position in space minus our actor location and this gives us a vector that's pointing that direction and then we're going to add the offset vector to that and then we will put this first one into the vertex position one then let me drag this out a little bit more and we're gonna go ahead and copy this paste it it's gonna look a little bit messy until we get the pins attached and then so the position of the following index minus our actor location and then add that result to the offset and plug that into our vertex 2 position and the last thing to do is make sure we change our color for each of these back to white to indicate a value of one for our mask let's go ahead and save that and try it out all right and so lo and behold there is our vision cone that is now changing as we encounter things and you'll notice something interesting here this is something just i prefer to do notice it's kind of acting really strange when it encounters a space like a like a flat wall and such and this is because we're drawing our mask right at that exact position so you're seeing any rounding errors etc making the surface kind of flash and such so we're going to do one more thing here that we're going to actually modify as our trace results we are going to go ahead and go back into our create cone function and we're going to then extend this these values ever so slightly let me go ahead and add another pin right here i want to try to move that a little bit there we go and so i'm going to take this directional vector that we have before we've added any distance to it i drag out here and i'm going to then multiply that by a float and this is going to be basically a we're going to use this to basically extend this vector that we've created or this position further into space along the line of the the trace results and so i'm going to grab that i'm just multiply that by let's say 10 for now and i'm going to add that over here and this is what i'm actually going to then be saving into my array right here and just so that we don't have any weird shapes going on i'm going to do the same thing then for the results right down here go ahead and compile that now if i go ahead and hit play if i run into a wall and such you'll see that we're getting a little bit of overlap as it goes further into the wall and i no longer have this kind of weird effect going on where it flashes and you can begin pushing this even further if you want to such that like you can see you know a decent chunk of the ceiling uh you can try to make it smaller so that you get only the minimum possible it's really you know entirely up to you the other strange thing you'll notice is that based on how fine of our mesh we have you're kind of getting different potential shape results right at the edge there so this is where we can then modify our degrees and our num traces so let's see let's increase that from 20 to like 80 and we'll decrease the degrees per trace to like one now if i compile this and hit play we have a lot more traces and we have a lot finer uh of a mesh that we're basically drawing the canvas we can even go ahead and turn off this debug and you can see here that we now have a very nice looking kind of vision cone system running around let's say there are certain types of items and such that you don't actually want to interact with this cone system you can simply either add a custom channel or what we can do here is i will simply find those boxes by first turning off this post process we have i'm just going to select these boxes then all these little template boxes and since we're using a line trace what we can do here is go over to our collision and i'm going to go to custom i'm just going to tell it to only do overlaps for the visibility since that's the current trace channel we're using now if i go back and turn the post process back on you can see that these boxes for example are no longer causing us to stop our vision system but our projectile potentially still is so you can do the same change if you need there i do recommend using a custom trace for this rather than visibility especially if you need visibility especially if you need visibility to work later on for something else you're doing in order to prevent this additional like overlap effect here that we're seeing we're going to modify our material real quick for our post process to get rid of that effect let's go ahead and jump over into our vision system here and we're just going to add in an if statement we're going to go ahead and add a scalar we're going to go ahead and plug this into the a is greater than b and we're going to take the z texture for a equals b or a is less than b and then for b we're going to just leave that as is and we're going to use a constant b of like 750 basically it's going to be whatever the maximum length of our trace is and then for a i just need to know how far away i am so we're going to take our absolute position and our player position and this is going to give us this gives us a vector direction so i just need to get the length and i use the vector3 length and go ahead and plug that in add a rewrote node for a little bit more cleanliness there and now i will plug this into our alpha hit apply and we can go ahead and run this and now we will no longer see that additional kind of repeating tiling texture pattern that we were seeing beforehand so the last thing then to cover is adding in some kind of small little vision sphere around our character because right now all we have is this cone and you can't really see your character well let's go ahead and pop back into our line of sight vision material and we're going to go ahead and add in a new little function here so then right after this if statement i'm going to add a pair of nodes in here i'm going to first add a sphere mask and i'm going to add this result to my if statement then i'm going to clamp that to make sure that we're only using 0 to one for the lerp and for the sphere mask then i'll leave the hardness at 100 and i'm going to plug in our position here to a i create myself a scalar here and i can use this as distance and plug this into both b and the radius now if i complete increase this distance value i can start creating a zone around my object that i can see in so let's go ahead and leave this at like 120 for now compile this and then i can go ahead and look here and we can already immediately see that we've now have a region around the player that they can still see inside of you can make this larger and smaller however you need it to be this is kind of a nice thing in case you want to give your player the ability to see like a little bit behind them just so that they're aware and if you want to make it really small you can do that too so hopefully this has been a useful how-to tutorial for how to create your own line of sight vision system i wish you luck with implementing it on your own games thank you for watching
Info
Channel: Okari
Views: 21,979
Rating: undefined out of 5
Keywords: UE4, Unreal Engine, Tutorial, Line of Sight Vision
Id: BezQiFCGkq4
Channel Id: undefined
Length: 46min 51sec (2811 seconds)
Published: Sat Sep 12 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.