Oceans with Unity Shader Graph.

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello and welcome back to polytubes in today's lesson we're taking another look at a ocean shader using shadowgraph i say another look only because i've done like two of these before but there's been a lot of improvements to shadycraft since the last time i touched it which is probably like nearly a year or so ago not that anyone cares so we do have some refraction happening here uh there's a texture-based displacement we've got some normals it is the same idea of just two textures panning in opposite directions for those of you who are familiar with this technique but when you are using proper height and normals it looks a bit more convincing i should specify this is a good base for a water i do advise that you improve upon it but for the sake of this tutorial we're going to try to keep things simple try to keep it under like an hour long of just me rambling so if you like what you see and you want to learn how to do it then we can just go ahead and start that i will just mention quickly though that the walrus cave that you see here is uh not going to be available for download on my patreon but it is freely available on sketchfab and this time i've got the model from a user called rosie jarvis she's got a lot of cool hand-painted stuff i recommend checking out her work and giving the account a follow and i will be providing a link in the description for this specific model if you just wanted to check it out so onto the actual tutorial i'm just going to start by creating a new blank material and i'll just put that on my plane just so we're starting with a clean slate and before we begin any shader stuff i just want to mention that for this whole thing to work you do need to change your pipeline settings so if you come down into the folder here called settings and then you'll have the three quality settings so make sure you select whichever one you are outputting to by default i think it's the high quality one or you can just go ahead and change all three but either way the important thing here is that you enable the depth texture and opaque texture if you don't do this things are going to get pretty screwy it's a common mistake because even if you don't tick the depth texture everything will look fine in your scene view but your game view will be completely wrong i know it takes me forever to actually just get to the tutorial but there is another slightly important thing to mention here at the moment shadowgraph does not support tessellation and since we want to be doing a texture-based tessellation we need to supply the geometry ourselves so i'm just going to be including a subdivided plane for this in the future i imagine we won't need to do this or if you're using amplify shader editor that has tessellation working but for some strange reason shadow graph this is not supported not sure about hdrp but the urp it's a no-go so we'll just use this for now so let's create ourselves a shader and we'll be using a pbr graph call that whatever you want and open it up and the first thing that we're going to work on will be the refraction and the way that we're going to be doing this is by using something called a grab pass which essentially just takes a picture of your screen and then we're going to distort that texture based on a normal map so we're going to put down a sample texture 2d here and we're going to create a property for texture2d and we'll call it normal map then we'll just drag that in and hook it up and make sure you set the type here to a normal which reminds me actually for the normal map itself by default it will import into unity as a default texture type so just make sure to change it over to normal map that way unity knows to read it as a normal node but anyway back to the shader we're going to want to combine the red and green channels of this it will probably still work if you use rgba but the alpha component of this texture has nothing in it and the blue channel of a normal map is essentially the flat channel so it doesn't contain any information that we want at least that's my understanding so yeah we'll combine red and green and then we'll get ourselves a multiply and make sure you only use the rg2 slot here because we are only putting two things into this node so there's no point in us outputting you know a four or a three channel we only need the two channel and then we just create a vector one and this will be the refract strength and so that's what we're going to put into the b slot of our multiply now we have something that will essentially control the power of our normal map but of course that by itself isn't going to do anything we need to create something for this normal map to so we're going to grab ourselves a screen position node and then again we'll split this on the r and g channels and combine it again with rng and output only on the two slot and then we'll just add it all together and add a scene color node onto the end of this that's pretty much the refraction done so we can hook this into the albedo slot now and just have a look at what's happening here obviously we need to change over our material so that it's using the actual shader that we've been making and by default every shader you create with shadow graph goes into the shadow graph directory which is kind of lame if anybody knows how to create your own directory then please let me know but either way we'll put on our shader and we'll throw in our normal map and now you might notice that things are getting a little bit wonky here and that's because we need to change over our pbr master node here to a transparent workflow so that's a tiny mistake on my part i promise there's only like three or four more mistakes in this you can see with the normal map on we have a refract strength of zero so nothing's really changed we can see through it which is a good sign but if you start to change the refract strength you can see that it is distorting our texture based on the normal map that we have so if you're using a different normal map it will refract in a different way so since we're done with the refraction part of this i'll just select all of the nodes and hit ctrl g on the keyboard to group these together i don't know where else you would hit ctrl g i'm not sure why i have to specify on the keyboard but you know i'm just speaking here and words are falling out of my mouth without me thinking before i move on uh i do just want to mention that there is potentially a better way or a more accurate way to do this refraction and this is from a website called coding black and in his example he uses a custom function and a tiny bit of code and so i've built that same thing using the normal map texture 2d which influences the index of refraction i will be including this node setup in this uh shadowgraph but for the sake of the tutorial i'm not going to cover it it's all on codenblack.com which i recommend checking out anyway the guy seems to have like a lot of cool tutorials there as i say i will just be using my simple refraction here which which seems to do the same thing at least in my inexperienced eyes but i imagine that the other node setup is probably handling things in a better way moving on though currently our refraction is working across the entire canvas and i want to mask that out by something and the thing that i want to mask it out by is depth meaning if there's an object underneath the surface of this water if it's close to the surface then it will be refracted whereas if it's you know quite far underneath the water then i have no need to refract it and the way that we're going to calculate the depth here is with a scene depth node which as you can imagine gets the depth of the scene and we want to do this based on the camera so we're going to multiply this with the camera node and use the far plane option and then we're going to subtract this by a screen position node and make sure you set the mode to raw and we do only want the alpha of this so we need to throw in another split node and then grab the alpha and that's what goes into our subtract lastly we will just throw on a saturate node at the end of this because we got a lot of things happening so it's a good time to just clamp these values so they don't go below zero or over one and then we'll just grab all of this and we'll overwrite the albedo that we have now just so we can see what this looks like and so you can see that our depth is being calculated here and it's appearing as this sort of black uh gradient essentially which is fine but for masks typically it's the white value that lets something through and it's the black value that does not so we want to come back to our shader here and throw in a one minus so that our mask is inverted and then we can start to do something with it you know we can use the white to let the refraction through and the black will not the other thing that we could do here is at the moment we can't control this at all you know we can't control its strength we can't control its size so we'll just throw in a couple of multipliers and some vector ones the first one comes after our initial split here so the split from the screen position we want to multiply this by a vector one so we'll make that a property and we'll call this the depth distance so this will control the actual distance of the depth itself and just replace that with the node that was there before so now instead of the split going into subtract we have split into multiply with our vector and that goes into subtract and then we'll just throw in one more at the end here but before our saturation node and this will just be the overall strengths so you know if you can imagine because this is at the end of this node set up here this property controls you know the overall power of everything that's come before it so it doesn't matter what we've done before this is kind of like the master power note like the master volume on some sort of game that you're playing you know you can tweak all of the little sound effects and whatnot but ultimately there is a master controller and this is that once that's in we can just give it a quick look and see what's happening and i'll be honest i'm a little bit confused as to the way that the values work here in that for the depth distance to even come into effect it has to be you know like about 0.9 i maybe this needs a remap or something but it works so i'm happy with that i'm just a bit confused by the actual numerical inputs that we have to do but my confusion aside it works you know we can control the depth and we can control the overall strength of it and you'll notice that as you rotate the camera around that does change how this looks i believe this is even the same with the amplify version but something about this it seems like it's moving not moving it seems like it's changing too much but could be could be me i will be building an updated amplify ocean after this it's going to be not the same it's going to be using something pretty cool so i guess at that point i'll see if this depth stuff behaves the same maybe it's a unity thing rather than a strictly shadowgraph thing but we'll find out soon enough i've been rambling on a little bit too much about that so let's just go back to the shader now once more since we're done with this we'll select everything ctrl g and give this group a name and so now that we have this set up we need a way to combine this depth with our refraction because remember we want to use this as a mask to show what is being refracted and what isn't and the easiest way to do that is with a loop and the cool thing about loops is it is just an a and a b slot and then a mask and the mask you know it's just a black and white value and it defines you know what shows in a and what shows in b so we'll use our depth as our mask and then we'll throw our refraction into the b slot and we'll leave the a slot blank for now which means you know what will be black will stay black but what will be white will allow our refraction node to come through so quite simple just hook it all in and we can just go and see what that looks like seems to be working okay and of course we have our controls for the depth so we can control how deep this refraction will go and the overall power of it so pretty cool stuff now that that's all out of the way i think it's time to actually make our water look a bit more like water so we're going to move on to the normals next which means we're going to start by just placing down a sample texture 2d and we already have the normal map as a property and that's what we'll be using obviously now make sure you do set the type here to normal i forgot to do it at this point but i will remember to do that later but you can do it now if if you want and then you can say that you are better than i am but then after you've changed your type to normal you can add in a normal strength node i find it's always good to use one of these when you're doing oceans and various water bits and whatnot because you know it's nice to be able to tweak your normal map just keep in mind that you usually only want to reduce the power of your normal map you never really want to increase it because you can't add detail to your texture and so to control that we'll just create a vector one call it normal strength and this one we can actually turn into a slider since we know we know we only want a zero to one range you know you don't want to go below zero on your normal map strength and you don't really want to go above one and now if you remember at the beginning of this tutorial i was talking about how this is the uh the dual panning like the opposite panning technique so for this we're going to need to create some uvs of our own where the texture is actually scrolling so to do that in shadowgraph we create a time node and we're going to multiply this by a vector2 and the reason we're using a vector2 in this instance is we want to be able to control the x and the y independently because we're dealing with an offset here so you can if you want use a vector 1 it means it will scroll x and y at the same value that you put in but i prefer to do a vector 2 so i can either have you know my x be blank or just a small value in x and a high value in y i say hi but i just mean 1 basically because we're going to multiply this with another property which we'll call our pan speed and this ultimately affects the speed but the vector 2 technically also does control the speed but we only want to use that to control the direction so just keep the vector 2 between values of 0 and 1 and then let the pan speed vector do the rest of the work so once that's done we can add in a tiling and offset node hook in all of these nodes into the offset and throw that in and we can have a quick look at it and you can see here how the vector2 is only controlling the direction so if you come here and just minus the amount then it will go in the opposite way oh actually i think i just mentioned that you should just do a zero to one range no sorry you can absolutely do a minus in the vector two because if you wanted to go the opposite way it needs to be an opposite value oh i'm a good teacher but anyway while we're here and while we still have the tiling and offset node we might as well create ourselves another vector one and we'll call this one the normal tiling so this will control the actual tiling amount of our texture and we'll just stick that straight into the tiling slot pretty handy now there's two things that i noticed were wrong here for starters my plane has that little corner on the side that should not be there and by the time i come to upload this stuff onto my patreon which is uh free by the way you don't need to pay to get this stuff uh i will have fixed that so it will be completely square because you know you want to be able to tile these planes around without having a weird hole in the corner of it the other thing i noticed was the normal map being not set to a normal map so i just fixed that here and now we are both equally intelligent on a more important note however you'll notice that there are these seams in between these two planes and that's because we're doing these uvs based on the actual object uvs you can do world space if you want i have a tutorial where we do that but for this i know the textures are tiling and we're not doing any procedural stuff so i figured it was just easier to do the object uv space which means your tiling number needs to be like a round number like you know has to be one two three four i'm sure you know how to count as well as i do you don't want to do like half values or point things because that's when it will not work it would be nice if on shader graph you could set a vector one to be locked to like an integer range like with amplify pretty sure i said indigo into integer into doesn't matter um maybe in the future they'll do an update but for now you'll just have to remember not to do a decimal point you're just you know one two three four i'm counting again jesus stop it okay back to work we can just grab these scrolling uvs that we've just made and just slot that straight into the uvs of the refraction stuff that we had done so now as this normal map moves so does the refraction of it and since it's using the same tiling as well everything is lined up one to one because it's using the same normal map it is worth quickly pointing out here that the normal strength property that we've made is still only controlling the strength of the normal map itself and not the refraction which for me is fine because i don't ever intend this water or any water i make to have a normal strength of zero so there will always be some amount of refraction happening anyway but if you wanted to tie it together then you just have to stick in a normal strength node into the refraction area as well and just use the same vector one property that we have for the normals so sticking with the normal map stuff we need to create a duplicate of what we already have and then just pan it in the opposite way so i'm just going to copy over the sample texture 2d and the detector 2d property and also the normal strength make sure these are using the same properties that we've already set up because we don't want to create anything new here like it's going to use the same strength property we're going to use the same normal map we're just going to use different uvs and to create the different uvs we're just going to copy over all of this panning and tiling stuff that we already have and just paste it above and so at the moment it's you know it's exactly the same if we were to just put that into the uvs of our duplicate normal map it would seem as though we haven't done anything so the first thing i do is i just hook in the time node that we're already using from the first one just to get rid of the time node that we've duplicated i don't know if this makes any difference in code but i figure less nodes is probably more efficient and then of course make sure you change your vector2 values because this is the this is going to be the new direction of this panning normal map so you don't want it to be the same as what we already have because then it's just going to move in these in the exact same way you can go with opposite values here if you want it doesn't really matter so long as they are different and you can always change it after the fact anyway so just get something in there that is not the same as what you already have and for the tiling amount i like to keep it as simple as possible you could if you wanted create a whole new vector one to control the tiling amount of this duplicated normal map but what i prefer to do is just i create a multiply and i feed that back to one property of the normal tiling into it which means i'm still only using one vector1 property but whatever the value is it will be multiplied by an amount for the other normal map so you know it will always be bigger than the original this is just the way that i do it if you want like i say you can create a whole new vector one for this and just you know have complete control over how big it is same for the speed i leave the speed alone because technically if this texture is larger or tiling more than the original one it's going to have the illusion of moving at a different speed anyway so you know that's that's just me trying to keep my material as simple as possible but you can obviously do whatever you want so when you're done with all of that make sure you use a normal blend this will blend the normal maps together correctly and then you can just see what that looks like and the effect should be quite immediate and quite obvious there we are it's looking pretty okay i do recommend going back into your shader and you know tweaking with the the values like how much you want something to be panning by how large you want the other normal map to be compared to the original one little things like this until you're happy with it basically you may have noticed though that we're not doing anything additional with the refraction so we're not duplicating our refraction to make sure that it's you know accounting for this normal map that's panning in the opposite way and for me this is because the illusion of the refraction is already working like i don't need it to be so accurate that i have to you know create another duplicate of my refraction to feed in these new uvs to account for the other normal map that is going in the other way you can if you want you're more than free it's basically the exact same setup that we've just done but personally i kind of think that's overkill but anyway as usual now that we're done with both the normals and the panning and tiling uvs we'll just select all of those control g to group them give them a name and uh yeah we can move on to the next bit which will be the displacement and so for this we are going to use a height texture that i've created and again just worth pointing out that all of this is available if you wanted to grab it for free just do a hobbity skippity along to my patreon and uh it's all there so we're going to create another texture 2d here and we'll just call this one displacement and now instead of creating a sample texture 2d to put this texture into we need to create a sample texture 2d lod because that's the only thing that works with the vertex position offset stuff that we want to do i don't know why but you know it is what it is now's a good time to mention though that these aren't just random height and normal images they were created together like they're they're part of the same set as as it were like if you had to use a different height with these normals it would look incorrect and you know vice versa and if you were curious as to how i've acquired these it's basically just using the ocean modifier in blender which i highly recommend checking out not just the ocean modifier i mean blender in general if you haven't used it it's incredibly cool but anywho since we know that we are going to be doing the different uv opposite panning thing we might as well start off with the duplicate now and we can already feed our uvs into this since we already have it made and then we'll just add these together and throw in a saturate because you know again we're combining these two values together so it's a good idea to clamp them and of course we do want to be able to control the strength of this you know to determine how high our waves will go so we'll just create a multiply and get a new vector one call this you know something like display strength and just hook that together now we need a way to tell unity like we know which way we want to displace these normals so we're going to create a position node make sure the space is set to object and we're going to split this but we're going to combine it into a vector3 with the r and the b channels only red and blue and we'll grab that multiply that we had created and that will go into the y slot of this vector three essentially what this is doing is we are controlling the power of the y value only and in this case y is going to be you know the object's position which is which is i suppose the same as the worldwide but either way this is just easier and i don't know what the hell is going on with my shadow graph at this point but this always seems to happen where after a while anything i group if i try to move it it just goes absolutely nuts but anyway feed all of this into that position offset and now we can save this out and have a look and uh you know it's pretty cool it also helps i think ease the um apparentness of the fact that we're just panning like two textures in opposite directions because these waves are almost you know hitting each other and it's creating this nice kind of movement at least in my opinion so now the last thing that we need to do is just the color and it would be good to have the peaks of our waves be a different color to the surface itself it's almost as though you know you want it to be a slightly lighter color because it's a bit thinner than the ocean itself so more light is able to come through and for this we're going to use that same height map that we have because that already has the perfect values that we can use you know it has the white for the highs and the blacks for the lows so if you remember the logic behind the loops that's pretty much the same thing as what we're going to do here so we'll create a loop and we'll feed the saturated version of both of our height maps blended into the alpha slot of this loop and so what this loop is now saying is you know if there is something that is white in this texture display something in the b slot if there's something black in this texture display it as the a slot so we're just going to create two colors put them in a and b one's going to be the top color one's going to be the bottom color and that is about it now we can feed this loop into the other loop that we've made because that's going into our albedo because before you know what we were saying with the refract the depth mask is allowing the refraction through but what isn't calculated by the depth mask is just appearing now as black whereas we want to just say no more black we're going to feed in our two colors and then just for a good measure since we are adding all of these things together i am going to just put in another saturate node here just to make sure that you know out of all of the things that are combining together here at the end nothing is going to be blown like outside of the zero to one range one thing i will just say quickly is i did try to add in that object intersection like when an object hits the water it has some sort of like edge foamy type thing but i could not get it to work correctly and that you can see here there's just these horrible outlines appearing on the surface of the ocean and even though it's using the same surface stuff that we're doing for the refraction i just could not get this to go away and it appeared in the game view as well so in the end i just i gave up i think it's probably either a shadow graph issue or a unity issue hopefully at some point this will just be fixed but yeah otherwise unless i'm forgetting something which is i mean completely likely i think that will just about wrap it up as usual if you have any comments questions or concerns you can just keep them to yourself no no i'm just kidding it's always nice to hear from you even when you're telling me that i'm doing things just incredibly wrong because you know we've we've all got to learn somehow and i know i've mentioned it a few times already but i do have a patreon and that is where all of the source files for my tutorials will go so if you wanted this just as a unity package of course not including the walrus cave then you can just go over there and you can just grab that for free it will also contain the textures and the shader nodes if you just wanted to rebuild this shader yourself rather than having the uh the final product handed to you it's up to you obviously i will be working on a amplify shader tutorial for an updated ocean at some point i don't know if it will be the next tutorial but it will definitely be a tutorial that is coming along soon and it's not just going to be a conversion of what we're seeing here there is some uh some genuinely new things that we're going to be doing there and it should be pretty cool but i don't want to say too much just in case none of it works out and i can't actually do the tutorial but we'll see so far so good i also just want to give a shout out to my fiance who probably isn't watching this video or if she is she probably hasn't made it this far she is currently doing a bit of work a long long way away from me so i just wanted to let her know that she has missed and i'm pretty sure i haven't killed your plants yet but you know there's still time so pretty sure that's the end of the video thank you very much for watching and a big big big thank you to my patron supporters yeah i will see you all in the next one [Music] you
Info
Channel: PolyToots
Views: 38,186
Rating: undefined out of 5
Keywords: unity, game dev, uv, game art, shaders, tutorial, shader graph, shadergraph, nodes
Id: kgXeo2SRDd4
Channel Id: undefined
Length: 27min 0sec (1620 seconds)
Published: Wed Jul 29 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.