Ocean Shader | Unity HDRP Shader Graph Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
okay so recently i've been messing around with uh water shaders a bunch in unity specifically like an ocean shader in the hdrp shader graph just trying to implement things like foam refraction all that good stuff you can see the shader here the it's kind of what i want to like show off um it's got the uh wave crest boom edge foam you have some depth refraction and some blurring effects as it as the depth increases um i'm using unity's built-in tessellation although it's not really necessary with these planes with these water planes but if they were lower res this would you know be a lot more apparent i guess they're a lot more useful um yeah um and yeah i have the everything split up into different tiles in the ocean or different planes um and everything is tiling together using you know uh the world position of the vertices to sample textures and stuff and this is just the basic scene i was using to like test everything it's just some terrain a couple objects but yeah i'll go through some of the steps or showcase the steps i went through to make this um so i guess before you start doing anything we can change some of the settings in this graph inspector um so our material will obviously be lit material type we want it to be standard uh surface type we'll set it to transparent so we can access things like the depth buffer um color depth test is fine um we want it double-sided whatever that option is that might be in the material options you can enable tessellation it'll add this tessellation parameter right here or you can just use the normal vertex position offset if you'd like and then i believe oh yeah and then if you want the so i was using screen space reflections in my shader you could just check that enable it right here receive screen space reflection transparent um if you do want the screen space reflections you will have to enable them in your project settings on your camera i believe and then i was using a gerstner wave generation uh to take care of the height displacement and everything tiled together with one sine wave or combined together with the sine wave and to do that i used this uh i was referencing this article on the developer on this like develop developer in a video article video it just goes over different uh equations for generating sine waves and or different types of waves such as sine waves i used scroll down i use this gerstner wave function oh you can see so for the x and then this y would actually be z in unity we have this will this be the equations for the offsets and then this is our this third equation is for the height uh this q parameter here is steepness a would be amplitude on this capital d that you see here and here this is just the vector 2 direction and then w right here that would be frequency uh dotted with the x and z vertices positions and then this fee is just a um like a speed or a variable that we're multiplying with time to change our time scale and uh so yeah we can implement these first i suppose so back in unity in our shader graph we'll get a position node and we will split this out into the x and z components and this will basically be our world space uvs to tile everything together and then we'll also go ahead and get a time mode that right there and so according to this article so we'll need a steepness amplitude vector2 direction frequency and speed variables so we can go ahead and create these we have amplitude frequency steepness [Music] speed then a create a vector 2 and call it direction okay and so i'm actually going to group these as well and just call them like i don't know uv's and time so the first thing we can do according to this equation multiply steepness by our amplitude so grab our amplitude steepness simple multiply set these together next we can grab our direction we'll want to normalize this so that it always has a length of one um you don't have to normalize this but of course if you don't then it'll interfere with the frequency when we multiply them together so we can multiply these together um we will also well we also need to split this out after we normalize it because we'll need to access the x and z components separately there and then the last thing we'll do is multiply our time with our speed parameter and let me go ahead and set just some uh default parameters so which one for everything i guess is fine for now maybe three currency we'll put it 0.5 speed 0.5 and for direction we'll give the x value of 1. so the first thing we want to do is multiply or sorry not multiply take the dot product between our vector 2 world positions and our direction multiplied with frequency dot product and we can actually you can always sort of uh i guess debug by just plugging everything into the base color if you want to see what it's doing um this will be creating so we're not all right okay so you can also see how this is following the camera sort of uh got we need to change this position to absolute world position so it's not influenced by the camera position at all now you can see that's fixed um and what this is doing is it's just creating a mask going and like increasing like just continuously increasing in values from or based on our direction so if we change our direction oops change our y direction and see you know how that's working if you wanted to debug it even a little further you could you know they put this in a fraction node and then output it and it's very clear you know how how we can just take the uh sign of this to generate waves this would be you know the super simple sine waves if we were to simply take the sine of our dot product but we're not going to do that we're going to do a little bit more more complicated stuff to it to make to get our gerson or wave generation so next what we want to do is add time to this dot product so that everything is increasing uh so we've like you know continuous movement for our waves um then we'll take the cosine of that here and here we can multiply these with our multiply this so if we look at the we just took the cosine of our frequency and direction dotted with our vertices positions added to time and then we can multiply that by the x and z um direction components and then multiply that with our steepness and amplitude so we split out our directions right here we'll multiply these so this be the x and then copy that and by the actually so we'll use g it's just a vector too multiply those together and then we can multiply that by our steepness and frequency or sorry steepness and amplitude uh might actually be cleaner if we do that first so actually multiply that right there and then multiply it with our cosine and so this would be our x and z [Music] offset components and all we need to do now is calculate the height which is very simple it's just the sine instead of the cosine of that and then we multiply it by our amplitude so we grab this take the sign of it and then we multiply that oops with our amplitude over here and we can feed these all into a vector three like this and then put that into either our position or our tessellation displacement i'll set a factor two for that for now save that now you can see we have waves made on the shaded wireframe because we don't you're not updating our normals yet so yeah i can see we have you know some nice peaks uh we increase the steepness you can see how that shifting these vertices near the peaks towards the center uh amplitude obviously since these are being multiplied together you're gonna have to tweak these depending on frequency obviously and speed all working as intended now you will notice this this culling around the edges of our screen um we can just turn up this max displacement to something like one to get rid of that effect i probably don't even need one it might be overkill um but i'll just leave it on one we have a triangle size as well but just controlling the you know the minimum size of the triangle basically and in the example shader i had a sine wave added to this to uh break it up you know make it oh actually one thing i also forgot um so you can see using if you look at our little gizmo in the top right you can see that the uh positive z and x directions are well basically our waves are going in the negative z and x directions even though um we have the direction set to a positive to a positive x and a positive y or z in this case um to fix that we can just negate this after we normalize it and now it'll just make this clear and help out with a few more calculations we'll be doing down the line that'll just make things cleaner and easier to work with save that and now we have our waves going in the proper direction so i'll go ahead now and add the additional sine wave that we can combine with this gerson wave to break it up i gave it its own uh frequency speed and direction so we can just duplicate these values uh rename them i'll rename this secondary frequency secondary speed and secondary direction i'll also add categories for everything so i can call this category of secondary wave parameters and i want one more category called primary wave parameters i'll put the first five things remaining to the primary wave and then now we can just uh basically reuse copy these um what is this five nodes right here we don't actually need the split node so let's duplicate that drag that down a little bit and then we'll replace obviously replace these variables with the ones we just made okay and then we'll again do the same thing we'll take the dot product add our time to it so dot product with our wave direction and frequency then we will add time and then of course take the sign of that to get the height we only need the height offset for these waves um and then we'll just add these together with our personal wave height me move this over a little bit add node add that together and then multiply it by our amplitude go ahead and save that get our scene you can see how the sine waves are breaking up the gerson waves a little bit uh you can see that they're following this since the direction is just you know going straight along the x in this direction um usually obviously you want to so you don't want the frequencies to match frequency and speed to match with your primary waves so i can put this on like point three that's one that's six maybe speed 0.4 speed on this 1.2 i like cutting it in half you can mess around with those and parameters we can [Music] set the wave direction three maybe um so yeah that'll take care of all the height displacement that we need um so we can group these nodes we just made to a group called height so we can drag that around keep everything organized we can calculate our normals now um i do also have generally when you do ocean and water shaders you want two normal maps sort of scrolling together combine them and have them all set in opposite directions to simulate like a shiny water effect when you have a very high smoothness parameter i have two [Music] these are just two uh normal maps water normal maps i made in substance designer they're not great but they'll work it could definitely be better and then i also have a phone texture we'll use that later but basically only need three textures right here this foam texture water normal and then a secondary water normal and make sure these are your normal maps are tagged as uh normal maps in the texture type so i can go ahead and add parameters for this this will be texture 2ds i'll call it normal01 and like normal 0-2 maybe um then in addition to these we'll need parameters for the ripple strength the ripple tiling and set it let's see oh and our ripple speed okay i'll give these defaults one point three on the speed uh get our normal texture 2ds and we'll sample those with a sample texture 2d node i will set the type to normal space on tangent and do the same thing for this one okay here um and then we'll also take our normal tile or our ripple 10 excuse me in our ripple speed and again we'll use the world position vertices in place of our uvs sample this so we'll take that just multiply it by our tiling and then we can oh we do need to offset these as well with time because we want them to be scrolling back and forth so we'll take time multiply it fire brick little speed and then since we want these to be going in opposite directions we'll add the time to one of our add time with the uvs for one of our samples and subtract time from the other one and then those in our uv's so um if we preview this or well we don't have grab the default textures or the default normals oh we will also need to tag these two um variables as normal maps as well for defaults anyway now if we look at this let's see tiling together and then to combine them together unity has a normal combine or more blend i think it's called yeah uh not that blunt normal blend okay plug those in uh just leave it on default um and you can see how our normal switch well yeah you can see how they're blended together falling in opposite directions um we'll put those into a normal strength node what choose that node string normal string okay our normal string get our ripple string parameter just plug that in i'm actually going to set this to 0.2 as a default okay and then we'll also want to recalculate the normals from our wave generation our height map um so if we take this y parameter after we multiply it with our amplitude we can plug that into a normal from height normal from height node i just leave the strength at one by default over here and then we'll again we will blend these normals together and that actually takes care of everything we need for the normals so we can go ahead and group that chord normals drag this group to an appropriate spot and then output that into our normal slot save and now see we have normals beautiful um yeah uh where are my ripple ones other people assigned so one paranormal two turn down the tiling i suppose uh two see we have the strength setup uh speed is definitely too fast and yeah this so let me go ahead and crank up our smoothness parameter to something like 0.9 let's just make it look more like water for now uh yeah you'll see that we get this glistening water effect with our normals tiled together or blended together like this and then flowing in opposite directions okay the next thing i want to tackle is a foam mask uh we'll do both the edge foam and the wave crests um i will actually make a category first normal parameters for all of the variables we made here or the parameters okay um so for edge foam we'll need to access our depth buffer and to do that you need a seam depth node we'll set the sampling space to i and we'll also need a screen position node set to raw uh we'll split that out and grab the alpha component oh this alpha component contains it's the it's basically i guess the pixel depth of every pixel on the objects we're rendering or with the shader that the shader is applied to this would be the distance of you know each pixel on this plane from the camera essentially and then the scene depth it will return uh the pixel depth of all the or you know the depth buffer which contains the pixel depth of all the i guess opaque objects that have been rendered previously like our terrain this cube and the sphere and when we subtract the currently rendering geometry with our material from the uh you know the depth buffer contained or the depth buffer that we got from our opaque materials we'll get a a uh basically a mask that is a zero where they're for black where they're basically the same and then it'll gradually increase to white as we get because we have you know a greater offset a greater delta between the two and so all we can do is just scene depth subtract our alpha and that's basically all we need and then we can obviously you know multiply this by decimal to you know flatten the offset or the slope i guess which is um the slope at which the depth is increasing multiply that by like 0.2 or something and we can go ahead and view that output so just take that we'll saturate it first because we're gonna have values way above one put in our base color uh oh and so uh we're gonna have to make sure our material is set to since i created this before i changed shader parameters gotta set this to transparent surface type uh and now we can see our edge mask depth edge mask basically um uh let me i'll also put turn on double sided in the material because we will need it later mirror the normals and you will see this uh so this weird um cooling effect when we get you know down by the uh down lower by the water to fix that you can just turn on depth rate up here in the surface options and that should fix that issue okay anyways onto our phone so let's start by adding a few parameters i'll add a foam falloff add a foam width um let's see oh it's something called foam removal and foam fans uh okay oh and we will need that foam texture as well um the uh foam texture that we imported so i'll go ahead and sample that to start with will actually turn on the tiling and offset because we're not going to be all setting it with time or anything so we can just use the built-in unity option for that so the idea behind this is that we take the cosine of the depth value as it increases and then offset that by time we're offset the depth and by time and then take the cosine of that and that'll give us like a radial some like radio waves oscillating out from the uh molecular terrain the edge of our terrain so if we want to visualize the uh that banding effect we can just take our time variable add it to the depth and then we'll just take the cosine of that and we can output that in our base color so yeah we go back to our scene you can see how the uh so these are actually flowing the wrong way uh but yeah we have this effect where the banding the bands of these bands are you know flowing in this case towards our terrain but if we just reverse that they'd be falling out um so if we just instead of adding time we will just subtract it from our depth and that will make it oscillate in the proper direction as you can see here okay um but i'll delete this for now uh so the first thing we'll do is we'll take our our depth right here the scene depth minus the current you know rendering object pixel depth i will multiply that by our falloff um then we'll subtract our foam width from that and so this will just bring values near the edges of the terrain below zero and that'll you know will bring basically our zero point out further and then we'll just clamp those and we can multiply this by our from a removal variable this is just like additional falloff after we do some calculations to this separately okay so then we can take our from follow and multiply that with our foam bands here uh and then here is where we can take our time variable and subtract this banting effect for the the foam bands and then from here we'll take the cosine right here so this again is our foam width we're just basically increasing the range the values that are below zero so that when we clamp that using a saturate node the saturate node clamps all the values in the zero to one range you can multiply that with this cosine and then we'll have basically a so it'll be black on the edge and we'll just invert it from one minus note to flip everything so we got one minus so now our edge will always be white and then we can multiply that with our foam texture just using the r channel so now if we take this multiplication and we subtract the boom removal the value that we multiply by from removal and then we can go ahead and view this in our well we should probably saturate it first because we will have values outside of the zero to one range oh and some of these defaults are probably so these default values are probably not set up properly so i'll just put everything on one as a default except for the foam bands we can put this at like a five maybe texture so both one one uh one and the bands at like five so yeah now you can see this banding effect that we have where the edges are staying white and it's gradually spilling out change the fall off to two the width it's just that you know uh obviously the edge from with that never changes will always be at least one according to this uh change the this foam removal which will increase the width of the banding also change the number of bands right here and then of course the player from texture it's a little hard to tell but it just breaks up the banding effect essentially and then this would obviously be like a mask for our uh that we blend or we learn between a watercolor and a foam color uh but first we will or i will set up the [Music] the wave crest foam and blend the two foams together and then we'll use that as the the color mask uh let's do that or actually let me create a category for these uh um edge from parameters save that oh yeah i should uh normally i increase the tiling on the foam texture which will you know obviously break it up quite a bit if you want um i will be using the same foam texture to sample or the same foam texture for the uh edge foam and the wave crests you could just sample it again with a if you you know have a variable to change the tiling because it looks pretty good like with a high tiling value on the edges but it's very noticeable on the wave crest so you may want to split that up and just sample the texture twice so you can have a low tiling for the wave crests and then a high titling for the edge foam but i'll leave it at two for now i like to i just use two for both of them in the tiling um also so for the wavecrest we'll add a few variables um first we want the uh let's call this crest falloffs size um we can add a crest offset and then a lot of variable called extra dispersion like that and so first we'll take our crest offset and then we'll grab uh so we'll grab this output right here which is you know just the dot product of our these are our gerstner waves the dot product will register waves with the direction um we'll grab the output after we add time to it so it's again moving we want our wave crests to move with our waves so we will add that with our offset if we want an offset to reposition you know where the crest sits on on the wave on top of the wave so we'll add that and then we will mod it with a constant we'll mod it with tau and the reason we do this is because when we're so when uh when we define the function that controls the falloff of the wave crest we want a very sharp falloff right at the front of the wave and then we want a very gradual follow-up on the back of the wave um if that makes sense so you know we want to a very it sort of be like misty and uh i missed you but we want the breakup to be very slow and apparent on the back of the wave and to do that we have this equation right here um let me so if you take a look here we have this vertical line is where x is equal to two pi and you know two pi is tau um and we always want this interval to tile together so it starts at zero very gradually increases to one and it has a very sharp drop of drop off back to zero and since we're modding our x value by tau whoops um then this value will just loop indefinitely so we'll always have this wave pattern and the equation is this one right here we just take the cosine of so if i sort of re-create it so if we have the cosine of x this is just a normal cosine wave we raise x to some value say three we can see how the falloff is getting or how the waves are getting very uh you know contracting they're shrinking they're compressing i suppose you'd say um i'll store that as a variable for now like z so we can control that and then in order to you know anchor this peak right here on tau or on two pi we want this to always be anchored onto that position then we'll need to obviously multiply x by some value so for example z is three we'll need a value around point zero two five so that'll create that continuous effect when we mod uh the x value by two pi but obviously we don't wanna you know just guess and input this manually so if we set this as another parameter like w or actually we won't use a slider for these um we'll want to calculate them based we want to calculate our this you know variable that we have to multiply by based on our z value which in this case this is z value this will be our crest falloff variable uh so we have the crest follow we could actually write this out if we want or actually i don't even know if you can store variables like that in decimals i won't worry about it but z is equal to our crest follow then we need to calculate w so w is equal to again you can see it up here w is basically a in this situation w would be equal to pi times say again we'll store this as a variable for now pi times q over pi raised to the z uh so we have this slope right here um and then we want to calculate q which in this case is equivalent to n uh q is equal to 1 over 2 raised to the power of again we're using our this will be our crest follow-up variable which is z so z minus 1 and then that will anchor our wave in the zero to zero to two pi range where our um you know where the wave intersects uh one is at zero and two pi and y y is equal to one where x is zero and two pi and then obviously we want to shift this in the zero to one range as well as flip it around so come up to our cosine of w times x raised to the again this would be our crest fall of z all we have to do is multiply it by 0.5 and then add 0.5 and now that's shifted into the 0 to 1 range y is between 0 and 1 inclusive and then we can just invert that by subtracting or doing a one minus operation and then if we sample the foam texture using a equation like this then you can see how when we're subtracting values on this gradual slope we'll get a very uh slow fall versus the front it'll be a very sort of hard edge but not i didn't want to direct you know just linear increase that then has a very sharp edge that falls to zero because that wouldn't look natural so we have to do something like this you can see how i increase and decrease this it just cranks up those falloff values so we'll implement this into unity or into the shader graph so we have the crest fall off um i guess the first thing we can do is raise our x value to a power of the crest follow-up one thing to note is that you get a warning doing this operation because when our time our scene time is basically zero we are this dot product will can go get like you know it will go into the negatives we'll get negative values depending on which way our direction is going based on our based on our vertex positions because uh position of these is again x 70 z is 70 and our direction vector is one and one which remember we're negating that so it's actually negative one and negative one so we'll get you know like a dot product of negative seventeen negative seventy then when time is zero we're adding to that so it's still negative the values are still uh or the the dot product would be negative 70 so we're getting and then we're adding time to that but if time is zero because the game just started this will remain negative 70. um again we're adding an offset but this offset is less than 70 it'll still be negative um and so we get an error if we're putting that negative into this uh power node let's fix that we can just clamp this value to the zero to tau range and that'll fix that error when we get it uh i am [Music] recording this in the future um thinking back on it i realized we should just instead of clamping the values after using the built-in mod function we should just create a custom function where we do the mod operation and then we test whether or not we get a negative value out of it and then basically output that added to our mod value just so it's always um just so it always returns positive because you know i realize when you load up the scene and the time is zero then the wave crests will basically be not be basically won't be applied properly until you know the time value is equivalent to the you know x and z values of these uh planes that have the water applied so you know when time hits 70 or something then um then we'll finally actually see the wave crest working properly within with the parameters um but if we just do it like this then it doesn't matter what our time value is uh it'll output properly and you know it'll always be positive so we can take the power of it so the next thing we're going to do is calculate this n value right here um which is then used to calculate this a value which is the factor that we're multiplying our waves by so in order to calculate in n is 1 over two raised to the b minus one so we will get a divide node so that's a one uh we'll need a power node we'll also need we'll set this to 2 then we'll need to subtract and so we'll take our b value or our crest follow subtract 1. raise that or take 2 and raise it to that power and then we will divide all that by 1. and then we'll calculate the a which we just need the pi constant times n over pi raised to the b so if we get a constant pi um since this is our n value we'll multiply these together and then we'll also take this constant power and raise it to the crest follow like this and then we just divide these or divide our power by the multiplication so now that we have this set up we just multiply them together again again this is our um a value basically just multiplying our x component by a that was all the calculation for the a component it is a little expensive to do this um so it is you know you can just use you a just a hard-coded parameter like .025 like i did if the offset was three um or you could calculate it like this but we are using two power operations and two divide operations so it isn't exactly cheap to do unfortunately um but yeah we multiply those take the cosine we want to take the cosine not sine because cosine is will be one when x is zero um now of course we do the one minus well okay first we multiply it by 0.5 and then add 0.5 to shift it into the zero to one range and then we can flip it or invert it using one minus okay um so that's our basic wave uh let's set defaults crossfall i'll set that to 2 and not implemented size or dispersion but we can go ahead and just take a look at this put it in the saturated output in our base color just see what it looks like right now we're only accounting for the gerstner waves um but it's very fairly easy to account for the uh the sine waves we blended in with it so you can see the where's my material so you can see the sort of wave we have we have a very steep follow-up right here and then a very gradual one towards the back uh just increase that fall you can see how that's changing i'll leave an offset if we want to reposition the wave and we'll be subtracting our foam mask from this these uh grayscale values so we'll get you know white start subtracting the mask will get white values and the foam mask where it's black and then where there's white we'll get nothing or we'll you know have the normal watercolor so to add in the secondary waves um we just take this addition of the two right here so our final height before we multiply the amplitude um and i will add take that add our crest size to it i'll saturate this because and we'll have uh this value's already in the negative two to two range since we're just adding two sine waves together so we'll add the crest size then we'll saturate it do a one minus which we'll need in a second as well as multiply this by this down multiply multiply this by our extra dispersion variable and we're multiplying the extra dispersion in first so that we're only dispersing if we if we take this you know extra dispersion negative uh we still only want it to affect like the or make it positive we only want to affect the um the waves like we don't want it to affect the troughs we just need to make sure we're multiplying that together before we add it in so we can take our extra dispersion now add it together with the cosine wave and then we'll take this and just add it together this is like our wave size mask and then if we simulate how we did for the hedge foam we just took our foam texture and subtracted the mask from it will do the same thing take the take the foam texture subtract subtract our mask and then we'll saturate it take a look why is this excursion okay and now we can so we can see the see how our waves are appearing you know where they should on the the peaks the highest points of our water we have a fall off an offset which we'll all set up within our um this uh sort of like size mask we can change the size we can change the extra dispersion as you can see it's just dispersing it or just adding if you really crank it up you'll get this effect but uh yeah and then so then what we want to do is we want to combine our crest and edge foam together so we have the two subtract nodes uh all we're going to do is just take the max of both of those so we get the maximum here i'll introduce another variable called the uh let's call it foam edge hardness just click edge hardness well that's fine actually no it's not but it's too long edge hardness um give this a default value of say 10 perhaps and before we saturate we'll just multiply our foam mask and everything by this edge hardness value saturate it save and that is our wave crest foam and edge foam complete the mask anyway just add the color later um so you can see how our edge hardness is affecting the wave obviously we go negative it'll invert everything really crank it up to get a very sharp edge if we want like 200 this is affecting both the uh edge foam and the waveform i'll leave it on 10 though maybe our extra dispersion touch change the offset a little bit change the size if we'd like and of course it's affected by our wave direction everything but yeah um now we can use this mask as a color mask so first i will group everything like that just call it phone uh may also group this called depth which does depth uh what we can do now as well is since we have our foam mask complete we can now add a smoothness parameter or we can now calculate our smoothness all we want is just the water to be smooth and the foam even though it doesn't really make sense we do want the foam to be smooth i didn't add like a separate normal mask for the foam or anything normal texture um but you could um you just have to you know blend it in in the correct place in our normal map but i will add a variable call it uh smoothness it's just our overall material smoothness all we need to do is just take the smoothness i believe we do a one minus and then we just multiply it with our bone or sorry we put the foam mask into the one minus and then multiply by smoothness because the smoothness value of zero is very rough and diffuse and our foam mask is white so if we just invert it it'll become black and then we multiply by the smoothness to affect the overall uh water smoothness this smoothness set the default 2.9 and we can see the effect that's having so now the we don't have our specular highlights clearly visible on the phone anymore can of course change the smoothness parameter but yeah uh so let me make a category for these crest phone parameters uh i won't put the smoothness in there but i will put all the other stuff we made um you will have to be aware that the edge hardness is applied for both the edge foam and the crest foam i just have it in this category it's up to you where you put that though i'll go ahead and do the albert or the base color so normally when people do water color they [Music] take the view direction um which is you know the the direction of every pixel towards the camera and then they dot that with the normal direction of the water use a dot product to get a mask um just to create variations in the water between you know right below you it'll be very or it'll be your it'll be one color you know at the sort of on the face of the wave that'll kind of blend to that color and then obviously well you know dot product works a lot explaining this um but to do that we will so we'll use the this normal blend right here then we'll first we need to transform that to world space so get a transform node it's in tangent currently so transform it to world we'll use direction because this is our normals and normals are directions um then look at our view direction which is in world space just fine and we will just take the dot product of these together as you can see we have that fresnel effect um i believe unity does have a fresnel node yeah you could use um you would you would plug in your these uh transform normals right here uh then we could change the power but this works fine just doing it like this i just square it once to give it a sharper offset sharper follow up and then you can introduce two color parameters then we'll just learn between these with a lerp node using our fresnel mask uh can't swizzle these out as well to vector threes i don't know if this is more efficient or not but you don't need the w channel in our case uh so just blurp these together um so that will be like our wave base color um we will get another alert node to look in our foam mask so we have our foam mask here [Music] and then so we'll also need a foam color uh go ahead and put that in the set of default white uh we'll put that in the open parameters i will swizzle it again even though i don't know if it's efficient or not or inefficient to do that but i'm gonna do it for now uh i'll just blur those however the lyric node is i believe one it'll use it fully use the b input and where it's zero it'll use the a input and then we can put this into our base color group this i'll call this view direction base color and we can just group these into our face color combined or something like that so color one i usually go for like a greenish teal color second i'll go for like a dark blue this probably also turned on my normal string or the ripple string like this um but yeah that works uh let me get the foam color set this like an off-white that um and yeah that is mostly the base color we will so we do want to add the refraction in uh the depth and the depth refraction and all that so we're going to need to sample our seamed up um and that will be blended in with our base color or our scene color so we'll need to sample the steamed up again and the same color and we'll blend that in with our base color so to do that we will first start with a screen position node uh we can leave that at default and if we just straight up sample a's scene color we'll use the hd render pipeline scene color check the exposure um or else everything will be extremely bright but now we can just take a look at our scene color or see what this node what these nodes are returning which is just the uh you know base color buffer render buffer uh so yeah you can see it's just you know turning the existing scene color at every pixel position uh so um and so we'll offset these uh basically offset the screen coordinates using our normal map and that way we can mimic uh refraction uh so if we take our normals we don't want the wave norms we just want the ripple normals after our normal strength is applied to them so take that split it out we will also split our screen position um and so we have the x and the y normal channels this is what we need the rg uh oh and we should introduce another parameter we'll call this refraction fraction strength default it's like 0.5 so first we will multiply the normals the rng channels by our refraction strength so multiply it by the g channel like so and then if we just add this back into our screen position in the respective channels uh reconstruct the vector4 for our you know screen sampling positions and then plug that into the same color node and then we can assume we have the refraction basically the refraction effect uh turn down the strength of it um you might be able to notice one of the issues with uh the refraction doing the fraction this way first off the edges of our screen might uh you know we might see like behind i guess our scene like maybe our i don't know exactly how this is working but basically just a default white texture looks like you know where since the refraction normals are not anchored onto the edges of our screen and you also see that even though you know this cube for instance is out of the water it's still refracting behind it uh same with the terrain here the age even though it's well out of the water we're seeing refraction as if it was in the water so first to fix the this edge on the screen uh what we can do is go to desmos and um so if we have this is our screen x and screen y or tend to put that x values like the screen x um then we want to clamp that to the zero to one range or we basically want where the values are close to zero we want it to be zero where it's zero going to zero to shoot up and form a sort of plateau and then shoot back down and it hits one um and then multiply our normals with that um so if we square this uh you can see we have you know the basically the the slope we need um if we subtract one to offset it now it's centered you know one unit over and if we just multiply it by two to you know change squeeze the squeeze it closer together change the follow-up then we have the basic we have it in this zero to one box range all we have to do is flip that around by subtracting one so now we have you know the fall if we need now we just need to basically increase this make this a lot sharper towards the edges so what we need to do for that is just multiply it or raise it to some power like 10 and we'll get this very uh this very plateau-ish type mask that we can use to multiply if we're sampled if our screen coordinates are variable then we can multiply our normals with this to anchor them on the edges of our scene graph to do that we'll first take our all we need is the r and g first we'll multiply them by two uh multiply by two then we can subtract one to shift it over i will square that so yeah you can see that you know we have the parabola shape that we want um and then basically all we need to do is just raise that to a very high power like say 10 and you can see how this is changing that falloff changing the mask now obviously we'll invert this with a one minus at the end set this like 15 maybe uh and then we just do a one minus like this then we can just copy that verbatim don't need to change anything except the use our screen y position instead see we have the black uh borders at the oops very edge top think about it when you hit command z um and so yeah so now we can just add multiply our normals with these two masks here so move all this over take our x let's apply it with our screen x mask and we'll take our y let's play with our y normals and we'll feed that into the multiplies the refraction strength and then everything should be good to go and then you can see it's anchored to the edge of the screen on the left there's no like gaps or anything top bottom left uh you can still see gaps if you really crank up this reflection strength like right here it's not very noticeable when it's this high so yeah i don't know it's not it's not a hundred percent full proof but it works well enough for me i think um and then the next thing we'll need to do is get rid of this uh what do you call it this refraction out of the water for objects that are out not in the water um so what we're going to do is use the uh we're also going to refract our depth we're going to sample depth again using the same refraction coordinates and we'll use that to learn between this scene color and you know the existing water foam base color we can sample our scene depth or scene depth again set up the eye space we'll do the same subtraction so so that is our b and then grab our alpha value from the raw screen position and plug that into our a sorry these need to be reversed so let's look on our b and yeah so we're subtracting the existing scene depth which is behind the plot the water planes i you know it's at a greater distance we subtract that from uh the current rendering geometry which is the depth of the current rendering geometry which is its alpha value so we have that delta and we can test whether it's negative with a comparison if it's less than zero then we will multiply it by negative two uh we'll get a branch um so if that is true if it is less we'll multiply by negative two or else we'll just return the value and so we can use this mask to blend between the refraction and the scene color and it'll remove the refraction behind behind objects that are out of the water first thing i will do so i also do i need to add a few more parameters now to control you know that opacity fall off and that blending with the water edge um so i'll add a depth strength i'll add a water opacity a bit of water edge opacity and i think that's all i need i'll add them as we go if i need more but for now first thing i'll do is multiply our depth string with this output um we'll saturate this after we do that uh next we'll take our water edge opacity we'll subtract 1 or one minus it subtract it from one um multiply that with our saturated and then we'll also add the variable back into it like so um and we will want to set the opacity variables to sliders clamp to the zero to one range we don't want those to go above or below those values uh depth strength we can set to 0.2 as a default and so now if we take this opacity mask and before we blend in our foam we want to blend in our scene color which is you know basically our watercolor too so take this put it in alert mode um and then we'll take our you know watercolor put in the b slot take our scene color then the a then this group right here and then put this output into our lorp with the uh place our watercolor with the new combined color now we can output this to our base color save and now you can see that we have the this uh yeah we can see our we have like a follow-up where we can see the terrain um change the so we have a oh i didn't implement the water opacity yet uh to do that we would just multiply everything at the end here do that real quick let's play that by the water by city use that as our mask for the lerp see okay uh usually you probably just want water opacity at one uh i'll leave mine on one we have the edge opacity which controls the edge at like 0.8 maybe and of course we have our depth strength turn that down up so yeah that is our refraction working uh you can see that there is no none of that uh depth effect occurring along this edge because we're just lurping with the normal watercolor instead of the uh scene color um you will there is if we do have depth that's uh basically we have two objects sort of like overlapping fairly close to each other we're actually not even close to each other just two objects are overlapping like this then the only issue with um handling the refraction and the mask like this is that you will again see [Music] this you know it's we can see the the normal watercolor where the where we should be seeing the uh underwater terrain um i don't know i mean there probably is a better way to avoid this it's probably something i'll work on like maybe blending with the normal like multiplying by the uh normal scene depth right here um but this method works fairly well granted you don't have granted you don't have like really high refraction strength but yeah let's see like you know we're behind this cube we'll see a little bit of that effect occurring right here along the edge of the cube where the you know we're getting watercolor instead of the terrain color but for the most part it works pretty well the last thing we can do is add an effect so that our terrain will blur as the depth increases and we can also make sure that we can actually see through the water when we're underneath it instead of just up at the edge as you can see uh so to do that we will there's a pretty handy node called the utility logic we have this is front face node right here and obviously it'll return true if the face is you know obviously a front face or it's uh the normal the normal direction it should be facing and then these are back faces so it'll return false um and obviously that's either a one or a zero so if we have a mask like that we will need a custom node here because we want to convert this to a float but in shade rf there's no like boolean to float conversion or anything i don't think yeah they don't let you do it man for if like a node so we just need a custom function um we need an input which is a boolean and an output which is a float i'll just name it in and out set this to string call it bool to float and all we need to do is just set our output equal to our input like that very simple then just put our front face into that and now we have a black and white mask that will return will be so if we're you know at the water level here this would be black then above the water will be white so we can use that to control the opacity so if we take that we before we multiply with our water opacity we take this multiply these together and then we'll set that multiply back out and then rewire it like that um save that and as you can see we're underneath the water we can very clearly see through see to the you know background whatever's behind it and then we're above when we're above it works as normal when we're like in between it'll the water levels you know the camera is in between under and above the water it'll work perfectly fine as well so yeah that takes care of the underwater and then last thing we want is that uh depth blur effect and that's also very simple fix all we basically need to do is just take this subtraction here and plug it into the lod sampling part of our scene color save it so now if we look at our terrain we can see that we're getting this blurring effect as it gets deeper um you will notice if i turn my water opacity to zero we have this like this black uh mask that's occurring um it's like dark area uh this is just because we're not clamping uh the lod level that we're sampling so it's sampling leds that like don't exist or i guess leds pass like led6 i think thanks i think it usually has six leds max i'm 100 sure on that but um yeah so we can just take this uh clamp it from zero to six um we might also so even though this is right right near the surface it's still pretty blurry at this at this uh level so all we have to do if we want to offset that is just subtract some value from this before we from this before we clamp it so if we add something like negative 1 or negative 1.5 actually i get a one and then clamp that now we can see that everything is basically clear at the top clear the surface and then it blurs out as it goes deeper and then if i turn this opacity down to zero you can see also that we're not getting that black effect anymore because we again clamped the lod level from zero to six um if we go under the water we still haven't fixed this but this is a very easy um well it is fixed but it's always sampling basically the lowest led level because again it's just sampling the skybox depth the uh we should have a massive well the depth is just very large here so it's always simply ld level six um but what we can do is just take this front-face bull to float conversion and just simply multiply uh before we clamp it and subtract we can just multiply this subtraction value but this float conversion then add negative one there now if we save that uh this will always be now as you can see we're sampling the lod level zero when we're under the water and then it works as usual when we're above the water this uh you could also clamp this if you didn't want like the lod0 you could clamp this to like a maybe like to use ld one or two um if you didn't want it to be uh always clear no matter like where you are on the uh you could so if you wanted you get a camera this obviously has the position so if we take that position position and then split out the green channel which is the y uh we can subtract we basically create like a delta that as we get lower beneath the water level which is some y value then you know as that delta gets bigger we can use that to sample the lod level so it'll blur out as we get deeper something you could do um but yeah i i think it looks i like it as is uh it always just sampling led level zero and then you could you know take care of the actual underwater effects and just add like fog using a like a volume like a we got sky fog volume just add another one down here it'll take care of the water effects and all that um but yeah i think that's everything i wanted to go over uh if you have any you know tips or suggestions on how i might be able to improve this uh please let me know uh if there was something that could that was confusing to you um tell me uh oh i will they all enable the screen space reflections real quick as well take a look at that so you can see this screen space reflection right there here in the wave crest for the edge of the wave it's the sphere so we have the reflections as well as the depth depth refraction um to enable if you did want to enable the screen space reflections you'll have to go to your if you're using http you go to your hdrp global settings and if we scroll down to [Music] this camera right here in the frame settings and we go to believe it's in rendering find oh okay so you go to the camera lighting tab and then we have screen space reflection right here and then we want to check transparency as well if we uncheck that you can see that our screen space reflections are turning on and off for this material so yeah that should be everything i guess i'll finish the housekeeping things here just again group all this stuff into a category i'll call this water parameters move that to the top to be there and then group our opacity slash refraction this and that should take care of everything um yeah uh one last thing you could think about as well is creating different quality levels if we take a um we get like a material quality keyword and sample this uh we can use that to control whether or not we you know use this uh these calculations for the uh for clamping the screen space position on refraction and all that we could use material quality keyword to change if we actually dynamically calculate this follow failure if it's just if we require it as just a constant begin to save some operations to optimize the shader a little bit um just thinking about small things like this could help improve the performance of your shader if you needed to or if you want to have like different quality levels uh you could use this node right here um yeah we have the defaults and obviously all that but i'm not going to implement that right now but yeah i suggest if you do uh or i suggest you should if you really want to optimize things yeah i think that's the end of the tutorial um i hope this helped you or hope some of you uh maybe learn something that you or the technique that you might not have been familiar with uh like either for foam or for the depth and the depth blurring but let me know let me know how it worked out and i will catch you next time
Info
Channel: Grant's Graphics
Views: 20,766
Rating: undefined out of 5
Keywords: Unity, shader, ocean, water, tutorial, HDRP, graph, material
Id: QAH1Kep3zRM
Channel Id: undefined
Length: 106min 46sec (6406 seconds)
Published: Wed Mar 02 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.