Unity: Water Shader with Amplify [URP]

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome back to polytubes in today's lesson we're going to be creating this water shader which has some pretty cool features packed into it like proper sorted refraction thanks to a user called psy over on the amplify discord and we've got caustics depth edge detection wave height there's uh animated displacement and normal maps and there's even more stuff that we'll cover as we go on i am using the universal render pipeline for this and even though most of the shader portion can be done in shadow graph i will be using the amplify editor because i need to make use of a texture packing tool that comes free with amplifier we'll talk more about that later the main thing that's missing from shader graph that we'll be using is the tessellation as usual all source files are available for free over on my patreon i thank all of you who are silently following and i super duper thank those of you who are supporting the channel it's amazing thank you the first thing i want to address is the animated displacement and normal maps this is using a 3d texture which is kind of like a flip book texture but as the name implies it has access to that third dimension it's more commonly used for volumetric stuff but it has a nice like automatic blending between frames that you just don't get with flipbook textures by default we're looking at the same number of frames here but the example on the left is your standard flipbook texture and the one on the right is a 3d texture it's worth pointing out that the flipbook version on the left is actually running at a slightly higher speed than the other one but you can still clearly see the uh the frame swapping you know as opposed to the other one which is nice and smooth so this is a frame animation and we'll cover how to use an amplify tool to create this 3d texture in a bit but first i'll show you how i got the frames in the first place and it's all just an ocean modifier in blender i will be providing the the dot blend file if anyone wants to have a look but i will also just quickly cover the important steps for anyone who's interested if you're not interested then you know feel free to bounce to the next bit here we are in blender obviously we need to use the ocean modifier and we get that by just slapping it on a standard plane the ocean by default comes in at 50 meters squared regardless of your starting planes size which is worth remembering for later there's a few properties but nothing overwhelming i think like you know you can control the level of detail via the resolution then you know good scale which is you know the scale of the waves which is essentially the strength uh even the direction of them the peakiness of them and of course there's the time which is very important because we're planning on you know cranking out an animation so here's the one that i ended up with in the tutorial and the trick is to just use two ocean modifiers this is because we need to create a loop so the second modifier is set to displace the geometry of the first and we just make sure that it starts from when the first modifier ends after a few experiments i ended up with about 32 frames over a three second duration meaning i'm cramming about three seconds worth of this ocean moving into about 30 frames which you know at about 30 frames per second that would actually be one second but we can control the speed of this later in unity so the only time that we're concerned with now is the ocean modifiers time so i found that a rate of about 10 frames per ocean modifier time like one second of that worked out quite well but feel free to experiment for yourself just don't try to cram too much time into too few frames otherwise the blending can get pretty nasty as you can see here it's also worth mentioning that my ocean bake frames are actually set to 33 not 32 this is because the last frame will always be the same as the first when it comes to a looping animation and so you know there's absolutely no need to render it we're not actually going to be baking these modifiers by the way but we do need to set this up here regardless just so it knows where we plan on ending the simulation so to get this all working we need to animate the time and scale values of both modifiers for the time where the first modifier starts at zero and goes to three the other modifier will start from three and end by the same amount of time as the first modifier increased by so you know that's plus three in this example so if your first modifier went from zero to five then your second would go from five to ten you know i hope i hope that makes sense similar-ish deal for the scale but it's more about like opposing numbers here because this is basically the strength of the modifier so we need one to be the max strength that we want while the other has none and then end on the opposite so where one starts at say three it will end on zero and the other will start on zero and end at three once we have our loop we need to get the camera ready and it's also worth pointing out that i'm repeating my ocean on the x and y by two this is because i want to make 100 sure that i don't have any seams in my textures so i have four of these ocean planes now each at 50 meters squared which all tile and then my camera which is set to orthographic so you know like no perspective rendering a 50 meter squared area right in the middle of these four planes and pointing straight down this will give us a perfectly seamless and tileable result so we have our loop and our camera set up now we need to get our normal and displacement maps out of this so we'll start with the normal as that's the easiest because blender actually comes with this normal map mat cap which blew my tiny mind when i found out like this is such a nice thing to have for pumping out quick normals to get the proper colors of a normal map in the viewport we do need to make sure we're using the srgb as the display device this might be a bit confusing for those of you who are familiar with the idea of normal maps being non-color or linear textures but this is still true it's just we need the srgb display device in order to see it correctly in the viewport because we're going to be rendering it from the viewport you also need to pay special attention to the camera's render size i've set mine to 256 as this is the max that i want my textures to be remember that we're pumping out like a 32 frame animation here so you've got to make do with low resolution textures unfortunately this is also the section where you specify the output directory the file name and the format for the normal maps we will go with a png and rgb at 16 bits then you just come up to view and render the viewport animation so long as you are looking through the camera that is and it will spew out all 32 frames into the you know the place that you've specified similar routine for the displacement but this time we need to swap to material mode and we will use a material that will give us a black and white ramp where the uh the blackest is the the bottom and the widest is the top top toppest isn't wood at the top you know what i mean anyway i'm just using a texture coordinate node and i'm splitting the z generated vector seems to work well enough i'm quite new to blender so maybe there's another way to do this we need to not be using the srgb display device anymore though as we're not interested in seeing any color information in our viewport so go back to that and change it to none don't forget to change the output file name for this otherwise that might get a bit confusing if you've called your other ones normal maps and then you just bake out another set of normal maps that aren't normal maps so you know file name quite important and we're going to change the file format to open exr and now we have access to rgba float which is like four billion colors or something pretty important for displacement accuracy we definitely don't need this level of accuracy for our purposes but if i don't do this then people in the comments are going to be angry and i may even be a little angry with myself to be fair so yeah same deal just render it out and dump all of these frames into unity so now that we're back into unity with all of our animated frames i'm going to make use of amplify's texture array creator which aside from creating regular arrays has an option to pack into 3d textures which is what we want i should mention here that if you don't have amplifier installed then you won't have this tool i did have a hunt around for alternatives but there's so much terminology confusion in regards to like what is and what is not a 3d texture that i wasn't able to find anything moving on though it's a pretty simple tool to use we just select all of the textures we want to pack bung them over into the tool specify the resolution you want bearing in mind we rendered ours at 256 so that's you know you don't want to force it into a 512 because that's just gonna upscale it um so 256 for the normals is fine but for the displacement i think i brought this down to 64. you don't need a lot of high-res detail in the displacement for this obviously make sure you enable the 3d texture checkbox and then the only two things left to worry about are formats and output directory plus the file name so three things i guess then when you're done just hit the button at the top and it will pump out your 3d texture you don't need to keep the original frames if you're trying to save space but you will need to keep them if you plan on making changes to size and resolution later or if you just happen to lose it then you need to remake it i'm it's worth keeping the originals so do this for the displacement and normals making sure you specify different file names before building the texture because i think it will just overwrite without asking so something to watch out for and for the texture formats it's generally pretty safe to keep it as a rgb 32 but i did some experiments with the normal map and with a 256 texture size for each frame i ended up using uh rgba four four four four four four four four four fours um i'm not a bit depth wizard or anything but the normal map worked fine and the file size was like half of everything else which um is worth mentioning actually you do need to be careful about your original texture size and the number of frames that you're using you can see here that our pack normals ended up being eight megabytes which okay it's not the end of the world at all but the next tier up is a 512 texture if you wanted more pixels and if you want a more unique movement you'd need more frames so you could easily like accidentally end up blowing hundreds of megabytes on this so you know be careful finally we can move on to the shader portion of this video and i'll be running through the creation of this in a segment by segment style rather than recreating it step by step so to begin with i'll just be disconnecting everything except the smoothness and then i'll apply this change and if we come over to look at the material you'll see that you know we only have our smoothness here which is expected because it's the only thing hooked in but there's also controls here for tessellation and these are here because it's enabled in the shader so you know we get them automatically in the material uh along with some other settings that are pretty important for this video like making sure that we're using transparency and enabling two-sided so you know we can go underwater and look up and lastly making sure that zed write mode is enabled and the main reason that i have to enable z right mode is because i'm using two-sided so if you don't need to use two-sided then you probably don't need to enable z-right mode unless you've got like some massive waves going on in which case it usually helps out there since we're fresh off the boat in regards to 3d textures that's where we'll start by putting the shader back together again remember that we're using 3d textures for both our displacement and our normals we can use a regular texture sample node for this though just make sure that you lock the autocast to texture 3d that way the property for this in the material will only accept 3d textures and of course make sure that the one containing your normal map has the unpacked normal map option otherwise unity won't recognize it as a normal map the trick to these 3d textures as an animation lies within the uvs which is what this little get node is all about but before we move on to the uvs i'm going to simplify this part here and essentially remove the side fix so i can show you why it's important later okay so the uvs for these 3d textures that's all of this over here and i'm starting with the world position node because like a lot of my water tutorials i'm using world space mapping meaning i'm just projecting uvs from the top rather than using the objects uvs it helps a lot with you know tiling across meshes that don't tile and things like that but you see here i'm just creating an example of how you would do this for regular textures the main difference to keep in mind is ordinarily you can append x y or uv before you multiply in your tiling vector whereas with the 3d texture uvs we are appending after the tiling which is why we need to split the x and the y or the u and the v separately before it gets appended together and the reason we're doing that is because we also need to make use of the z or w channel to scroll through our frames in the array i apologize if this is confusing it's just that xyz is what we're looking at on screen but in uv terms it's uvw world space mapping is a good thing to get into for water in general like i was saying before about how it kind of just avoids a whole bunch of seam and tiling issues but the main reason i'm using it in this scene is because i have the sides of water which need to offset by the same degree as the top but we'll talk more about that in a bit when we actually do the offsetting stuff so let's move on and hook the normal map back into the shader you can see weird streaks of lighting moving across the sides and this is because we're using world space mapping so our normals and later on with our displacement are being projected from the top only this is why i had that little side fix group over here which is using the y world normal as a mask for the normal map strength meaning if an area is white which would be anything with like a a y facing normal it can be controlled with our slider and if it's black then it you know it has no input it will be zero so pretty simple fix which is always good so it's the same deal with the displacement since that's using the same uvs we've made you can ignore this other register node here we use that as a mask for color later on and also this section here that's not connected is a cheeky little wave smoother which i'll cover later as well the only important thing happening here is we have a black and white animated displacement and we're multiplying it with a vector 3 but we've zeroed out the x and z values so it's only multiplying on the y value which is up and that's it really simple stuff the remap node is only here because i wanted a zero to one slider on my material it's not required at all so if we hook this back in it will do as you expect really it will take the white values of our texture and displace the mesh upwards using this information and the reason that the sides of the mesh are also conforming to the same offset is again because of the fact that we're using that top-down uv projection if you were to use the object's uvs which i can show you here by using a vertex texture coordinate node or maybe even a regular texture coordinate node would work and just save this out you can see that the mesh splits at the edges and it's because we're using the mesh's own uvs which means it's going to offset in different places so i'll just undo that nastiness and get things back to the way they were the other thing to mention at this point is you might want high waves but you don't want your waves to clip through your geometry like your land so the way that i've solved it in this example is through this group here called the cheeky little wave smoother it's cheeky because this is a specific example of um my water just being confined to this space as opposed to you know like an entire world of water but the logic is still mostly the same you'll have something that detects where land is and you can use that information to control the wave height in this case it's just a simple texture that i got from painting over a top-down screenshot and fiddling with the scale and offset until it matched up the sped up video you're seeing now uh was after i'd gotten the correct scale and offset which is why the texture fits so perfectly after i give it the right rotation at least but yeah that's what this grouped area is all about so i just register all of that and then get it over in the displacement group and multiply it into the chain after the part where we're controlling the strength and direction of the displacement so then the black and white values of our texture will be taken into consideration as well which is you know it's obviously what we want since we're still at the displacement group i'd like to point your attention to this other register node we have here which is just the basic result of our displacement you know we're not modifying it in any way we're just registering it here but i'm using our displacement texture as a black and white mask to also tint the albedo a bit so we can use a loop that says if a value is white or one do one thing and if it's black or zero do another so i've got a color node here and i'm also adding that color by a small amount so i can have a base color which goes into the a slot and then my added color which will always be slightly lighter than my chosen color will go into the b slot and of course the registered displacement node acts as our mask so that goes into the alpha slot the effect is quite subtle as it's just supposed to emulate like a bit of lighting with you know water being thinner at the peaks but if i exclude the mask and just pump the one color into the albedo you can see that the difference is you know quite strong it's it's it's horrible as a certain class of english people might say so let's again put that back to the way that it was we're on the home stretch here but this last note for the emission is a pretty complicated one i i wish i could tell you that it's just this one little group here and you know there we go end of tutorial but now it contains all of this magical refraction caustics and all of the depth masking basically so we'll start with the refraction and just like in the last tutorial where we were distorting the air with this heat haze i'm using this custom function from a user called psy over on the amplified discord which sorts the refraction properly meaning we could distort geometry underneath the water surface only as opposed to the common way that it's done which also distorts things above the surface which sounds stupid but it's basically just getting a texture of the whole screen and then distorting it based on your normal input so with this custom function that doesn't happen it you know it can mask out what's underneath the water of the surface so this little purple node on the left here is just our animated normal map since that's what we want the refraction to be based on and of course we have a slider to determine the strength and it just feeds out through a grab screen color node into a register here called distortion so if i go over here to the final emission node and i change it to use the distortion only you'll see what's going on with this we've got ourselves some deliciously clear water i mean that makes me super thirsty just from looking at it but it's not quite correct for what we want so as nice as this is we do need to start thinking about introducing depth as an aside it's worth mentioning at this point that you will need to have the depth texture enabled on your urp settings for this to work otherwise everything will appear white for you and if you didn't already you also need to make sure the opaque texture is also enabled this is what lets you use transparency and it's disabled by default for reasons so if we come up to here this is the part where we're controlling all of our depth and the base of this is just subtracting screen depth by surface depth but we have the added bonus of being able to output the refraction uvs that we're getting from size custom functions so we can include that as part of our depth calculation to make sure things are being distorted correctly while underwater and that's what that purple get note is there if i just create a test get node here and feed the early portion of this setup into it along with a one minus and a saturation hopefully you can see what's happening here the depth portion here is all white and if you look at the capsule in the water you can tell that the refraction is still occurring so this is what we want to use as a mask to do things like show how much clear water is visible to show the caustics and of course the edge foam too which in this example is not really foam as much as it is just a line but if you wanted to expand on this and use that as a mask for a texture then you know by all means please the reason i have these two purple register nodes here is to differentiate between the edge detection which is where the water meets land and the depth in general they're using the same kinds of nodes here it's just one of them is using this float constant with a valley of 12. i think 12 is just what i thought was a nice thin line for the show you of course can do whatever you want and the other one has this slider range which i'm actually controlling for the you know like the proper depth all of this depth mask stuff in this group is what we're using at the very end of our emission chain to control the range of things like the refraction the edge foam and the caustics so it's probably a good time to talk about the caustics part of this before we finish up with connecting all the depths and i just realized am i saying cow sticks correctly caustics caused the cows to cause the girl jesus caustic caustic oh no i've been saying it like the americans so to begin with let's bypass all of the depth connections at the end and just stick this group into our emission slot i should also mention that we're using a modified version of this uh reconstruct world normal from depth that allows us to input our refraction uvs which means our caustics are also going to be refracted by our normal map if you didn't have this it's not the end of the world but i have included this function with the uh the download on patreon because while there's nothing wrong with modifying existing functions it does mean you might lose your modification when you do an update to the plugin the edit to this is super basic though just open the function or a renamed copy of it and then add an input node set to a vector2 give it a name and stick it in after the screen position node this input node is what allows us to call the function in a shader and then we can plug in our own vector2 into it which for us will be the refracted uvs i'll also mention now that i am using the varonoi node here which is not the most efficient way i could have done the caustics i do recommend either panning noises or even a small flip book for this but since the shader is expensive anyway we'll just continue with procedural caustics it's feeding into a smooth step note 2 which is optional but it helped crisp out the effect which i thought was nice if you're using your own texture for this or whatever then obviously you might not need to do that the purple get node called time that you see here hooked into the angle slot of the varanoi is actually the same time setup that we're using for the animated uvs like right at the start of this shader portion but as you can see i'm multiplying it by a value before it goes into the angle so it's not the exact same time not that it made a massive difference but you know still so let's take a quick look at what this is doing remember that we've skipped all of the depth masking so the result is going to be pretty full on yeah okay so it's pretty neat for sure and oh i almost completely forgot that like the whole underwater stuff so just in case i forget again it's just a post process volume but you know hopefully i'll cover this at the end of the tutorial so let's go back into the shader now and we'll multiply our caustics by the depth mask so this is the one literally called depth as opposed to the edge foam which is still technically a depth mask but anyway we'll do that and the results will of course show us that our underwater lighting is now restricted by the depth of the water which you know makes sense and it's pretty cool you'll notice though that we are of course only seeing the car sticks here and not the sand underneath this is because we also need to bring the refraction back into this which also has to be affected by the depth itself and that's what this little chain here is all about we're just taking our distortion which was the end result of that depth mass refraction function and multiplying it by the same depth setup as the one we used for the caustics then just add it all together and let the magic happen i am using saturate nodes here too and this is just a stop blowout basically it keeps values in the zero to one range my general rule is if i'm sure i've done things correct but it's looking wrong then i need to clamp some values and that's what the saturate is for lastly but not finally we'll add on the edge foam depth mask and multiply it by a simple slider to control its strength keep in mind this is not going to control its size we would do that much earlier in the chain remember i had that float value at about 12 that is for the size this is just to control its opacity basically and there we are the shader is done and i haven't forgotten about the underwater effect either i will just say though that this is a pretty low effort on my part i threw it in as a little bonus is uh it's not really related to the shader at all in fact it is not related to the shadow but if you see over here in my scene hierarchy i have two objects one called post process and one called post process underwater you will need the the default unity post processing for this to work but the general idea is you can stick a script called volume on one of these empty objects and again if you don't have the post processing installed you won't be able to find this script and from there you can chuck in a post processing profile which you can create anywhere in your project tab from the right click create menu and add in a bunch of lovely goodies like uh bloom tone mapping and whatever else then on your script you set the mode to local and at this point it will ask you for a collider so just add a box collider onto the same object or any kind of 3d collider and now you can create a space in which only these post-process effects will be seen so i made two of them one for the above like the surface of the water and another for below uh yeah the other thing that i completely nearly forgot is i've grabbed the textures in this scene from a website called 3d textures dot me or dot me i don't know how the cool kids say these things but anyway it's one of those sites where you can get royalty free pbr ready textures and if you like what you're seeing you can always help them out on their patreon which i think is kind of cool moving away from all this forced subscription-based stuff and instead the content is just free but those who want to support it you know can always do so kind of like my patreon which you should absolutely check out if you want to freely download the source files for this tutorial absolute final 100 lastly i want to thank my amazing fiance who made this little greek island scene for all of you while she continues to get the grips with blender so a big round of applause for her please but that will be that so thank you very much for watching uh this last bit of dialogue is pointless because nobody listens to the end of videos but thank you anyway i hope it was of use and uh i will see you in the next one [Music] you
Info
Channel: PolyToots
Views: 38,992
Rating: undefined out of 5
Keywords: 3d coat, unity, sculpting, game dev, texturing, baking, unwrap, uv, game art, shaders, amplify shader editor, tutorial, blender
Id: zD6GV6bZenM
Channel Id: undefined
Length: 26min 15sec (1575 seconds)
Published: Mon Sep 21 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.